summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cmake.conf4
-rw-r--r--.gitignore10
-rw-r--r--.qmake.conf5
-rw-r--r--CMakeLists.txt24
-rw-r--r--LICENSE.GPL3-EXCEPT704
-rw-r--r--LICENSES/Apache-2.0.txt61
-rw-r--r--LICENSES/BSD-3-Clause.txt9
-rw-r--r--LICENSES/GFDL-1.3-no-invariants-only.txt (renamed from LICENSE.FDL)23
-rw-r--r--LICENSES/GPL-2.0-only.txt (renamed from LICENSE.GPL2)0
-rw-r--r--LICENSES/GPL-3.0-only.txt (renamed from LICENSE.GPL3)0
-rw-r--r--LICENSES/LGPL-3.0-only.txt (renamed from LICENSE.LGPL3)0
-rw-r--r--LICENSES/LicenseRef-Qt-Commercial.txt8
-rw-r--r--LICENSES/Qt-GPL-exception-1.0.txt22
-rw-r--r--cmake/FindBlueZ.cmake12
-rw-r--r--cmake/FindPCSCLITE.cmake21
-rw-r--r--coin/axivion/ci_config_linux.json40
-rw-r--r--coin/module_config.yaml13
-rw-r--r--config.tests/bluez/CMakeLists.txt34
-rw-r--r--config.tests/bluez/bluez.pro5
-rw-r--r--config.tests/bluez/main.cpp29
-rw-r--r--config.tests/bluez_le/CMakeLists.txt31
-rw-r--r--config.tests/bluez_le/bluez_le.pro1
-rw-r--r--config.tests/bluez_le/main.cpp29
-rw-r--r--config.tests/linux_crypto_api/CMakeLists.txt31
-rw-r--r--config.tests/linux_crypto_api/linux_crypto_api.pro5
-rw-r--r--config.tests/linux_crypto_api/main.cpp29
-rw-r--r--config.tests/winrt_bt/CMakeLists.txt34
-rw-r--r--config.tests/winrt_bt/main.cpp30
-rw-r--r--config.tests/winrt_bt/winrt.pro3
-rw-r--r--config.tests/winrt_btle_no_pairing/main.cpp40
-rw-r--r--config.tests/winrt_btle_no_pairing/winrt.pro3
-rw-r--r--configure.json5
-rw-r--r--dependencies.yaml7
-rw-r--r--dist/changes-5.13.235
-rw-r--r--dist/changes-5.14.053
-rw-r--r--dist/changes-5.14.125
-rw-r--r--dist/changes-5.14.249
-rw-r--r--dist/changes-5.15.025
-rw-r--r--dist/changes-5.15.120
-rw-r--r--dist/changes-5.15.224
-rw-r--r--examples/CMakeLists.txt13
-rw-r--r--examples/bluetooth/CMakeLists.txt11
-rw-r--r--examples/bluetooth/bluetooth.pro12
-rw-r--r--examples/bluetooth/btchat/CMakeLists.txt66
-rw-r--r--examples/bluetooth/btchat/btchat.pro27
-rw-r--r--examples/bluetooth/btchat/chat.cpp155
-rw-r--r--examples/bluetooth/btchat/chat.h77
-rw-r--r--examples/bluetooth/btchat/chat.ui31
-rw-r--r--examples/bluetooth/btchat/chatclient.cpp70
-rw-r--r--examples/bluetooth/btchat/chatclient.h60
-rw-r--r--examples/bluetooth/btchat/chatserver.cpp85
-rw-r--r--examples/bluetooth/btchat/chatserver.h60
-rw-r--r--examples/bluetooth/btchat/doc/images/btchat-example.pngbin6527 -> 11007 bytes
-rw-r--r--examples/bluetooth/btchat/doc/src/btchat.qdoc175
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24/bluetooth.pngbin0 -> 383 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24/bluetooth_dark.pngbin0 -> 729 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24/send.pngbin0 -> 575 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24/send_dark.pngbin0 -> 903 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24@2/bluetooth.pngbin0 -> 543 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24@2/bluetooth_dark.pngbin0 -> 938 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24@2/send.pngbin0 -> 1046 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24@2/send_dark.pngbin0 -> 1258 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24@3/bluetooth.pngbin0 -> 775 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24@3/bluetooth_dark.pngbin0 -> 946 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24@3/send.pngbin0 -> 1429 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24@3/send_dark.pngbin0 -> 1693 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24@4/bluetooth.pngbin0 -> 875 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24@4/bluetooth_dark.pngbin0 -> 1263 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24@4/send.pngbin0 -> 1820 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/24x24@4/send_dark.pngbin0 -> 2200 bytes
-rw-r--r--examples/bluetooth/btchat/icons/btchat/index.theme22
-rw-r--r--examples/bluetooth/btchat/main.cpp65
-rw-r--r--examples/bluetooth/btchat/remoteselector.cpp118
-rw-r--r--examples/bluetooth/btchat/remoteselector.h69
-rw-r--r--examples/bluetooth/btchat/remoteselector.ui47
-rw-r--r--examples/bluetooth/btfiletransfer/btfiletransfer.pro31
-rw-r--r--examples/bluetooth/btfiletransfer/btfiletransfer.qrc6
-rw-r--r--examples/bluetooth/btfiletransfer/busy.gifbin847 -> 0 bytes
-rw-r--r--examples/bluetooth/btfiletransfer/doc/images/btfiletransfer-example.pngbin42755 -> 0 bytes
-rw-r--r--examples/bluetooth/btfiletransfer/doc/src/btfiletransfer.qdoc43
-rw-r--r--examples/bluetooth/btfiletransfer/main.cpp69
-rw-r--r--examples/bluetooth/btfiletransfer/pairing.gifbin3951 -> 0 bytes
-rw-r--r--examples/bluetooth/btfiletransfer/pindisplay.cpp79
-rw-r--r--examples/bluetooth/btfiletransfer/pindisplay.h79
-rw-r--r--examples/bluetooth/btfiletransfer/pindisplay.ui89
-rw-r--r--examples/bluetooth/btfiletransfer/progress.cpp107
-rw-r--r--examples/bluetooth/btfiletransfer/progress.h87
-rw-r--r--examples/bluetooth/btfiletransfer/progress.ui55
-rw-r--r--examples/bluetooth/btfiletransfer/remoteselector.cpp413
-rw-r--r--examples/bluetooth/btfiletransfer/remoteselector.h122
-rw-r--r--examples/bluetooth/btfiletransfer/remoteselector.ui214
-rw-r--r--examples/bluetooth/btscanner/device.cpp229
-rw-r--r--examples/bluetooth/btscanner/device.h92
-rw-r--r--examples/bluetooth/btscanner/doc/images/btscanner-example.pngbin73283 -> 0 bytes
-rw-r--r--examples/bluetooth/btscanner/doc/src/btscanner.qdoc41
-rw-r--r--examples/bluetooth/btscanner/main.cpp68
-rw-r--r--examples/bluetooth/btscanner/service.cpp111
-rw-r--r--examples/bluetooth/btscanner/service.h80
-rw-r--r--examples/bluetooth/chat/Button.qml93
-rw-r--r--examples/bluetooth/chat/InputBox.qml130
-rw-r--r--examples/bluetooth/chat/Search.qml107
-rw-r--r--examples/bluetooth/chat/chat.pro20
-rw-r--r--examples/bluetooth/chat/chat.qml248
-rw-r--r--examples/bluetooth/chat/chat.qrc11
-rw-r--r--examples/bluetooth/chat/doc/images/chat-view.pngbin10185 -> 0 bytes
-rw-r--r--examples/bluetooth/chat/doc/src/chat.qdoc84
-rw-r--r--examples/bluetooth/chat/images/clear.pngbin320 -> 0 bytes
-rw-r--r--examples/bluetooth/chat/images/default.pngbin4738 -> 0 bytes
-rw-r--r--examples/bluetooth/chat/images/lineedit-bg.pngbin217 -> 0 bytes
-rw-r--r--examples/bluetooth/chat/qmlchat.cpp96
-rw-r--r--examples/bluetooth/heartrate-game/App.qml99
-rw-r--r--examples/bluetooth/heartrate-game/BluetoothAlarmDialog.qml80
-rw-r--r--examples/bluetooth/heartrate-game/BottomLine.qml11
-rw-r--r--examples/bluetooth/heartrate-game/CMakeLists.txt91
-rw-r--r--examples/bluetooth/heartrate-game/Connect.qml155
-rw-r--r--examples/bluetooth/heartrate-game/GameButton.qml39
-rw-r--r--examples/bluetooth/heartrate-game/GamePage.qml77
-rw-r--r--examples/bluetooth/heartrate-game/GameSettings.qml61
-rw-r--r--examples/bluetooth/heartrate-game/Main.qml71
-rw-r--r--examples/bluetooth/heartrate-game/Measure.qml325
-rw-r--r--examples/bluetooth/heartrate-game/SplashScreen.qml30
-rw-r--r--examples/bluetooth/heartrate-game/Stats.qml80
-rw-r--r--examples/bluetooth/heartrate-game/StatsLabel.qml34
-rw-r--r--examples/bluetooth/heartrate-game/TitleBar.qml63
-rw-r--r--examples/bluetooth/heartrate-game/bluetoothbaseclass.cpp65
-rw-r--r--examples/bluetooth/heartrate-game/bluetoothbaseclass.h72
-rw-r--r--examples/bluetooth/heartrate-game/connectionhandler.cpp107
-rw-r--r--examples/bluetooth/heartrate-game/connectionhandler.h66
-rw-r--r--examples/bluetooth/heartrate-game/devicefinder.cpp168
-rw-r--r--examples/bluetooth/heartrate-game/devicefinder.h72
-rw-r--r--examples/bluetooth/heartrate-game/devicehandler.cpp136
-rw-r--r--examples/bluetooth/heartrate-game/devicehandler.h78
-rw-r--r--examples/bluetooth/heartrate-game/deviceinfo.cpp68
-rw-r--r--examples/bluetooth/heartrate-game/deviceinfo.h57
-rw-r--r--examples/bluetooth/heartrate-game/doc/images/heartgame-result.pngbin9468 -> 0 bytes
-rw-r--r--examples/bluetooth/heartrate-game/doc/images/heartgame-result.webpbin0 -> 23682 bytes
-rw-r--r--examples/bluetooth/heartrate-game/doc/images/heartgame-running.pngbin10951 -> 0 bytes
-rw-r--r--examples/bluetooth/heartrate-game/doc/images/heartgame-running.webpbin0 -> 24072 bytes
-rw-r--r--examples/bluetooth/heartrate-game/doc/images/heartgame-search.pngbin14591 -> 0 bytes
-rw-r--r--examples/bluetooth/heartrate-game/doc/images/heartgame-search.webpbin0 -> 29732 bytes
-rw-r--r--examples/bluetooth/heartrate-game/doc/images/heartgame-start.pngbin13214 -> 0 bytes
-rw-r--r--examples/bluetooth/heartrate-game/doc/images/heartgame-start.webpbin0 -> 33590 bytes
-rw-r--r--examples/bluetooth/heartrate-game/doc/src/heartrate-game.qdoc61
-rw-r--r--examples/bluetooth/heartrate-game/heartrate-game.pro38
-rw-r--r--examples/bluetooth/heartrate-game/heartrate-global.h58
-rw-r--r--examples/bluetooth/heartrate-game/images.qrc7
-rw-r--r--examples/bluetooth/heartrate-game/images/alert.svg4
-rw-r--r--examples/bluetooth/heartrate-game/images/bluetooth.svg3
-rw-r--r--examples/bluetooth/heartrate-game/images/bt_off_to_on.png (renamed from examples/bluetooth/heartrate-game/qml/images/bt_off_to_on.png)bin6143 -> 6143 bytes
-rw-r--r--examples/bluetooth/heartrate-game/images/clock.svg4
-rw-r--r--examples/bluetooth/heartrate-game/images/heart.pngbin0 -> 2318 bytes
-rw-r--r--examples/bluetooth/heartrate-game/images/logo.png (renamed from examples/bluetooth/heartrate-game/qml/images/logo.png)bin31915 -> 31915 bytes
-rw-r--r--examples/bluetooth/heartrate-game/images/progress.svg4
-rw-r--r--examples/bluetooth/heartrate-game/images/search.svg4
-rw-r--r--examples/bluetooth/heartrate-game/main.cpp102
-rw-r--r--examples/bluetooth/heartrate-game/qml.qrc18
-rw-r--r--examples/bluetooth/heartrate-game/qml/App.qml130
-rw-r--r--examples/bluetooth/heartrate-game/qml/BluetoothAlarmDialog.qml122
-rw-r--r--examples/bluetooth/heartrate-game/qml/BottomLine.qml59
-rw-r--r--examples/bluetooth/heartrate-game/qml/Connect.qml188
-rw-r--r--examples/bluetooth/heartrate-game/qml/GameButton.qml88
-rw-r--r--examples/bluetooth/heartrate-game/qml/GamePage.qml93
-rw-r--r--examples/bluetooth/heartrate-game/qml/GameSettings.qml101
-rw-r--r--examples/bluetooth/heartrate-game/qml/Measure.qml244
-rw-r--r--examples/bluetooth/heartrate-game/qml/SplashScreen.qml90
-rw-r--r--examples/bluetooth/heartrate-game/qml/Stats.qml99
-rw-r--r--examples/bluetooth/heartrate-game/qml/StatsLabel.qml82
-rw-r--r--examples/bluetooth/heartrate-game/qml/TitleBar.qml97
-rw-r--r--examples/bluetooth/heartrate-game/qml/images/heart.pngbin2664 -> 0 bytes
-rw-r--r--examples/bluetooth/heartrate-game/qml/main.qml105
-rw-r--r--examples/bluetooth/heartrate-game/qml/qmldir1
-rw-r--r--examples/bluetooth/heartrate-game/qmldir15
-rw-r--r--examples/bluetooth/heartrate-server/CMakeLists.txt58
-rw-r--r--examples/bluetooth/heartrate-server/doc/src/heartrate-server.qdoc80
-rw-r--r--examples/bluetooth/heartrate-server/heartrate-server.pro7
-rw-r--r--examples/bluetooth/heartrate-server/main.cpp162
-rw-r--r--examples/bluetooth/lowenergyscanner/CMakeLists.txt72
-rw-r--r--examples/bluetooth/lowenergyscanner/Characteristics.qml121
-rw-r--r--examples/bluetooth/lowenergyscanner/Devices.qml144
-rw-r--r--examples/bluetooth/lowenergyscanner/Dialog.qml48
-rw-r--r--examples/bluetooth/lowenergyscanner/Header.qml25
-rw-r--r--examples/bluetooth/lowenergyscanner/Label.qml16
-rw-r--r--examples/bluetooth/lowenergyscanner/Main.qml31
-rw-r--r--examples/bluetooth/lowenergyscanner/Menu.qml55
-rw-r--r--examples/bluetooth/lowenergyscanner/Services.qml115
-rw-r--r--examples/bluetooth/lowenergyscanner/assets/Characteristics.qml161
-rw-r--r--examples/bluetooth/lowenergyscanner/assets/Dialog.qml89
-rw-r--r--examples/bluetooth/lowenergyscanner/assets/Header.qml71
-rw-r--r--examples/bluetooth/lowenergyscanner/assets/Label.qml63
-rw-r--r--examples/bluetooth/lowenergyscanner/assets/Menu.qml101
-rw-r--r--examples/bluetooth/lowenergyscanner/assets/Services.qml158
-rw-r--r--examples/bluetooth/lowenergyscanner/assets/main.qml162
-rw-r--r--examples/bluetooth/lowenergyscanner/characteristicinfo.cpp98
-rw-r--r--examples/bluetooth/lowenergyscanner/characteristicinfo.h63
-rw-r--r--examples/bluetooth/lowenergyscanner/device.cpp162
-rw-r--r--examples/bluetooth/lowenergyscanner/device.h91
-rw-r--r--examples/bluetooth/lowenergyscanner/deviceinfo.cpp63
-rw-r--r--examples/bluetooth/lowenergyscanner/deviceinfo.h65
-rw-r--r--examples/bluetooth/lowenergyscanner/doc/src/lowenergyscanner.qdoc66
-rw-r--r--examples/bluetooth/lowenergyscanner/lowenergyscanner.pro32
-rw-r--r--examples/bluetooth/lowenergyscanner/main.cpp77
-rw-r--r--examples/bluetooth/lowenergyscanner/qmldir11
-rw-r--r--examples/bluetooth/lowenergyscanner/resources.qrc12
-rw-r--r--examples/bluetooth/lowenergyscanner/serviceinfo.cpp72
-rw-r--r--examples/bluetooth/lowenergyscanner/serviceinfo.h65
-rw-r--r--examples/bluetooth/picturetransfer/Button.qml75
-rw-r--r--examples/bluetooth/picturetransfer/DeviceDiscovery.qml109
-rw-r--r--examples/bluetooth/picturetransfer/FileSending.qml111
-rw-r--r--examples/bluetooth/picturetransfer/PictureSelector.qml142
-rw-r--r--examples/bluetooth/picturetransfer/background.pngbin189737 -> 0 bytes
-rw-r--r--examples/bluetooth/picturetransfer/bttransfer.qml83
-rw-r--r--examples/bluetooth/picturetransfer/doc/images/opp-example-1.pngbin152770 -> 0 bytes
-rw-r--r--examples/bluetooth/picturetransfer/doc/images/opp-example-2.pngbin155839 -> 0 bytes
-rw-r--r--examples/bluetooth/picturetransfer/doc/images/opp-example-3.pngbin169837 -> 0 bytes
-rw-r--r--examples/bluetooth/picturetransfer/doc/src/picturetransfer.qdoc100
-rw-r--r--examples/bluetooth/picturetransfer/filetransfer.cpp77
-rw-r--r--examples/bluetooth/picturetransfer/filetransfer.h78
-rw-r--r--examples/bluetooth/picturetransfer/icon.pngbin4712 -> 0 bytes
-rw-r--r--examples/bluetooth/picturetransfer/main.cpp77
-rw-r--r--examples/bluetooth/picturetransfer/picturetransfer.pro28
-rw-r--r--examples/bluetooth/picturetransfer/qmltransfer.qrc10
-rw-r--r--examples/bluetooth/pingpong/assets/Board.qml190
-rw-r--r--examples/bluetooth/pingpong/assets/Dialog.qml71
-rw-r--r--examples/bluetooth/pingpong/assets/Menu.qml132
-rw-r--r--examples/bluetooth/pingpong/assets/main.qml72
-rw-r--r--examples/bluetooth/pingpong/doc/images/intro.pngbin27442 -> 0 bytes
-rw-r--r--examples/bluetooth/pingpong/doc/images/intro1.pngbin12522 -> 0 bytes
-rw-r--r--examples/bluetooth/pingpong/doc/src/pingpong.qdoc82
-rw-r--r--examples/bluetooth/pingpong/main.cpp68
-rw-r--r--examples/bluetooth/pingpong/pingpong.cpp489
-rw-r--r--examples/bluetooth/pingpong/pingpong.h150
-rw-r--r--examples/bluetooth/pingpong/pingpong.pro20
-rw-r--r--examples/bluetooth/pingpong/resource.qrc8
-rw-r--r--examples/bluetooth/scanner/Button.qml89
-rw-r--r--examples/bluetooth/scanner/default.pngbin4738 -> 0 bytes
-rw-r--r--examples/bluetooth/scanner/doc/images/devicescan.pngbin37924 -> 0 bytes
-rw-r--r--examples/bluetooth/scanner/doc/images/servicescan.pngbin80603 -> 0 bytes
-rw-r--r--examples/bluetooth/scanner/doc/src/scanner.qdoc58
-rw-r--r--examples/bluetooth/scanner/qmlscanner.cpp71
-rw-r--r--examples/bluetooth/scanner/scanner.pro18
-rw-r--r--examples/bluetooth/scanner/scanner.qml216
-rw-r--r--examples/bluetooth/scanner/scanner.qrc7
-rw-r--r--examples/bluetooth/shared/Info.cmake.ios.plist39
-rw-r--r--examples/bluetooth/shared/Info.cmake.macos.plist24
-rw-r--r--examples/bluetooth/shared/Info.qmake.ios.plist39
-rw-r--r--examples/bluetooth/shared/Info.qmake.macos.plist24
-rw-r--r--examples/nfc/CMakeLists.txt9
-rw-r--r--examples/nfc/annotatedurl/CMakeLists.txt55
-rw-r--r--examples/nfc/annotatedurl/Info.plist41
-rw-r--r--examples/nfc/annotatedurl/android/AndroidManifest.xml53
-rw-r--r--examples/nfc/annotatedurl/annotatedurl.cpp156
-rw-r--r--examples/nfc/annotatedurl/annotatedurl.h69
-rw-r--r--examples/nfc/annotatedurl/annotatedurl.pro9
-rw-r--r--examples/nfc/annotatedurl/doc/images/annotatedurl.pngbin7345 -> 5210 bytes
-rw-r--r--examples/nfc/annotatedurl/doc/images/annotatedurl2.pngbin7685 -> 7200 bytes
-rw-r--r--examples/nfc/annotatedurl/doc/images/annotatedurl3.pngbin0 -> 6392 bytes
-rw-r--r--examples/nfc/annotatedurl/doc/src/annotatedurl.qdoc133
-rw-r--r--examples/nfc/annotatedurl/main.cpp67
-rw-r--r--examples/nfc/annotatedurl/mainwindow.cpp161
-rw-r--r--examples/nfc/annotatedurl/mainwindow.h85
-rw-r--r--examples/nfc/annotatedurl/mainwindow.ui61
-rw-r--r--examples/nfc/corkboard/Mode.qml159
-rw-r--r--examples/nfc/corkboard/NfcFlag.pngbin8591 -> 0 bytes
-rw-r--r--examples/nfc/corkboard/android/AndroidManifest.xml84
-rw-r--r--examples/nfc/corkboard/cork.jpgbin149337 -> 0 bytes
-rw-r--r--examples/nfc/corkboard/corkboard.pro24
-rw-r--r--examples/nfc/corkboard/corkboard.qrc10
-rw-r--r--examples/nfc/corkboard/corkboards.qml128
-rw-r--r--examples/nfc/corkboard/doc/images/corkboard.pngbin639743 -> 0 bytes
-rw-r--r--examples/nfc/corkboard/doc/src/corkboard.qdoc137
-rw-r--r--examples/nfc/corkboard/icon.pngbin6594 -> 0 bytes
-rw-r--r--examples/nfc/corkboard/main.cpp66
-rw-r--r--examples/nfc/corkboard/note-yellow.pngbin54283 -> 0 bytes
-rw-r--r--examples/nfc/corkboard/tack.pngbin7282 -> 0 bytes
-rw-r--r--examples/nfc/ndefeditor/CMakeLists.txt69
-rw-r--r--examples/nfc/ndefeditor/Info.cmake.plist54
-rw-r--r--examples/nfc/ndefeditor/Info.qmake.plist49
-rw-r--r--examples/nfc/ndefeditor/Main.qml9
-rw-r--r--examples/nfc/ndefeditor/MainWindow.qml384
-rw-r--r--examples/nfc/ndefeditor/NdefRecordDelegate.qml50
-rw-r--r--examples/nfc/ndefeditor/doc/images/ndefeditor.pngbin13445 -> 29285 bytes
-rw-r--r--examples/nfc/ndefeditor/doc/src/ndefeditor.qdoc115
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20/add.pngbin0 -> 99 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20/arrow_back.pngbin0 -> 115 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20/file_download.pngbin0 -> 140 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20/file_upload.pngbin0 -> 141 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20/link.pngbin0 -> 168 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20/text_snippet.pngbin0 -> 197 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/add.pngbin0 -> 133 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/arrow_back.pngbin0 -> 157 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/file_download.pngbin0 -> 198 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/file_upload.pngbin0 -> 197 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/link.pngbin0 -> 273 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/text_snippet.pngbin0 -> 249 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/add.pngbin0 -> 148 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/arrow_back.pngbin0 -> 174 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/file_download.pngbin0 -> 268 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/file_upload.pngbin0 -> 266 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/link.pngbin0 -> 336 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/text_snippet.pngbin0 -> 295 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/add.pngbin0 -> 167 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/arrow_back.pngbin0 -> 234 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/file_download.pngbin0 -> 311 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/file_upload.pngbin0 -> 304 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/link.pngbin0 -> 457 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/text_snippet.pngbin0 -> 377 bytes
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/index.theme22
-rw-r--r--examples/nfc/ndefeditor/icons/ndefeditor/qt_attribution.json14
-rw-r--r--examples/nfc/ndefeditor/main.cpp70
-rw-r--r--examples/nfc/ndefeditor/mainwindow.cpp379
-rw-r--r--examples/nfc/ndefeditor/mainwindow.h114
-rw-r--r--examples/nfc/ndefeditor/mainwindow.ui225
-rw-r--r--examples/nfc/ndefeditor/mimeimagerecordeditor.cpp150
-rw-r--r--examples/nfc/ndefeditor/mimeimagerecordeditor.h87
-rw-r--r--examples/nfc/ndefeditor/mimeimagerecordeditor.ui83
-rw-r--r--examples/nfc/ndefeditor/ndefeditor.pro71
-rw-r--r--examples/nfc/ndefeditor/ndefmessagemodel.cpp156
-rw-r--r--examples/nfc/ndefeditor/ndefmessagemodel.h53
-rw-r--r--examples/nfc/ndefeditor/nfcmanager.cpp29
-rw-r--r--examples/nfc/ndefeditor/nfcmanager.h33
-rw-r--r--examples/nfc/ndefeditor/nfctarget.cpp31
-rw-r--r--examples/nfc/ndefeditor/nfctarget.h35
-rw-r--r--examples/nfc/ndefeditor/qmldir5
-rw-r--r--examples/nfc/ndefeditor/textrecordeditor.cpp91
-rw-r--r--examples/nfc/ndefeditor/textrecordeditor.h81
-rw-r--r--examples/nfc/ndefeditor/textrecordeditor.ui101
-rw-r--r--examples/nfc/ndefeditor/urirecordeditor.cpp80
-rw-r--r--examples/nfc/ndefeditor/urirecordeditor.h80
-rw-r--r--examples/nfc/ndefeditor/urirecordeditor.ui45
-rw-r--r--examples/nfc/nfc.pro11
-rw-r--r--examples/nfc/poster/doc/images/qml-poster-example.pngbin7946 -> 0 bytes
-rw-r--r--examples/nfc/poster/doc/src/poster.qdoc62
-rw-r--r--examples/nfc/poster/poster.pro16
-rw-r--r--examples/nfc/poster/poster.qml218
-rw-r--r--examples/nfc/poster/poster.qrc5
-rw-r--r--examples/nfc/poster/qmlposter.cpp68
-rw-r--r--licenseRule.json94
-rw-r--r--qtconnectivity.pro5
-rw-r--r--src/CMakeLists.txt12
-rw-r--r--src/android/CMakeLists.txt9
-rw-r--r--src/android/android.pro3
-rw-r--r--src/android/bluetooth/AndroidManifest.xml2
-rw-r--r--src/android/bluetooth/CMakeLists.txt27
-rw-r--r--src/android/bluetooth/bluetooth.pro19
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothBroadcastReceiver.java187
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothGattCharacteristic.java44
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothGattDescriptor.java39
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothInputStreamThread.java68
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLE.java1837
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLEServer.java989
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothSocketServer.java (renamed from src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer.java)86
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java193
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothInputStreamThread.java104
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java1532
-rw-r--r--src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLEServer.java611
-rw-r--r--src/android/nfc/AndroidManifest.xml2
-rw-r--r--src/android/nfc/CMakeLists.txt22
-rw-r--r--src/android/nfc/nfc.pro16
-rw-r--r--src/android/nfc/src/org/qtproject/qt/android/nfc/QtNfc.java (renamed from src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java)105
-rw-r--r--src/android/nfc/src/org/qtproject/qt/android/nfc/QtNfcBroadcastReceiver.java37
-rw-r--r--src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfcBroadcastReceiver.java72
-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
-rw-r--r--src/imports/bluetooth/bluetooth.pro17
-rw-r--r--src/imports/bluetooth/plugin.cpp84
-rw-r--r--src/imports/bluetooth/plugins.qmltypes409
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp651
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h170
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothservice.cpp382
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothservice_p.h131
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothsocket.cpp385
-rw-r--r--src/imports/bluetooth/qdeclarativebluetoothsocket_p.h148
-rw-r--r--src/imports/bluetooth/qmldir4
-rw-r--r--src/imports/imports.pro4
-rw-r--r--src/imports/nfc/nfc.pro20
-rw-r--r--src/imports/nfc/plugin.cpp101
-rw-r--r--src/imports/nfc/plugins.qmltypes91
-rw-r--r--src/imports/nfc/qdeclarativendeffilter.cpp167
-rw-r--r--src/imports/nfc/qdeclarativendeffilter_p.h93
-rw-r--r--src/imports/nfc/qdeclarativendefmimerecord.cpp97
-rw-r--r--src/imports/nfc/qdeclarativendefmimerecord_p.h75
-rw-r--r--src/imports/nfc/qdeclarativendeftextrecord.cpp180
-rw-r--r--src/imports/nfc/qdeclarativendeftextrecord_p.h95
-rw-r--r--src/imports/nfc/qdeclarativendefurirecord.cpp98
-rw-r--r--src/imports/nfc/qdeclarativendefurirecord_p.h80
-rw-r--r--src/imports/nfc/qdeclarativenearfield.cpp360
-rw-r--r--src/imports/nfc/qdeclarativenearfield_p.h135
-rw-r--r--src/imports/nfc/qmldir4
-rw-r--r--src/nfc/ApiChangesQt6.txt18
-rw-r--r--src/nfc/CMakeLists.txt125
-rw-r--r--src/nfc/android/androidjninfc.cpp94
-rw-r--r--src/nfc/android/androidjninfc_p.h73
-rw-r--r--src/nfc/android/androidmainnewintentlistener.cpp85
-rw-r--r--src/nfc/android/androidmainnewintentlistener_p.h69
-rw-r--r--src/nfc/configure.cmake12
-rw-r--r--src/nfc/doc/qtnfc.qdocconf25
-rw-r--r--src/nfc/doc/snippets/doc_src_qtnfc.cpp82
-rw-r--r--src/nfc/doc/snippets/doc_src_qtnfc.qml65
-rw-r--r--src/nfc/doc/snippets/foorecord.cpp124
-rw-r--r--src/nfc/doc/snippets/foorecord.h78
-rw-r--r--src/nfc/doc/snippets/main.cpp51
-rw-r--r--src/nfc/doc/snippets/nfc.cpp51
-rw-r--r--src/nfc/doc/snippets/snippets.pro13
-rw-r--r--src/nfc/doc/src/examples.qdoc42
-rw-r--r--src/nfc/doc/src/nfc-android.qdoc91
-rw-r--r--src/nfc/doc/src/nfc-cpp.qdoc45
-rw-r--r--src/nfc/doc/src/nfc-features.qdoc64
-rw-r--r--src/nfc/doc/src/nfc-index.qdoc122
-rw-r--r--src/nfc/doc/src/nfc-overview.qdoc166
-rw-r--r--src/nfc/doc/src/nfc-pcsc.qdoc34
-rw-r--r--src/nfc/doc/src/nfc-qml.qdoc43
-rw-r--r--src/nfc/doc/src/qt6-changes.qdoc149
-rw-r--r--src/nfc/ios/qiosndefnotifier.cpp11
-rw-r--r--src/nfc/ios/qiosndefnotifier_p.h56
-rw-r--r--src/nfc/ios/qiosnfcndefsessiondelegate.mm298
-rw-r--r--src/nfc/ios/qiosnfcndefsessiondelegate_p.h88
-rw-r--r--src/nfc/ios/qiostagreaderdelegate.mm110
-rw-r--r--src/nfc/ios/qiostagreaderdelegate_p.h48
-rw-r--r--src/nfc/ndef/qndefaccessfsm_p.h103
-rw-r--r--src/nfc/ndef/qnfctagtype4ndeffsm.cpp374
-rw-r--r--src/nfc/ndef/qnfctagtype4ndeffsm_p.h82
-rw-r--r--src/nfc/neard/adapter.cpp25
-rw-r--r--src/nfc/neard/adapter_p.h60
-rw-r--r--src/nfc/neard/agent.cpp38
-rw-r--r--src/nfc/neard/agent_p.h100
-rw-r--r--src/nfc/neard/dbusobjectmanager.cpp26
-rw-r--r--src/nfc/neard/dbusobjectmanager_p.h58
-rw-r--r--src/nfc/neard/dbusproperties.cpp26
-rw-r--r--src/nfc/neard/dbusproperties_p.h71
-rw-r--r--src/nfc/neard/manager.cpp25
-rw-r--r--src/nfc/neard/manager_p.h91
-rw-r--r--src/nfc/neard/neard.pri22
-rw-r--r--src/nfc/neard/neard_dbus_types_p.h28
-rw-r--r--src/nfc/neard/neard_helper.cpp44
-rw-r--r--src/nfc/neard/neard_helper_p.h51
-rw-r--r--src/nfc/neard/org.freedesktop.dbus.objectmanager.xml2
-rw-r--r--src/nfc/neard/org.freedesktop.dbus.properties.xml2
-rw-r--r--src/nfc/neard/org.neard.Agent.xml26
-rw-r--r--src/nfc/neard/org.neard.Manager.xml38
-rw-r--r--src/nfc/neard/tag.cpp25
-rw-r--r--src/nfc/neard/tag_p.h60
-rw-r--r--src/nfc/nfc.pro134
-rw-r--r--src/nfc/pcsc/qpcsc.cpp32
-rw-r--r--src/nfc/pcsc/qpcsc_p.h72
-rw-r--r--src/nfc/pcsc/qpcsccard.cpp419
-rw-r--r--src/nfc/pcsc/qpcsccard_p.h96
-rw-r--r--src/nfc/pcsc/qpcscmanager.cpp357
-rw-r--r--src/nfc/pcsc/qpcscmanager_p.h65
-rw-r--r--src/nfc/pcsc/qpcscslot.cpp57
-rw-r--r--src/nfc/pcsc/qpcscslot_p.h46
-rw-r--r--src/nfc/qapduutils.cpp81
-rw-r--r--src/nfc/qapduutils_p.h53
-rw-r--r--src/nfc/qllcpserver.cpp200
-rw-r--r--src/nfc/qllcpserver_android_p.cpp131
-rw-r--r--src/nfc/qllcpserver_android_p.h93
-rw-r--r--src/nfc/qllcpserver_p.cpp94
-rw-r--r--src/nfc/qllcpserver_p.h94
-rw-r--r--src/nfc/qllcpserver_p_p.h87
-rw-r--r--src/nfc/qllcpsocket.cpp400
-rw-r--r--src/nfc/qllcpsocket_android_p.cpp324
-rw-r--r--src/nfc/qllcpsocket_android_p.h134
-rw-r--r--src/nfc/qllcpsocket_p.cpp192
-rw-r--r--src/nfc/qllcpsocket_p.h142
-rw-r--r--src/nfc/qllcpsocket_p_p.h106
-rw-r--r--src/nfc/qndeffilter.cpp404
-rw-r--r--src/nfc/qndeffilter.h58
-rw-r--r--src/nfc/qndefmessage.cpp170
-rw-r--r--src/nfc/qndefmessage.h75
-rw-r--r--src/nfc/qndefnfcsmartposterrecord.cpp233
-rw-r--r--src/nfc/qndefnfcsmartposterrecord.h54
-rw-r--r--src/nfc/qndefnfcsmartposterrecord_p.h54
-rw-r--r--src/nfc/qndefnfctextrecord.cpp67
-rw-r--r--src/nfc/qndefnfctextrecord.h40
-rw-r--r--src/nfc/qndefnfcurirecord.cpp46
-rw-r--r--src/nfc/qndefnfcurirecord.h40
-rw-r--r--src/nfc/qndefrecord.cpp74
-rw-r--r--src/nfc/qndefrecord.h44
-rw-r--r--src/nfc/qndefrecord_p.h40
-rw-r--r--src/nfc/qnearfieldmanager.cpp331
-rw-r--r--src/nfc/qnearfieldmanager.h76
-rw-r--r--src/nfc/qnearfieldmanager_android.cpp331
-rw-r--r--src/nfc/qnearfieldmanager_android_p.h99
-rw-r--r--src/nfc/qnearfieldmanager_emulator.cpp101
-rw-r--r--src/nfc/qnearfieldmanager_emulator_p.h89
-rw-r--r--src/nfc/qnearfieldmanager_generic.cpp24
-rw-r--r--src/nfc/qnearfieldmanager_generic_p.h31
-rw-r--r--src/nfc/qnearfieldmanager_ios.mm278
-rw-r--r--src/nfc/qnearfieldmanager_ios_p.h84
-rw-r--r--src/nfc/qnearfieldmanager_neard.cpp100
-rw-r--r--src/nfc/qnearfieldmanager_neard_p.h61
-rw-r--r--src/nfc/qnearfieldmanager_p.h86
-rw-r--r--src/nfc/qnearfieldmanager_pcsc.cpp140
-rw-r--r--src/nfc/qnearfieldmanager_pcsc_p.h55
-rw-r--r--src/nfc/qnearfieldmanagerimpl_p.cpp60
-rw-r--r--src/nfc/qnearfieldmanagerimpl_p.h67
-rw-r--r--src/nfc/qnearfieldmanagervirtualbase.cpp214
-rw-r--r--src/nfc/qnearfieldmanagervirtualbase_p.h99
-rw-r--r--src/nfc/qnearfieldsharemanager.cpp181
-rw-r--r--src/nfc/qnearfieldsharemanager.h104
-rw-r--r--src/nfc/qnearfieldsharemanager_p.h91
-rw-r--r--src/nfc/qnearfieldsharemanagerimpl_p.cpp58
-rw-r--r--src/nfc/qnearfieldsharemanagerimpl_p.h69
-rw-r--r--src/nfc/qnearfieldsharetarget.cpp148
-rw-r--r--src/nfc/qnearfieldsharetarget.h84
-rw-r--r--src/nfc/qnearfieldsharetarget_p.h108
-rw-r--r--src/nfc/qnearfieldsharetargetimpl_p.cpp53
-rw-r--r--src/nfc/qnearfieldsharetargetimpl_p.h68
-rw-r--r--src/nfc/qnearfieldtagtype1_p.h108
-rw-r--r--src/nfc/qnearfieldtagtype2_p.h94
-rw-r--r--src/nfc/qnearfieldtagtype3.cpp185
-rw-r--r--src/nfc/qnearfieldtagtype3_p.h86
-rw-r--r--src/nfc/qnearfieldtagtype4.cpp161
-rw-r--r--src/nfc/qnearfieldtagtype4_p.h82
-rw-r--r--src/nfc/qnearfieldtarget.cpp328
-rw-r--r--src/nfc/qnearfieldtarget.h103
-rw-r--r--src/nfc/qnearfieldtarget_android.cpp419
-rw-r--r--src/nfc/qnearfieldtarget_android_p.cpp71
-rw-r--r--src/nfc/qnearfieldtarget_android_p.h109
-rw-r--r--src/nfc/qnearfieldtarget_emulator.cpp297
-rw-r--r--src/nfc/qnearfieldtarget_emulator_p.h127
-rw-r--r--src/nfc/qnearfieldtarget_ios.mm467
-rw-r--r--src/nfc/qnearfieldtarget_ios_p.h119
-rw-r--r--src/nfc/qnearfieldtarget_neard_p.cpp361
-rw-r--r--src/nfc/qnearfieldtarget_neard_p.h386
-rw-r--r--src/nfc/qnearfieldtarget_p.cpp160
-rw-r--r--src/nfc/qnearfieldtarget_p.h96
-rw-r--r--src/nfc/qnearfieldtarget_pcsc.cpp161
-rw-r--r--src/nfc/qnearfieldtarget_pcsc_p.h67
-rw-r--r--src/nfc/qnfc.cpp47
-rw-r--r--src/nfc/qqmlndefrecord.cpp356
-rw-r--r--src/nfc/qqmlndefrecord.h112
-rw-r--r--src/nfc/qtlv_p.h133
-rw-r--r--src/nfc/qtnfcglobal.h55
-rw-r--r--src/nfc/qtnfcglobal_p.h40
-rw-r--r--src/nfc/targetemulator_p.h121
-rw-r--r--src/src.pro30
-rw-r--r--src/tools/sdpscanner/CMakeLists.txt20
-rw-r--r--src/tools/sdpscanner/main.cpp61
-rw-r--r--src/tools/sdpscanner/qt_attribution.json2
-rw-r--r--src/tools/sdpscanner/sdpscanner.pro16
-rw-r--r--sync.profile27
-rw-r--r--tests/CMakeLists.txt17
-rw-r--r--tests/auto/CMakeLists.txt32
-rw-r--r--tests/auto/auto.pro35
-rw-r--r--tests/auto/bic/data/QtBluetooth.5.14.0.linux-gcc-amd64.txt5462
-rw-r--r--tests/auto/bic/data/QtNfc.5.14.0.linux-gcc-amd64.txt5228
-rw-r--r--tests/auto/cmake/CMakeLists.txt45
-rw-r--r--tests/auto/cmake/cmake.pro7
-rw-r--r--tests/auto/nfccommons/qnearfieldmanager_emulator.cpp90
-rw-r--r--tests/auto/nfccommons/qnearfieldmanager_emulator_p.h61
-rw-r--r--tests/auto/nfccommons/qnearfieldtagtype1.cpp (renamed from src/nfc/qnearfieldtagtype1.cpp)137
-rw-r--r--tests/auto/nfccommons/qnearfieldtagtype1_p.h72
-rw-r--r--tests/auto/nfccommons/qnearfieldtagtype2.cpp (renamed from src/nfc/qnearfieldtagtype2.cpp)89
-rw-r--r--tests/auto/nfccommons/qnearfieldtagtype2_p.h58
-rw-r--r--tests/auto/nfccommons/qnearfieldtarget_emulator.cpp279
-rw-r--r--tests/auto/nfccommons/qnearfieldtarget_emulator_p.h96
-rw-r--r--tests/auto/nfccommons/qtlv.cpp (renamed from src/nfc/qtlv.cpp)70
-rw-r--r--tests/auto/nfccommons/qtlv_p.h96
-rw-r--r--tests/auto/nfccommons/targetemulator.cpp (renamed from src/nfc/targetemulator.cpp)72
-rw-r--r--tests/auto/nfccommons/targetemulator_p.h88
-rw-r--r--tests/auto/qbluetoothaddress/CMakeLists.txt19
-rw-r--r--tests/auto/qbluetoothaddress/qbluetoothaddress.pro6
-rw-r--r--tests/auto/qbluetoothaddress/tst_qbluetoothaddress.cpp29
-rw-r--r--tests/auto/qbluetoothdevicediscoveryagent/CMakeLists.txt39
-rw-r--r--tests/auto/qbluetoothdevicediscoveryagent/qbluetoothdevicediscoveryagent.pro6
-rw-r--r--tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp329
-rw-r--r--tests/auto/qbluetoothdeviceinfo/CMakeLists.txt19
-rw-r--r--tests/auto/qbluetoothdeviceinfo/qbluetoothdeviceinfo.pro5
-rw-r--r--tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp51
-rw-r--r--tests/auto/qbluetoothhostinfo/CMakeLists.txt19
-rw-r--r--tests/auto/qbluetoothhostinfo/qbluetoothhostinfo.pro6
-rw-r--r--tests/auto/qbluetoothhostinfo/tst_qbluetoothhostinfo.cpp29
-rw-r--r--tests/auto/qbluetoothlocaldevice/CMakeLists.txt27
-rw-r--r--tests/auto/qbluetoothlocaldevice/qbluetoothlocaldevice.pro6
-rw-r--r--tests/auto/qbluetoothlocaldevice/tst_qbluetoothlocaldevice.cpp345
-rw-r--r--tests/auto/qbluetoothserver/CMakeLists.txt30
-rw-r--r--tests/auto/qbluetoothserver/qbluetoothserver.pro10
-rw-r--r--tests/auto/qbluetoothserver/tst_qbluetoothserver.cpp70
-rw-r--r--tests/auto/qbluetoothservicediscoveryagent/CMakeLists.txt39
-rw-r--r--tests/auto/qbluetoothservicediscoveryagent/qbluetoothservicediscoveryagent.pro7
-rw-r--r--tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp171
-rw-r--r--tests/auto/qbluetoothserviceinfo/CMakeLists.txt32
-rw-r--r--tests/auto/qbluetoothserviceinfo/qbluetoothserviceinfo.pro11
-rw-r--r--tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp158
-rw-r--r--tests/auto/qbluetoothsocket/CMakeLists.txt39
-rw-r--r--tests/auto/qbluetoothsocket/qbluetoothsocket.pro16
-rw-r--r--tests/auto/qbluetoothsocket/tst_qbluetoothsocket.cpp200
-rw-r--r--tests/auto/qbluetoothtransfermanager/qbluetoothtransfermanager.pro8
-rw-r--r--tests/auto/qbluetoothtransfermanager/testfile.txt1
-rw-r--r--tests/auto/qbluetoothtransfermanager/tst_qbluetoothtransfermanager.cpp360
-rw-r--r--tests/auto/qbluetoothtransferrequest/qbluetoothtransferrequest.pro5
-rw-r--r--tests/auto/qbluetoothtransferrequest/tst_qbluetoothtransferrequest.cpp164
-rw-r--r--tests/auto/qbluetoothuuid/CMakeLists.txt20
-rw-r--r--tests/auto/qbluetoothuuid/qbluetoothuuid.pro5
-rw-r--r--tests/auto/qbluetoothuuid/tst_qbluetoothuuid.cpp200
-rw-r--r--tests/auto/qlowenergycharacteristic/CMakeLists.txt31
-rw-r--r--tests/auto/qlowenergycharacteristic/qlowenergycharacteristic.pro7
-rw-r--r--tests/auto/qlowenergycharacteristic/tst_qlowenergycharacteristic.cpp127
-rw-r--r--tests/auto/qlowenergycontroller-gattserver/CMakeLists.txt2
-rw-r--r--tests/auto/qlowenergycontroller-gattserver/qlowenergycontroller-gattserver.pro2
-rw-r--r--tests/auto/qlowenergycontroller-gattserver/server/CMakeLists.txt15
-rw-r--r--tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp52
-rw-r--r--tests/auto/qlowenergycontroller-gattserver/server/server.pro5
-rw-r--r--tests/auto/qlowenergycontroller-gattserver/test/CMakeLists.txt38
-rw-r--r--tests/auto/qlowenergycontroller-gattserver/test/test.pro12
-rw-r--r--tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp194
-rw-r--r--tests/auto/qlowenergycontroller/CMakeLists.txt44
-rw-r--r--tests/auto/qlowenergycontroller/qlowenergycontroller.pro13
-rw-r--r--tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp1197
-rw-r--r--tests/auto/qlowenergydescriptor/CMakeLists.txt31
-rw-r--r--tests/auto/qlowenergydescriptor/qlowenergydescriptor.pro6
-rw-r--r--tests/auto/qlowenergydescriptor/tst_qlowenergydescriptor.cpp128
-rw-r--r--tests/auto/qlowenergyservice/CMakeLists.txt19
-rw-r--r--tests/auto/qlowenergyservice/qlowenergyservice.pro6
-rw-r--r--tests/auto/qlowenergyservice/tst_qlowenergyservice.cpp29
-rw-r--r--tests/auto/qndeffilter/CMakeLists.txt15
-rw-r--r--tests/auto/qndeffilter/tst_qndeffilter.cpp485
-rw-r--r--tests/auto/qndefmessage/CMakeLists.txt19
-rw-r--r--tests/auto/qndefmessage/qndefmessage.pro5
-rw-r--r--tests/auto/qndefmessage/tst_qndefmessage.cpp416
-rw-r--r--tests/auto/qndefnfcsmartposterrecord/CMakeLists.txt19
-rw-r--r--tests/auto/qndefnfcsmartposterrecord/qndefnfcsmartposterrecord.pro5
-rw-r--r--tests/auto/qndefnfcsmartposterrecord/tst_qndefnfcsmartposterrecord.cpp91
-rw-r--r--tests/auto/qndefrecord/CMakeLists.txt19
-rw-r--r--tests/auto/qndefrecord/qndefrecord.pro5
-rw-r--r--tests/auto/qndefrecord/tst_qndefrecord.cpp268
-rw-r--r--tests/auto/qnearfieldmanager/CMakeLists.txt49
-rw-r--r--tests/auto/qnearfieldmanager/qnearfieldmanager.pro29
-rw-r--r--tests/auto/qnearfieldmanager/tst_qnearfieldmanager.cpp268
-rw-r--r--tests/auto/qnearfieldtagtype1/CMakeLists.txt48
-rw-r--r--tests/auto/qnearfieldtagtype1/qnearfieldtagtype1.pro29
-rw-r--r--tests/auto/qnearfieldtagtype1/tst_qnearfieldtagtype1.cpp104
-rw-r--r--tests/auto/qnearfieldtagtype2/CMakeLists.txt48
-rw-r--r--tests/auto/qnearfieldtagtype2/qnearfieldtagtype2.pro29
-rw-r--r--tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp85
-rw-r--r--tests/bluetoothtestdevice/CMakeLists.txt74
-rw-r--r--tests/bluetoothtestdevice/bluetoothtestdevice.cpp474
-rw-r--r--tests/bttestui/Button.qml31
-rw-r--r--tests/bttestui/CMakeLists.txt89
-rw-r--r--tests/bttestui/btlocaldevice.cpp1008
-rw-r--r--tests/bttestui/btlocaldevice.h121
-rw-r--r--tests/bttestui/bttest.qrc6
-rw-r--r--tests/bttestui/bttestui.pro18
-rw-r--r--tests/bttestui/main.cpp56
-rw-r--r--tests/bttestui/main.qml617
-rw-r--r--tests/manual/CMakeLists.txt9
-rw-r--r--tests/manual/examples/btscanner/CMakeLists.txt48
-rw-r--r--tests/manual/examples/btscanner/Info.plist41
-rw-r--r--tests/manual/examples/btscanner/btscanner.pro (renamed from examples/bluetooth/btscanner/btscanner.pro)3
-rw-r--r--tests/manual/examples/btscanner/device.cpp182
-rw-r--r--tests/manual/examples/btscanner/device.h49
-rw-r--r--tests/manual/examples/btscanner/device.ui (renamed from examples/bluetooth/btscanner/device.ui)17
-rw-r--r--tests/manual/examples/btscanner/main.cpp33
-rw-r--r--tests/manual/examples/btscanner/service.cpp62
-rw-r--r--tests/manual/examples/btscanner/service.h36
-rw-r--r--tests/manual/examples/btscanner/service.ui (renamed from examples/bluetooth/btscanner/service.ui)63
-rw-r--r--tests/manual/qlowenergycontroller/CMakeLists.txt68
-rw-r--r--tests/manual/qlowenergycontroller/tst_qlowenergycontroller_device.cpp945
-rw-r--r--tests/manual/qlowenergycontroller_peripheral/CMakeLists.txt67
-rw-r--r--tests/manual/qlowenergycontroller_peripheral/tst_qlowenergycontroller_peripheral.cpp167
-rw-r--r--tests/shared/Info.ios.plist35
-rw-r--r--tests/shared/Info.macos.plist24
-rw-r--r--tests/shared/bttestutil_p.h47
-rw-r--r--tests/tests.pro4
982 files changed, 48593 insertions, 62824 deletions
diff --git a/.cmake.conf b/.cmake.conf
new file mode 100644
index 00000000..62cb061c
--- /dev/null
+++ b/.cmake.conf
@@ -0,0 +1,4 @@
+set(QT_REPO_MODULE_VERSION "6.8.0")
+set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1")
+set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1")
+list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_FOREACH=1")
diff --git a/.gitignore b/.gitignore
index 1b9be3d7..8eca9081 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
.DS_Store
*.pro.user
*.pro.shared
+CMakeLists.txt.user
*~
Makefile*
*.pdb
@@ -18,7 +19,7 @@ moc_*.cpp
ui_*.h
qrc_*.cpp
*.moc
-*so-deployment-settings.json
+*deployment-settings.json
.qmake.cache
.pch
QtBluetooth.version*
@@ -31,20 +32,15 @@ qmlplugindump_wrapper.sh
qdbusxml2cpp_wrapper.sh
config.log
tmp
-imports/*
include
config.tests/bluez/bluez
config.tests/bluez_le/bluez_le
examples/bluetooth/btchat/btchat
-examples/bluetooth/btfiletransfer/btfiletransfer
examples/bluetooth/btscanner/btscanner
-examples/bluetooth/chat/qml_chat
examples/bluetooth/heartrate-game/heartrate-game
examples/bluetooth/heartrate-server/heartrate-server
examples/bluetooth/lowenergyscanner/lowenergyscanner
examples/bluetooth/pingpong/pingpong
-examples/bluetooth/picturetransfer/qml_picturetransfer
-examples/bluetooth/scanner/qml_scanner
examples/nfc/annotatedurl/annotatedurl
examples/nfc/ndefeditor/ndefeditor
examples/nfc/poster/qml_poster
@@ -68,8 +64,6 @@ tests/auto/qbluetoothserver/tst_qbluetoothserver
tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent
tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo
tests/auto/qbluetoothsocket/tst_qbluetoothsocket
-tests/auto/qbluetoothtransfermanager/tst_qbluetoothtransfermanager
-tests/auto/qbluetoothtransferrequest/tst_qbluetoothtransferrequest
tests/auto/qbluetoothuuid/tst_qbluetoothuuid
tests/auto/qlowenergycharacteristic/tst_qlowenergycharacteristic
tests/auto/qlowenergycontroller/tst_qlowenergycontroller
diff --git a/.qmake.conf b/.qmake.conf
deleted file mode 100644
index 85f18db7..00000000
--- a/.qmake.conf
+++ /dev/null
@@ -1,5 +0,0 @@
-load(qt_build_config)
-
-DEFINES += QT_NO_FOREACH QT_NO_JAVA_STYLE_ITERATORS QT_NO_LINKED_LIST
-
-MODULE_VERSION = 6.0.0
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..babfc18f
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+
+include(.cmake.conf)
+project(QtConnectivity
+ VERSION "${QT_REPO_MODULE_VERSION}"
+ DESCRIPTION "Qt Connectivity Libraries"
+ HOMEPAGE_URL "https://qt.io/"
+ LANGUAGES CXX C
+)
+
+find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core Network)
+find_package(Qt6 ${PROJECT_VERSION} CONFIG OPTIONAL_COMPONENTS
+ DBus Gui Widgets Quick QuickControls2)
+qt_internal_project_setup()
+
+if(NOT TARGET Qt::Network)
+ message(NOTICE "Skipping the build as the condition \"TARGET Qt::Network\" is not met.")
+ return()
+endif()
+
+qt_build_repo()
diff --git a/LICENSE.GPL3-EXCEPT b/LICENSE.GPL3-EXCEPT
deleted file mode 100644
index b1cb1bec..00000000
--- a/LICENSE.GPL3-EXCEPT
+++ /dev/null
@@ -1,704 +0,0 @@
-This is the GNU General Public License version 3, annotated with The
-Qt Company GPL Exception 1.0:
-
--------------------------------------------------------------------------
-
-The Qt Company GPL Exception 1.0
-
-Exception 1:
-
-As a special exception you may create a larger work which contains the
-output of this application and distribute that work under terms of your
-choice, so long as the work is not otherwise derived from or based on
-this application and so long as the work does not in itself generate
-output that contains the output from this application in its original
-or modified form.
-
-Exception 2:
-
-As a special exception, you have permission to combine this application
-with Plugins licensed under the terms of your choice, to produce an
-executable, and to copy and distribute the resulting executable under
-the terms of your choice. However, the executable must be accompanied
-by a prominent notice offering all users of the executable the entire
-source code to this application, excluding the source code of the
-independent modules, but including any changes you have made to this
-application, under the terms of this license.
-
-
--------------------------------------------------------------------------
-
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- <program> Copyright (C) <year> <name of author>
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt
new file mode 100644
index 00000000..136d9004
--- /dev/null
+++ b/LICENSES/Apache-2.0.txt
@@ -0,0 +1,61 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt
new file mode 100644
index 00000000..b91bbd89
--- /dev/null
+++ b/LICENSES/BSD-3-Clause.txt
@@ -0,0 +1,9 @@
+Copyright (c) <year> <owner>.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ 2. 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.
+ 3. Neither the name of the copyright holder 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 HOLDER 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.
diff --git a/LICENSE.FDL b/LICENSES/GFDL-1.3-no-invariants-only.txt
index 938bb8da..857214dd 100644
--- a/LICENSE.FDL
+++ b/LICENSES/GFDL-1.3-no-invariants-only.txt
@@ -1,9 +1,10 @@
+
GNU Free Documentation License
Version 1.3, 3 November 2008
Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
- <http://fsf.org/>
+ <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -376,7 +377,7 @@ The Free Software Foundation may publish new, revised versions of the
GNU Free Documentation License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in
detail to address new problems or concerns. See
-http://www.gnu.org/copyleft/.
+https://www.gnu.org/licenses/.
Each version of the License is given a distinguishing version number.
If the Document specifies that a particular numbered version of this
@@ -400,19 +401,19 @@ public wiki that anybody can edit is an example of such a server. A
"Massive Multiauthor Collaboration" (or "MMC") contained in the site
means any set of copyrightable works thus published on the MMC site.
-"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0
-license published by Creative Commons Corporation, a not-for-profit
-corporation with a principal place of business in San Francisco,
-California, as well as future copyleft versions of that license
+"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0
+license published by Creative Commons Corporation, a not-for-profit
+corporation with a principal place of business in San Francisco,
+California, as well as future copyleft versions of that license
published by that same organization.
-"Incorporate" means to publish or republish a Document, in whole or in
+"Incorporate" means to publish or republish a Document, in whole or in
part, as part of another Document.
-An MMC is "eligible for relicensing" if it is licensed under this
-License, and if all works that were first published under this License
-somewhere other than this MMC, and subsequently incorporated in whole or
-in part into the MMC, (1) had no cover texts or invariant sections, and
+An MMC is "eligible for relicensing" if it is licensed under this
+License, and if all works that were first published under this License
+somewhere other than this MMC, and subsequently incorporated in whole or
+in part into the MMC, (1) had no cover texts or invariant sections, and
(2) were thus incorporated prior to November 1, 2008.
The operator of an MMC Site may republish an MMC contained in the site
diff --git a/LICENSE.GPL2 b/LICENSES/GPL-2.0-only.txt
index d159169d..d159169d 100644
--- a/LICENSE.GPL2
+++ b/LICENSES/GPL-2.0-only.txt
diff --git a/LICENSE.GPL3 b/LICENSES/GPL-3.0-only.txt
index 94a9ed02..94a9ed02 100644
--- a/LICENSE.GPL3
+++ b/LICENSES/GPL-3.0-only.txt
diff --git a/LICENSE.LGPL3 b/LICENSES/LGPL-3.0-only.txt
index 65c5ca88..65c5ca88 100644
--- a/LICENSE.LGPL3
+++ b/LICENSES/LGPL-3.0-only.txt
diff --git a/LICENSES/LicenseRef-Qt-Commercial.txt b/LICENSES/LicenseRef-Qt-Commercial.txt
new file mode 100644
index 00000000..825b1f35
--- /dev/null
+++ b/LICENSES/LicenseRef-Qt-Commercial.txt
@@ -0,0 +1,8 @@
+Licensees holding valid commercial Qt licenses may use this software in
+accordance with the the terms contained in a written agreement between
+you and The Qt Company. Alternatively, the terms and conditions that were
+accepted by the licensee when buying and/or downloading the
+software do apply.
+
+For the latest 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.
diff --git a/LICENSES/Qt-GPL-exception-1.0.txt b/LICENSES/Qt-GPL-exception-1.0.txt
new file mode 100644
index 00000000..d0322bf0
--- /dev/null
+++ b/LICENSES/Qt-GPL-exception-1.0.txt
@@ -0,0 +1,22 @@
+The Qt Company GPL Exception 1.0
+
+Exception 1:
+
+As a special exception you may create a larger work which contains the
+output of this application and distribute that work under terms of your
+choice, so long as the work is not otherwise derived from or based on
+this application and so long as the work does not in itself generate
+output that contains the output from this application in its original
+or modified form.
+
+Exception 2:
+
+As a special exception, you have permission to combine this application
+with Plugins licensed under the terms of your choice, to produce an
+executable, and to copy and distribute the resulting executable under
+the terms of your choice. However, the executable must be accompanied
+by a prominent notice offering all users of the executable the entire
+source code to this application, excluding the source code of the
+independent modules, but including any changes you have made to this
+application, under the terms of this license.
+
diff --git a/cmake/FindBlueZ.cmake b/cmake/FindBlueZ.cmake
new file mode 100644
index 00000000..b1d30122
--- /dev/null
+++ b/cmake/FindBlueZ.cmake
@@ -0,0 +1,12 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+set(BlueZ_FOUND 0)
+
+find_package(PkgConfig QUIET)
+
+pkg_check_modules(BLUEZ bluez IMPORTED_TARGET)
+
+if(TARGET PkgConfig::BLUEZ)
+ set(BlueZ_FOUND 1)
+endif()
diff --git a/cmake/FindPCSCLITE.cmake b/cmake/FindPCSCLITE.cmake
new file mode 100644
index 00000000..2abb6261
--- /dev/null
+++ b/cmake/FindPCSCLITE.cmake
@@ -0,0 +1,21 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(WIN32)
+ add_library(PkgConfig::PCSCLITE INTERFACE IMPORTED)
+ target_link_libraries(PkgConfig::PCSCLITE INTERFACE winscard)
+ set(PCSCLITE_FOUND 1)
+elseif(MACOS)
+ qt_internal_find_apple_system_framework(FWPCSC PCSC)
+ add_library(PkgConfig::PCSCLITE INTERFACE IMPORTED)
+ target_link_libraries(PkgConfig::PCSCLITE INTERFACE ${FWPCSC})
+ set(PCSCLITE_FOUND 1)
+else()
+ find_package(PkgConfig QUIET)
+
+ pkg_check_modules(PCSCLITE libpcsclite IMPORTED_TARGET)
+endif()
+
+if(NOT TARGET PkgConfig::PCSCLITE)
+ set(PCSCLITE_FOUND 0)
+endif()
diff --git a/coin/axivion/ci_config_linux.json b/coin/axivion/ci_config_linux.json
new file mode 100644
index 00000000..b7ae35f2
--- /dev/null
+++ b/coin/axivion/ci_config_linux.json
@@ -0,0 +1,40 @@
+{
+ "Project": {
+ "BuildSystemIntegration": {
+ "child_order": [
+ "GCCSetup",
+ "CMake",
+ "LinkLibraries"
+ ]
+ },
+ "CMake": {
+ "_active": true,
+ "_copy_from": "CMakeIntegration",
+ "build_environment": {},
+ "build_options": "-j4",
+ "generate_options": "--fresh",
+ "generator": "Ninja"
+ },
+ "GCCSetup": {
+ "_active": true,
+ "_copy_from": "Command",
+ "build_command": "gccsetup --cc gcc --cxx g++ --config ../../../axivion/"
+ },
+ "LinkLibraries": {
+ "_active": true,
+ "_copy_from": "AxivionLinker",
+ "input_files": [
+ "build/lib/lib*.so*.ir"
+ ],
+ "ir": "build/$(env:TESTED_MODULE_COIN).ir"
+ }
+ },
+ "_Format": "1.0",
+ "_Version": "7.6.2",
+ "_VersionNum": [
+ 7,
+ 6,
+ 2,
+ 12725
+ ]
+}
diff --git a/coin/module_config.yaml b/coin/module_config.yaml
new file mode 100644
index 00000000..aaf33238
--- /dev/null
+++ b/coin/module_config.yaml
@@ -0,0 +1,13 @@
+version: 2
+accept_configuration:
+ condition: property
+ property: features
+ not_contains_value: Disable
+
+instructions:
+ Build:
+ - !include "{{qt/qtbase}}/coin_module_build_template_v2.yaml"
+
+ Test:
+ - !include "{{qt/qtbase}}/coin_module_test_template_v3.yaml"
+ - !include "{{qt/qtbase}}/coin_module_test_docs.yaml"
diff --git a/config.tests/bluez/CMakeLists.txt b/config.tests/bluez/CMakeLists.txt
new file mode 100644
index 00000000..975a71f2
--- /dev/null
+++ b/config.tests/bluez/CMakeLists.txt
@@ -0,0 +1,34 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(config_test_bluez LANGUAGES C CXX)
+
+if(DEFINED QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_PREFIX_PATH)
+ set(CMAKE_SYSTEM_PREFIX_PATH "${QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_PREFIX_PATH}")
+endif()
+if(DEFINED QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_FRAMEWORK_PATH)
+ set(CMAKE_SYSTEM_FRAMEWORK_PATH "${QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_FRAMEWORK_PATH}")
+endif()
+
+foreach(p ${QT_CONFIG_COMPILE_TEST_PACKAGES})
+ find_package(${p})
+endforeach()
+
+if(QT_CONFIG_COMPILE_TEST_LIBRARIES)
+ link_libraries(${QT_CONFIG_COMPILE_TEST_LIBRARIES})
+endif()
+if(QT_CONFIG_COMPILE_TEST_LIBRARY_TARGETS)
+ foreach(lib ${QT_CONFIG_COMPILE_TEST_LIBRARY_TARGETS})
+ if(TARGET ${lib})
+ link_libraries(${lib})
+ endif()
+ endforeach()
+endif()
+
+add_executable(${PROJECT_NAME}
+ main.cpp
+)
+target_compile_options(${PROJECT_NAME} PRIVATE
+ -fpermissive
+)
diff --git a/config.tests/bluez/bluez.pro b/config.tests/bluez/bluez.pro
deleted file mode 100644
index 8bbff78a..00000000
--- a/config.tests/bluez/bluez.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-SOURCES += main.cpp
-
-# test checks existence of certain bluez defines whose
-# usage is known to violate the permissive test
-QMAKE_CXXFLAGS += -fpermissive
diff --git a/config.tests/bluez/main.cpp b/config.tests/bluez/main.cpp
index 63d7f8eb..f9da8ec9 100644
--- a/config.tests/bluez/main.cpp
+++ b/config.tests/bluez/main.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtConnectivity module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: BSD-3-Clause
#include <bluetooth/bluetooth.h>
diff --git a/config.tests/bluez_le/CMakeLists.txt b/config.tests/bluez_le/CMakeLists.txt
new file mode 100644
index 00000000..87536de4
--- /dev/null
+++ b/config.tests/bluez_le/CMakeLists.txt
@@ -0,0 +1,31 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(config_test_bluez_le LANGUAGES C CXX)
+
+if(DEFINED QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_PREFIX_PATH)
+ set(CMAKE_SYSTEM_PREFIX_PATH "${QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_PREFIX_PATH}")
+endif()
+if(DEFINED QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_FRAMEWORK_PATH)
+ set(CMAKE_SYSTEM_FRAMEWORK_PATH "${QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_FRAMEWORK_PATH}")
+endif()
+
+foreach(p ${QT_CONFIG_COMPILE_TEST_PACKAGES})
+ find_package(${p})
+endforeach()
+
+if(QT_CONFIG_COMPILE_TEST_LIBRARIES)
+ link_libraries(${QT_CONFIG_COMPILE_TEST_LIBRARIES})
+endif()
+if(QT_CONFIG_COMPILE_TEST_LIBRARY_TARGETS)
+ foreach(lib ${QT_CONFIG_COMPILE_TEST_LIBRARY_TARGETS})
+ if(TARGET ${lib})
+ link_libraries(${lib})
+ endif()
+ endforeach()
+endif()
+
+add_executable(${PROJECT_NAME}
+ main.cpp
+)
diff --git a/config.tests/bluez_le/bluez_le.pro b/config.tests/bluez_le/bluez_le.pro
deleted file mode 100644
index 28dcadcb..00000000
--- a/config.tests/bluez_le/bluez_le.pro
+++ /dev/null
@@ -1 +0,0 @@
-SOURCES += main.cpp
diff --git a/config.tests/bluez_le/main.cpp b/config.tests/bluez_le/main.cpp
index 0111afc8..a180c76b 100644
--- a/config.tests/bluez_le/main.cpp
+++ b/config.tests/bluez_le/main.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtConnectivity module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: BSD-3-Clause
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
diff --git a/config.tests/linux_crypto_api/CMakeLists.txt b/config.tests/linux_crypto_api/CMakeLists.txt
new file mode 100644
index 00000000..2ee9cca1
--- /dev/null
+++ b/config.tests/linux_crypto_api/CMakeLists.txt
@@ -0,0 +1,31 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(config_test_linux_crypto_api LANGUAGES C CXX)
+
+if(DEFINED QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_PREFIX_PATH)
+ set(CMAKE_SYSTEM_PREFIX_PATH "${QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_PREFIX_PATH}")
+endif()
+if(DEFINED QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_FRAMEWORK_PATH)
+ set(CMAKE_SYSTEM_FRAMEWORK_PATH "${QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_FRAMEWORK_PATH}")
+endif()
+
+foreach(p ${QT_CONFIG_COMPILE_TEST_PACKAGES})
+ find_package(${p})
+endforeach()
+
+if(QT_CONFIG_COMPILE_TEST_LIBRARIES)
+ link_libraries(${QT_CONFIG_COMPILE_TEST_LIBRARIES})
+endif()
+if(QT_CONFIG_COMPILE_TEST_LIBRARY_TARGETS)
+ foreach(lib ${QT_CONFIG_COMPILE_TEST_LIBRARY_TARGETS})
+ if(TARGET ${lib})
+ link_libraries(${lib})
+ endif()
+ endforeach()
+endif()
+
+add_executable(${PROJECT_NAME}
+ main.cpp
+)
diff --git a/config.tests/linux_crypto_api/linux_crypto_api.pro b/config.tests/linux_crypto_api/linux_crypto_api.pro
deleted file mode 100644
index 7dff17fa..00000000
--- a/config.tests/linux_crypto_api/linux_crypto_api.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-TEMPLATE = app
-
-TARGET = linux_crypto_api
-
-SOURCES += main.cpp
diff --git a/config.tests/linux_crypto_api/main.cpp b/config.tests/linux_crypto_api/main.cpp
index 0a392fb6..deeea051 100644
--- a/config.tests/linux_crypto_api/main.cpp
+++ b/config.tests/linux_crypto_api/main.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtConnectivity module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: BSD-3-Clause
#include <linux/if_alg.h>
#include <sys/socket.h>
diff --git a/config.tests/winrt_bt/CMakeLists.txt b/config.tests/winrt_bt/CMakeLists.txt
new file mode 100644
index 00000000..2a9034b0
--- /dev/null
+++ b/config.tests/winrt_bt/CMakeLists.txt
@@ -0,0 +1,34 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(config_test_winrt LANGUAGES C CXX)
+
+if(DEFINED QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_PREFIX_PATH)
+ set(CMAKE_SYSTEM_PREFIX_PATH "${QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_PREFIX_PATH}")
+endif()
+if(DEFINED QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_FRAMEWORK_PATH)
+ set(CMAKE_SYSTEM_FRAMEWORK_PATH "${QT_CONFIG_COMPILE_TEST_CMAKE_SYSTEM_FRAMEWORK_PATH}")
+endif()
+
+foreach(p ${QT_CONFIG_COMPILE_TEST_PACKAGES})
+ find_package(${p})
+endforeach()
+
+if(QT_CONFIG_COMPILE_TEST_LIBRARIES)
+ link_libraries(${QT_CONFIG_COMPILE_TEST_LIBRARIES})
+endif()
+if(QT_CONFIG_COMPILE_TEST_LIBRARY_TARGETS)
+ foreach(lib ${QT_CONFIG_COMPILE_TEST_LIBRARY_TARGETS})
+ if(TARGET ${lib})
+ link_libraries(${lib})
+ endif()
+ endforeach()
+endif()
+
+add_executable(${PROJECT_NAME}
+ main.cpp
+)
+target_link_libraries(${PROJECT_NAME} PUBLIC
+ runtimeobject
+)
diff --git a/config.tests/winrt_bt/main.cpp b/config.tests/winrt_bt/main.cpp
index 85c26bf7..e2e08d2e 100644
--- a/config.tests/winrt_bt/main.cpp
+++ b/config.tests/winrt_bt/main.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtConnectivity module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: BSD-3-Clause
#include <wrl.h>
#include <windows.devices.enumeration.h>
@@ -40,6 +15,7 @@ int main()
ABI::Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HString::MakeReference
(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), &deviceInformationStatics);
+ (void)Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService3>().Get();
(void)Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothDevice>().Get();
(void)Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice>().Get();
return 0;
diff --git a/config.tests/winrt_bt/winrt.pro b/config.tests/winrt_bt/winrt.pro
deleted file mode 100644
index d60fd242..00000000
--- a/config.tests/winrt_bt/winrt.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-SOURCES += main.cpp
-
-!winrt: LIBS += runtimeobject.lib
diff --git a/config.tests/winrt_btle_no_pairing/main.cpp b/config.tests/winrt_btle_no_pairing/main.cpp
deleted file mode 100644
index 665e357a..00000000
--- a/config.tests/winrt_btle_no_pairing/main.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtConnectivity module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <wrl.h>
-#include <windows.devices.bluetooth.h>
-
-#if defined(_WIN32) && defined(__INTEL_COMPILER)
-#error "Windows ICC fails to build the WinRT backend (QTBUG-68026)."
-#endif
-
-int main()
-{
- (void)Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattDeviceService3>().Get();
- return 0;
-}
diff --git a/config.tests/winrt_btle_no_pairing/winrt.pro b/config.tests/winrt_btle_no_pairing/winrt.pro
deleted file mode 100644
index d60fd242..00000000
--- a/config.tests/winrt_btle_no_pairing/winrt.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-SOURCES += main.cpp
-
-!winrt: LIBS += runtimeobject.lib
diff --git a/configure.json b/configure.json
deleted file mode 100644
index e63e6f2a..00000000
--- a/configure.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "subconfigs": [
- "src/bluetooth"
- ]
-}
diff --git a/dependencies.yaml b/dependencies.yaml
index fe122b69..45143acb 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -1,10 +1,7 @@
dependencies:
- ../qtandroidextras:
- ref: c224f69910ca54b8223cff13f641822756e50238
- required: false
../qtbase:
- ref: 63a1a30a014eb75a67c390a16faa9aeb03a4a012
+ ref: 4641945e45206508b44678011bb83da7722bad62
required: true
../qtdeclarative:
- ref: 42a977f2c0a4a978bb746a6e340eebd1df062c25
+ ref: 828b823938395d4d43f9b7a1b7f53f10a4a6b99b
required: false
diff --git a/dist/changes-5.13.2 b/dist/changes-5.13.2
new file mode 100644
index 00000000..22c4b3f5
--- /dev/null
+++ b/dist/changes-5.13.2
@@ -0,0 +1,35 @@
+Qt 5.13.2 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.13.0 through 5.13.1.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.13 series is binary compatible with the 5.12.x series.
+Applications compiled for 5.12 will continue to run with 5.13.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Qt 5.13.2 Changes *
+****************************************************************************
+
+QtBluetooth
+-----------
+
+ - [QTQAINFRA-2139] Fixed QMutex related compile error when using clang on
+ Windows.
+
+ - [QTBUG-78201] Fixed a case where an existing descriptor was not discovered
+ during the service discovery due to not being readable. This issue happened
+ on Android.
+
+ - Fixed a few minor documentation issues.
+
diff --git a/dist/changes-5.14.0 b/dist/changes-5.14.0
new file mode 100644
index 00000000..68bd528b
--- /dev/null
+++ b/dist/changes-5.14.0
@@ -0,0 +1,53 @@
+Qt 5.14 introduces many new features and improvements as well as bugfixes
+over the 5.13.x series. For more details, refer to the online documentation
+included in this distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.14 series is binary compatible with the 5.13.x series.
+Applications compiled for 5.13 will continue to run with 5.14.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Android *
+****************************************************************************
+
+ - [QTBUG-67482] Ported Bluetooth device scanning API to BluetoothLeScanner
+ API. This API will be used on Android SDK v21+.
+
+ - [QTBUG-69615] Fixed classic device discovery problems on Android. Newer
+ Android versions (9+) require Location permission for classic device
+ discovery.
+
+****************************************************************************
+* QtBluetooth *
+****************************************************************************
+
+ - Added possibility to build win32 backend which also works on Windows 7.
+
+ - Deprecated QBluetoothServiceInfo::DataComplete.
+
+ - Signficant refactoring of the Apple platform Bluetooth code to bring it
+ closer to all other code lines. Previously the macOS and iOS code was very
+ distinct which caused duplicated code lines.
+
+ - Proved the examples for HighDPI use cases.
+
+ - Added QLowEnergyController::Authorization enum value.
+
+ - [QTBUG-76615] Added the ability to support multiple manufacturer data
+ entries per QBluetoothDeviceInfo instance. This is of relevance when dealing
+ with BluetoothDeviceDiscoveryAgent::deviceUpdated() signals.
+
+ - [QTBUG77390] Reduced likelyhood of blocking the main event loop on Linux when
+ doing a device scan.
+
+ - [BlueZ] [QTBUG-63019] Added QLowEnergyController::createCentral with
+ locale device overload.
diff --git a/dist/changes-5.14.1 b/dist/changes-5.14.1
new file mode 100644
index 00000000..be79e803
--- /dev/null
+++ b/dist/changes-5.14.1
@@ -0,0 +1,25 @@
+Qt 5.14.1 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.14.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.14 series is binary compatible with the 5.13.x series.
+Applications compiled for 5.13 will continue to run with 5.14.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* QtBluetooth *
+****************************************************************************
+
+ - BlueZ-DBus:
+ * Invalidate btle service when it has disappeared
diff --git a/dist/changes-5.14.2 b/dist/changes-5.14.2
new file mode 100644
index 00000000..4b0fa8a8
--- /dev/null
+++ b/dist/changes-5.14.2
@@ -0,0 +1,49 @@
+Qt 5.14.2 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.14.0 through 5.14.1.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.14 series is binary compatible with the 5.13.x series.
+Applications compiled for 5.13 will continue to run with 5.14.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* QtBluetooth *
+****************************************************************************
+
+ - Windows:
+ * [QTBUG-80770] Fixed service state (DiscoveryRequired) when service
+ detail discovery fails.
+ * [QTBUG-81827] Avoid possible lock when calling
+ QBluetoothServer::hasPendingConnections.
+ - Android:
+ * Fixed the missing QLowEnergyService::error() signal emission if the
+ error was detected on the Java side. This probably cut 50% of all
+ errors out.
+ * Fixed runtime exception that happened when calling "stopLeScan" when
+ device's Bluetooth adapter is turned off.
+ * [QTBUG-81875] Fixed QBluetoothDeviceDiscoveryAgent with Android API 29.
+ * Fixed race condition where incoming and outgoing Low Energy requests
+ could overwrite each others payload.
+ - Linux:
+ * [QTBUG-81696] Added support for characteristic Write Without Response
+ requests when using BlueZ 5.50 or later.
+
+****************************************************************************
+* QtNFC *
+****************************************************************************
+
+ - Android:
+ * Fixed case when QNearFieldTarget::waitForRequestCompleted() did not stop
+ early (caused overly long timeout case) despite QNearFieldTarget::sendCommand()
+ having failed already.
diff --git a/dist/changes-5.15.0 b/dist/changes-5.15.0
new file mode 100644
index 00000000..2fa22be5
--- /dev/null
+++ b/dist/changes-5.15.0
@@ -0,0 +1,25 @@
+Qt 5.15 introduces many new features and improvements as well as bugfixes
+over the 5.14.x series. For more details, refer to the online documentation
+included in this distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.15 series is binary compatible with the 5.14.x series.
+Applications compiled for 5.14 will continue to run with 5.15.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* QtBluetooth *
+****************************************************************************
+
+ - On macOS, fixed missing writeNotify notifications in QBluetoothSocket.
+
+ - Fixed several deprecation warnings introduced by changes in other Qt modules.
+
diff --git a/dist/changes-5.15.1 b/dist/changes-5.15.1
new file mode 100644
index 00000000..332ee9d1
--- /dev/null
+++ b/dist/changes-5.15.1
@@ -0,0 +1,20 @@
+Qt 5.15.1 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.15.0.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.15 series is binary compatible with the 5.14.x series.
+Applications compiled for 5.14 will continue to run with 5.15.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+ - This release contains only minor code improvements.
diff --git a/dist/changes-5.15.2 b/dist/changes-5.15.2
new file mode 100644
index 00000000..904e0eab
--- /dev/null
+++ b/dist/changes-5.15.2
@@ -0,0 +1,24 @@
+Qt 5.15.2 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.15.1.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+ https://doc.qt.io/qt-5.15/index.html
+
+The Qt version 5.15 series is binary compatible with the 5.14.x series.
+Applications compiled for 5.14 will continue to run with 5.15.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+ https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Qt 5.15.2 *
+****************************************************************************
+
+This release only contains minor changes.
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
new file mode 100644
index 00000000..d009126a
--- /dev/null
+++ b/examples/CMakeLists.txt
@@ -0,0 +1,13 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+qt_examples_build_begin(EXTERNAL_BUILD)
+
+if(TARGET Qt6::Bluetooth)
+ add_subdirectory(bluetooth)
+endif()
+if(TARGET Qt6::Nfc)
+ add_subdirectory(nfc)
+endif()
+
+qt_examples_build_end()
diff --git a/examples/bluetooth/CMakeLists.txt b/examples/bluetooth/CMakeLists.txt
new file mode 100644
index 00000000..8ea6028b
--- /dev/null
+++ b/examples/bluetooth/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+qt_internal_add_example(heartrate-server)
+if(TARGET Qt6::Widgets)
+ qt_internal_add_example(btchat)
+endif()
+if(TARGET Qt6::Quick)
+ qt_internal_add_example(lowenergyscanner)
+ qt_internal_add_example(heartrate-game)
+endif()
diff --git a/examples/bluetooth/bluetooth.pro b/examples/bluetooth/bluetooth.pro
index bc18f571..7b2484da 100644
--- a/examples/bluetooth/bluetooth.pro
+++ b/examples/bluetooth/bluetooth.pro
@@ -3,14 +3,8 @@ TEMPLATE = subdirs
SUBDIRS += heartrate-server
qtHaveModule(widgets) {
- SUBDIRS += btchat \
- btscanner \
- btfiletransfer
+ SUBDIRS += btchat
}
-qtHaveModule(quick): SUBDIRS += scanner \
- picturetransfer \
- pingpong \
- lowenergyscanner \
- heartrate-game \
- chat
+qtHaveModule(quick): SUBDIRS += lowenergyscanner \
+ heartrate-game
diff --git a/examples/bluetooth/btchat/CMakeLists.txt b/examples/bluetooth/btchat/CMakeLists.txt
new file mode 100644
index 00000000..667dc194
--- /dev/null
+++ b/examples/bluetooth/btchat/CMakeLists.txt
@@ -0,0 +1,66 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(btchat LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/bluetooth/btchat")
+
+find_package(Qt6 REQUIRED COMPONENTS Bluetooth Core Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(btchat
+ chat.cpp chat.h chat.ui
+ chatclient.cpp chatclient.h
+ chatserver.cpp chatserver.h
+ main.cpp
+ remoteselector.cpp remoteselector.h remoteselector.ui
+)
+
+set(icon_files)
+foreach(icon IN ITEMS bluetooth bluetooth_dark send send_dark)
+ foreach(scale IN ITEMS "" "@2" "@3" "@4")
+ list(APPEND icon_files "icons/btchat/24x24${scale}/${icon}.png")
+ endforeach()
+endforeach()
+
+qt_add_resources(btchat "theme" FILES
+ ${icon_files}
+ icons/btchat/index.theme
+)
+
+set_target_properties(btchat PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(btchat PRIVATE
+ Qt6::Bluetooth
+ Qt6::Core
+ Qt6::Widgets
+)
+
+if (APPLE)
+ # Using absolute path for shared plist files is a Ninja bug workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../shared ABSOLUTE)
+ if (IOS)
+ set_target_properties(btchat PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.cmake.ios.plist"
+ )
+ else()
+ set_target_properties(btchat PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.cmake.macos.plist"
+ )
+ endif()
+endif()
+
+install(TARGETS btchat
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/bluetooth/btchat/btchat.pro b/examples/bluetooth/btchat/btchat.pro
index 9c37dfcf..0d7b5f77 100644
--- a/examples/bluetooth/btchat/btchat.pro
+++ b/examples/bluetooth/btchat/btchat.pro
@@ -3,7 +3,6 @@ TARGET = btchat
QT = core bluetooth widgets
requires(qtConfig(listwidget))
-android: QT += androidextras
SOURCES = \
main.cpp \
@@ -22,5 +21,31 @@ FORMS = \
chat.ui \
remoteselector.ui
+theme_resources.files = \
+ icons/btchat/24x24/bluetooth.png \
+ icons/btchat/24x24/bluetooth_dark.png \
+ icons/btchat/24x24/send.png \
+ icons/btchat/24x24/send_dark.png \
+ icons/btchat/24x24@2/bluetooth.png \
+ icons/btchat/24x24@2/bluetooth_dark.png \
+ icons/btchat/24x24@2/send.png \
+ icons/btchat/24x24@2/send_dark.png \
+ icons/btchat/24x24@3/bluetooth.png \
+ icons/btchat/24x24@3/bluetooth_dark.png \
+ icons/btchat/24x24@3/send.png \
+ icons/btchat/24x24@3/send_dark.png \
+ icons/btchat/24x24@4/bluetooth.png \
+ icons/btchat/24x24@4/bluetooth_dark.png \
+ icons/btchat/24x24@4/send.png \
+ icons/btchat/24x24@4/send_dark.png \
+ icons/btchat/index.theme
+
+theme_resources.prefix = /
+
+RESOURCES += theme_resources
+
+ios: QMAKE_INFO_PLIST = ../shared/Info.qmake.ios.plist
+macos: QMAKE_INFO_PLIST = ../shared/Info.qmake.macos.plist
+
target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/btchat
INSTALLS += target
diff --git a/examples/bluetooth/btchat/chat.cpp b/examples/bluetooth/btchat/chat.cpp
index 4cc5f08d..bf794902 100644
--- a/examples/bluetooth/btchat/chat.cpp
+++ b/examples/bluetooth/btchat/chat.cpp
@@ -1,86 +1,81 @@
-/****************************************************************************
-**
-** 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: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 "chat.h"
-#include "remoteselector.h"
-#include "chatserver.h"
#include "chatclient.h"
+#include "chatserver.h"
+#include "remoteselector.h"
+#include "ui_chat.h"
-#include <QtCore/qdebug.h>
+#include <QDebug>
-#include <QtBluetooth/qbluetoothdeviceinfo.h>
-#include <QtBluetooth/qbluetoothlocaldevice.h>
-#include <QtBluetooth/qbluetoothuuid.h>
+#include <QBluetoothDeviceInfo>
+#include <QBluetoothLocalDevice>
+#include <QBluetoothUuid>
-#ifdef Q_OS_ANDROID
-#include <QtAndroidExtras/QtAndroid>
+#include <QGuiApplication>
+#include <QStyleHints>
+
+#if QT_CONFIG(permissions)
+#include <QCoreApplication>
+#include <QPermissions>
+
+#include <QMessageBox>
#endif
-static const QLatin1String serviceUuid("e8e10f95-1a70-4b27-9ccf-02010264e9c8");
+using namespace Qt::StringLiterals;
+
+static constexpr auto serviceUuid = "e8e10f95-1a70-4b27-9ccf-02010264e9c8"_L1;
#ifdef Q_OS_ANDROID
-static const QLatin1String reverseUuid("c8e96402-0102-cf9c-274b-701a950fe1e8");
+static constexpr auto reverseUuid = "c8e96402-0102-cf9c-274b-701a950fe1e8"_L1;
#endif
Chat::Chat(QWidget *parent)
- : QDialog(parent), ui(new Ui_Chat)
+ : QDialog(parent), ui(new Ui::Chat)
{
//! [Construct UI]
ui->setupUi(this);
- connect(ui->quitButton, &QPushButton::clicked, this, &Chat::accept);
connect(ui->connectButton, &QPushButton::clicked, this, &Chat::connectClicked);
connect(ui->sendButton, &QPushButton::clicked, this, &Chat::sendClicked);
//! [Construct UI]
+ ui->connectButton->setFocus();
+
+ QStyleHints *styleHints = qGuiApp->styleHints();
+ updateIcons(styleHints->colorScheme());
+ connect(styleHints, &QStyleHints::colorSchemeChanged, this, &Chat::updateIcons);
+
+ initBluetooth();
+}
+
+Chat::~Chat()
+{
+ qDeleteAll(clients);
+ delete ui;
+}
+
+void Chat::initBluetooth()
+{
+#if QT_CONFIG(permissions)
+ QBluetoothPermission permission{};
+ switch (qApp->checkPermission(permission)) {
+ case Qt::PermissionStatus::Undetermined:
+ qApp->requestPermission(permission, this, &Chat::initBluetooth);
+ return;
+ case Qt::PermissionStatus::Denied:
+ QMessageBox::warning(this, tr("Missing permissions"),
+ tr("Permissions are needed to use Bluetooth. "
+ "Please grant the permissions to this "
+ "application in the system settings."));
+ qApp->quit();
+ return;
+ case Qt::PermissionStatus::Granted:
+ break; // proceed to initialization
+ }
+#endif // QT_CONFIG(permissions)
localAdapters = QBluetoothLocalDevice::allDevices();
- if (localAdapters.count() < 2) {
+ if (localAdapters.size() < 2) {
ui->localAdapterBox->setVisible(false);
} else {
//we ignore more than two adapters
@@ -91,8 +86,14 @@ Chat::Chat(QWidget *parent)
ui->firstAdapter->setChecked(true);
connect(ui->firstAdapter, &QRadioButton::clicked, this, &Chat::newAdapterSelected);
connect(ui->secondAdapter, &QRadioButton::clicked, this, &Chat::newAdapterSelected);
+ }
+
+ // make discoverable
+ if (!localAdapters.isEmpty()) {
QBluetoothLocalDevice adapter(localAdapters.at(0).address());
adapter.setHostMode(QBluetoothLocalDevice::HostDiscoverable);
+ } else {
+ qWarning("Local adapter is not found! The application might work incorrectly.");
}
//! [Create Chat Server]
@@ -112,10 +113,13 @@ Chat::Chat(QWidget *parent)
//! [Get local device name]
}
-Chat::~Chat()
+void Chat::updateIcons(Qt::ColorScheme scheme)
{
- qDeleteAll(clients);
- delete server;
+ const QString bluetoothIconName = (scheme == Qt::ColorScheme::Dark) ? u"bluetooth_dark"_s
+ : u"bluetooth"_s;
+ const QString sendIconName = (scheme == Qt::ColorScheme::Dark) ? u"send_dark"_s : u"send"_s;
+ ui->sendButton->setIcon(QIcon::fromTheme(sendIconName));
+ ui->connectButton->setIcon(QIcon::fromTheme(bluetoothIconName));
}
//! [clientConnected clientDisconnected]
@@ -165,7 +169,7 @@ int Chat::adapterFromUserSelection() const
void Chat::reactOnSocketError(const QString &error)
{
- ui->chat->insertPlainText(error);
+ ui->chat->insertPlainText(QString::fromLatin1("%1\n").arg(error));
}
//! [clientDisconnected]
@@ -191,23 +195,20 @@ void Chat::connectClicked()
RemoteSelector remoteSelector(adapter);
#ifdef Q_OS_ANDROID
- if (QtAndroid::androidSdkVersion() >= 23)
- remoteSelector.startDiscovery(QBluetoothUuid(reverseUuid));
- else
- remoteSelector.startDiscovery(QBluetoothUuid(serviceUuid));
+ // QTBUG-61392
+ Q_UNUSED(serviceUuid);
+ remoteSelector.startDiscovery(QBluetoothUuid(reverseUuid));
#else
remoteSelector.startDiscovery(QBluetoothUuid(serviceUuid));
#endif
if (remoteSelector.exec() == QDialog::Accepted) {
QBluetoothServiceInfo service = remoteSelector.service();
- qDebug() << "Connecting to service 2" << service.serviceName()
+ qDebug() << "Connecting to service" << service.serviceName()
<< "on" << service.device().name();
// Create client
- qDebug() << "Going to create client";
ChatClient *client = new ChatClient(this);
-qDebug() << "Connecting...";
connect(client, &ChatClient::messageReceived,
this, &Chat::showMessage);
@@ -218,7 +219,6 @@ qDebug() << "Connecting...";
connect(client, &ChatClient::socketErrorOccurred,
this, &Chat::reactOnSocketError);
connect(this, &Chat::sendMessage, client, &ChatClient::sendMessage);
-qDebug() << "Start client";
client->startClient(service);
clients.append(client);
@@ -241,12 +241,19 @@ void Chat::sendClicked()
ui->sendText->setEnabled(true);
ui->sendButton->setEnabled(true);
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
+ // avoid keyboard automatically popping up again on mobile devices
+ ui->sendButton->setFocus();
+#else
+ ui->sendText->setFocus();
+#endif
}
//! [sendClicked]
//! [showMessage]
void Chat::showMessage(const QString &sender, const QString &message)
{
+ ui->chat->moveCursor(QTextCursor::End);
ui->chat->insertPlainText(QString::fromLatin1("%1: %2\n").arg(sender, message));
ui->chat->ensureCursorVisible();
}
diff --git a/examples/bluetooth/btchat/chat.h b/examples/bluetooth/btchat/chat.h
index e4c81b24..ca5318cc 100644
--- a/examples/bluetooth/btchat/chat.h
+++ b/examples/bluetooth/btchat/chat.h
@@ -1,60 +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: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$
-**
-****************************************************************************/
-
-#include "ui_chat.h"
-
-#include <QtWidgets/qdialog.h>
-
-#include <QtBluetooth/qbluetoothhostinfo.h>
-
-QT_USE_NAMESPACE
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QDialog>
+
+#include <QBluetoothHostInfo>
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+ class Chat;
+}
+QT_END_NAMESPACE
class ChatServer;
class ChatClient;
@@ -85,12 +40,16 @@ private slots:
void newAdapterSelected();
+ void initBluetooth();
+
+ void updateIcons(Qt::ColorScheme scheme);
+
private:
int adapterFromUserSelection() const;
int currentAdapterIndex = 0;
- Ui_Chat *ui;
+ Ui::Chat *ui;
- ChatServer *server;
+ ChatServer *server = nullptr;
QList<ChatClient *> clients;
QList<QBluetoothHostInfo> localAdapters;
diff --git a/examples/bluetooth/btchat/chat.ui b/examples/bluetooth/btchat/chat.ui
index d7829294..bea3d2ee 100644
--- a/examples/bluetooth/btchat/chat.ui
+++ b/examples/bluetooth/btchat/chat.ui
@@ -50,12 +50,16 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
- <widget class="QLineEdit" name="sendText"/>
+ <widget class="QLineEdit" name="sendText">
+ <property name="placeholderText">
+ <string>Enter message</string>
+ </property>
+ </widget>
</item>
<item>
<widget class="QPushButton" name="sendButton">
<property name="text">
- <string>Send</string>
+ <string/>
</property>
<property name="default">
<bool>true</bool>
@@ -84,17 +88,26 @@
<property name="text">
<string>Connect</string>
</property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
</widget>
</item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</item>
- <item>
- <widget class="QPushButton" name="quitButton">
- <property name="text">
- <string>Quit</string>
- </property>
- </widget>
- </item>
</layout>
</widget>
<resources/>
diff --git a/examples/bluetooth/btchat/chatclient.cpp b/examples/bluetooth/btchat/chatclient.cpp
index cf3e2331..18e100a2 100644
--- a/examples/bluetooth/btchat/chatclient.cpp
+++ b/examples/bluetooth/btchat/chatclient.cpp
@@ -1,56 +1,14 @@
-/****************************************************************************
-**
-** 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: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 "chatclient.h"
-#include <QtCore/qmetaobject.h>
+#include <QMetaEnum>
+#include <QMetaObject>
+
+#include <QBluetoothServiceInfo>
+
+using namespace Qt::StringLiterals;
ChatClient::ChatClient(QObject *parent)
: QObject(parent)
@@ -77,9 +35,7 @@ void ChatClient::startClient(const QBluetoothServiceInfo &remoteService)
connect(socket, &QBluetoothSocket::readyRead, this, &ChatClient::readSocket);
connect(socket, &QBluetoothSocket::connected, this, QOverload<>::of(&ChatClient::connected));
connect(socket, &QBluetoothSocket::disconnected, this, &ChatClient::disconnected);
- connect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error),
- this, &ChatClient::onSocketErrorOccurred);
-
+ connect(socket, &QBluetoothSocket::errorOccurred, this, &ChatClient::onSocketErrorOccurred);
}
//! [startClient]
@@ -98,7 +54,7 @@ void ChatClient::readSocket()
return;
while (socket->canReadLine()) {
- QByteArray line = socket->readLine();
+ QByteArray line = socket->readLine().trimmed();
emit messageReceived(socket->peerName(),
QString::fromUtf8(line.constData(), line.length()));
}
@@ -115,12 +71,12 @@ void ChatClient::sendMessage(const QString &message)
void ChatClient::onSocketErrorOccurred(QBluetoothSocket::SocketError error)
{
- if (error == QBluetoothSocket::NoSocketError)
+ if (error == QBluetoothSocket::SocketError::NoSocketError)
return;
QMetaEnum metaEnum = QMetaEnum::fromType<QBluetoothSocket::SocketError>();
- QString errorString = socket->peerName() + QLatin1Char(' ')
- + metaEnum.valueToKey(error) + QLatin1String(" occurred");
+ QString errorString = socket->peerName() + ' '_L1
+ + metaEnum.valueToKey(static_cast<int>(error)) + " occurred"_L1;
emit socketErrorOccurred(errorString);
}
diff --git a/examples/bluetooth/btchat/chatclient.h b/examples/bluetooth/btchat/chatclient.h
index 25002f90..da75bf51 100644
--- a/examples/bluetooth/btchat/chatclient.h
+++ b/examples/bluetooth/btchat/chatclient.h
@@ -1,64 +1,14 @@
-/****************************************************************************
-**
-** 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: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
#ifndef CHATCLIENT_H
#define CHATCLIENT_H
-#include <QtCore/qobject.h>
+#include <QObject>
-#include <QtBluetooth/qbluetoothserviceinfo.h>
-#include <QtBluetooth/qbluetoothsocket.h>
+#include <QBluetoothSocket>
-QT_FORWARD_DECLARE_CLASS(QBluetoothSocket)
-
-QT_USE_NAMESPACE
+QT_FORWARD_DECLARE_CLASS(QBluetoothServiceInfo)
//! [declaration]
class ChatClient : public QObject
diff --git a/examples/bluetooth/btchat/chatserver.cpp b/examples/bluetooth/btchat/chatserver.cpp
index d078a32c..addbc1a9 100644
--- a/examples/bluetooth/btchat/chatserver.cpp
+++ b/examples/bluetooth/btchat/chatserver.cpp
@@ -1,60 +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: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 "chatserver.h"
-#include <QtBluetooth/qbluetoothserver.h>
-#include <QtBluetooth/qbluetoothsocket.h>
+#include <QBluetoothServer>
+#include <QBluetoothSocket>
+
+using namespace Qt::StringLiterals;
//! [Service UUID]
-static const QLatin1String serviceUuid("e8e10f95-1a70-4b27-9ccf-02010264e9c8");
+static constexpr auto serviceUuid = "e8e10f95-1a70-4b27-9ccf-02010264e9c8"_L1;
//! [Service UUID]
ChatServer::ChatServer(QObject *parent)
@@ -87,7 +42,7 @@ void ChatServer::startServer(const QBluetoothAddress& localAdapter)
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,
@@ -95,7 +50,7 @@ void ChatServer::startServer(const QBluetoothAddress& localAdapter)
classId.clear();
classId << QVariant::fromValue(QBluetoothUuid(serviceUuid));
- classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
+ classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
@@ -111,19 +66,19 @@ void ChatServer::startServer(const QBluetoothAddress& localAdapter)
//! [Service UUID set]
//! [Service Discoverability]
+ const auto groupUuid = QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup);
QBluetoothServiceInfo::Sequence publicBrowse;
- publicBrowse << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup));
- serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList,
- publicBrowse);
+ publicBrowse << QVariant::fromValue(groupUuid);
+ serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, publicBrowse);
//! [Service Discoverability]
//! [Protocol descriptor list]
QBluetoothServiceInfo::Sequence protocolDescriptorList;
QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::L2cap));
protocolDescriptorList.append(QVariant::fromValue(protocol));
protocol.clear();
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm))
<< QVariant::fromValue(quint8(rfcommServer->serverPort()));
protocolDescriptorList.append(QVariant::fromValue(protocol));
serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList,
@@ -143,6 +98,7 @@ void ChatServer::stopServer()
// Close sockets
qDeleteAll(clientSockets);
+ clientNames.clear();
// Close server
delete rfcommServer;
@@ -155,7 +111,7 @@ void ChatServer::sendMessage(const QString &message)
{
QByteArray text = message.toUtf8() + '\n';
- for (QBluetoothSocket *socket : qAsConst(clientSockets))
+ for (QBluetoothSocket *socket : std::as_const(clientSockets))
socket->write(text);
}
//! [sendMessage]
@@ -168,8 +124,10 @@ void ChatServer::clientConnected()
return;
connect(socket, &QBluetoothSocket::readyRead, this, &ChatServer::readSocket);
- connect(socket, &QBluetoothSocket::disconnected, this, QOverload<>::of(&ChatServer::clientDisconnected));
+ connect(socket, &QBluetoothSocket::disconnected,
+ this, QOverload<>::of(&ChatServer::clientDisconnected));
clientSockets.append(socket);
+ clientNames[socket] = socket->peerName();
emit clientConnected(socket->peerName());
}
//! [clientConnected]
@@ -181,9 +139,10 @@ void ChatServer::clientDisconnected()
if (!socket)
return;
- emit clientDisconnected(socket->peerName());
+ emit clientDisconnected(clientNames[socket]);
clientSockets.removeOne(socket);
+ clientNames.remove(socket);
socket->deleteLater();
}
@@ -198,7 +157,7 @@ void ChatServer::readSocket()
while (socket->canReadLine()) {
QByteArray line = socket->readLine().trimmed();
- emit messageReceived(socket->peerName(),
+ emit messageReceived(clientNames[socket],
QString::fromUtf8(line.constData(), line.length()));
}
}
diff --git a/examples/bluetooth/btchat/chatserver.h b/examples/bluetooth/btchat/chatserver.h
index c4191db8..ab60cad6 100644
--- a/examples/bluetooth/btchat/chatserver.h
+++ b/examples/bluetooth/btchat/chatserver.h
@@ -1,66 +1,17 @@
-/****************************************************************************
-**
-** 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: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
#ifndef CHATSERVER_H
#define CHATSERVER_H
-#include <QtCore/qobject.h>
+#include <QObject>
-#include <QtBluetooth/qbluetoothaddress.h>
-#include <QtBluetooth/qbluetoothserviceinfo.h>
+#include <QBluetoothAddress>
+#include <QBluetoothServiceInfo>
QT_FORWARD_DECLARE_CLASS(QBluetoothServer)
QT_FORWARD_DECLARE_CLASS(QBluetoothSocket)
-QT_USE_NAMESPACE
-
//! [declaration]
class ChatServer : public QObject
{
@@ -90,6 +41,7 @@ private:
QBluetoothServer *rfcommServer = nullptr;
QBluetoothServiceInfo serviceInfo;
QList<QBluetoothSocket *> clientSockets;
+ QMap<QBluetoothSocket *, QString> clientNames;
};
//! [declaration]
diff --git a/examples/bluetooth/btchat/doc/images/btchat-example.png b/examples/bluetooth/btchat/doc/images/btchat-example.png
index 762d49cb..acfadf5c 100644
--- a/examples/bluetooth/btchat/doc/images/btchat-example.png
+++ b/examples/bluetooth/btchat/doc/images/btchat-example.png
Binary files differ
diff --git a/examples/bluetooth/btchat/doc/src/btchat.qdoc b/examples/bluetooth/btchat/doc/src/btchat.qdoc
index 42a82bc6..5ad11502 100644
--- a/examples/bluetooth/btchat/doc/src/btchat.qdoc
+++ b/examples/bluetooth/btchat/doc/src/btchat.qdoc
@@ -1,37 +1,14 @@
-/****************************************************************************
-**
-** 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
/*!
\example btchat
- \title Bluetooth Chat Example
- \brief An example showing communication through Bluetooth.
+ \title Bluetooth Chat
+ \examplecategory {Connectivity}
+ \brief Shows communication through Bluetooth using RFCOMM protocol.
The Bluetooth Chat example shows how to use the \l{Qt Bluetooth} API to communicate
- with another application on a remote device using Bluetooth.
+ with another application on a remote device using Bluetooth RFCOMM protocol.
\image btchat-example.png
@@ -43,26 +20,28 @@
\section1 Chat Server
- The chat server is implemented by the ChatServer class. The ChatServer class is declared as:
+ The chat server is implemented by the \c ChatServer class.
+ The \c ChatServer class is declared as:
\snippet btchat/chatserver.h declaration
- The first thing the chat server needs to do is create an instance of QRfcommServer to listen
- for incoming Bluetooth connections. Our clientConnected() slot will be called whenever a new
- connection is created.
+ The first thing the chat server needs to do is create an instance of
+ QBluetoothServer to listen for incoming Bluetooth connections. The
+ \c {clientConnected()} slot will be called whenever a new connection is
+ created.
\snippet btchat/chatserver.cpp Create the server
The chat server is only useful if others know that it is there. To enable other devices to
- discover it, a record describing the service needs to be published in the systems SDP (Service
+ discover it, a record describing the service needs to be published in the system's SDP (Service
Discovery Protocol) database. The QBluetoothServiceInfo class encapsulates a service record.
- We will publish a service record that contains some textural descriptions of the services, a
+ We will publish a service record that contains some textual descriptions of the services, a
UUID that uniquely identifies the service, the discoverability attribute, and connection
parameters.
- The textural description of the service is stored in the ServiceName, ServiceDescription, and
- ServiceProvider attributes.
+ The textual description of the service is stored in the \c {ServiceName},
+ \c {ServiceDescription}, and \c {ServiceProvider} attributes.
\snippet btchat/chatserver.cpp Service name, description and provider
@@ -72,13 +51,14 @@
\snippet btchat/chatserver.cpp Service UUID
\snippet btchat/chatserver.cpp Service UUID set
- A Bluetooth service is only discoverable if it is in the PublicBrowseGroup.
+ A Bluetooth service is only discoverable if it is in the
+ \l {QBluetoothUuid::}{PublicBrowseGroup}.
\snippet btchat/chatserver.cpp Service Discoverability
- The ProtocolDescriptorList attribute is used to publish the connection parameters that the
- remote device requires to connect to our service. Here we specify that the Rfcomm protocol is
- used and set the port number to the port that our rfcommServer instance is listening to.
+ The \c ProtocolDescriptorList attribute is used to publish the connection parameters that the
+ remote device requires to connect to our service. Here we specify that the \c Rfcomm protocol
+ is used and set the port number to the port that our \c rfcommServer instance is listening to.
\snippet btchat/chatserver.cpp Protocol descriptor list
@@ -86,58 +66,92 @@
\snippet btchat/chatserver.cpp Register service
-
- As mentioned earlier, incoming connections are handled in the clientConnected() slot where
- pending connections are connected to the readyRead() and disconnected() signals. The signals
- notify others that a new client has connected.
+ As mentioned earlier, incoming connections are handled in the
+ \c {clientConnected()} slot where pending connections are connected to the
+ \l {QBluetoothSocket::}{readyRead()} and
+ \l {QBluetoothSocket::}{disconnected()} signals. The signals notify others
+ that a new client has connected.
\snippet btchat/chatserver.cpp clientConnected
- The readSocket() slot is called whenever data is ready to be read from a client socket. The
- slot reads individual lines from the socket, converts them from UTF-8, and emits the
- messageReceived() signal.
+ The \c {readSocket()} slot is called whenever data is ready to be read from
+ a client socket. The slot reads individual lines from the socket, converts
+ them from UTF-8, and emits the \c {messageReceived()} signal.
\snippet btchat/chatserver.cpp readSocket
- The clientDisconnected() slot is called whenever a client disconnects from the service. The
- slot emits a signal to notify others that a client has disconnected, and deletes the socket.
+ The \c {clientDisconnected()} slot is called whenever a client disconnects
+ from the service. The slot emits a signal to notify others that a client
+ has disconnected, and deletes the socket.
\snippet btchat/chatserver.cpp clientDisconnected
- The sendMessage() slot is used to send a message to all connected clients. The message is
+ The \c {sendMessage()} slot is used to send a message to all connected clients. The message is
converted into UTF-8 and appended with a newline before being sent to all clients.
\snippet btchat/chatserver.cpp sendMessage
- When the chat server is stopped the service record is removed from the system SDP database, all
- connected client sockets are deleted, and the QRfcommServer instance is deleted.
+ When the chat server is stopped, the service record is removed from the
+ system SDP database, all connected client sockets are deleted, and the
+ \c rfcommServer instance is deleted.
\snippet btchat/chatserver.cpp stopServer
+ \section1 Service Discovery
+
+ Before connecting to the server, the client needs to scan the nearby
+ devices and search for the device that is advertising the chat service.
+ This is done by the \c RemoteSelector class.
+
+ To start service lookup, the \c RemoteSelector creates an instance of
+ \l QBluetoothServiceDiscoveryAgent and connects to its signals.
+
+ \snippet btchat/remoteselector.cpp createDiscoveryAgent
+
+ An UUID filter is set, so that the service discovery only shows the devices
+ that advertise the needed service. After that a
+ \l {QBluetoothServiceDiscoveryAgent::}{FullDiscovery} is started:
+
+ \snippet btchat/remoteselector.cpp startDiscovery
+
+ When a matching service is discovered, a
+ \l {QBluetoothServiceDiscoveryAgent::}{serviceDiscovered()} signal is
+ emitted with an instance of \l QBluetoothServiceInfo as a parameter. This
+ service info is used to extract the device name and the service name,
+ and add a new entry to the list of discovered remote devices:
+
+ \snippet btchat/remoteselector.cpp serviceDiscovered
+
+ Later the user can select one of the devices from the list and try to
+ connect to it.
+
\section1 Chat Client
- The chat client is implemented by the ChatClient class. The ChatClient class is declared as:
+ The chat client is implemented by the \c ChatClient class.
+ The \c ChatClient class is declared as:
\snippet btchat/chatclient.h declaration
- The client creates a new QBluetoothSocket and connects to the remote service described by the
- \e remoteService parameter. Slots are connected to the sockets readyRead(), connected() and
- disconnected() signals.
+ The client creates a new QBluetoothSocket and connects to the remote
+ service described by the \c remoteService parameter. Slots are connected
+ to the socket's \l {QBluetoothSocket::}{readyRead()},
+ \l {QBluetoothSocket::}{connected()}, and
+ \l {QBluetoothSocket::}{disconnected()} signals.
\snippet btchat/chatclient.cpp startClient
- On successful socket connection we emit a signal to notify others.
+ On successful socket connection we emit a signal to notify other users.
\snippet btchat/chatclient.cpp connected
- Similarly to the chat server, the readSocket() slot is called when data is available from the
- socket. Lines are read individually and converted from UTF-8. The messageReceived() signal
- is emitted.
+ Similarly to the chat server, the \c readSocket() slot is called when data
+ is available from the socket. Lines are read individually and converted
+ from UTF-8. The \c {messageReceived()} signal is emitted.
\snippet btchat/chatclient.cpp readSocket
- The sendMessage() slot is used to send a message to the remote device. The message is
- converted to UTF-8 and a newline is appended.
+ The \c {sendMessage()} slot is used to send a message to the remote device.
+ The message is converted to UTF-8 and a newline is appended.
\snippet btchat/chatclient.cpp sendMessage
@@ -147,9 +161,10 @@
\section1 Chat Dialog
- The main window of this example is the chat dialog, implemented in the Chat class. This class
- displays a chat session between a single ChatServer and zero or more ChatClients. The Chat
- class is declared as:
+ The main window of this example is the chat dialog, implemented in the
+ \c Chat class. This class displays a chat session between a single
+ \c ChatServer and zero or more \c {ChatClient}s. The \c Chat class is
+ declared as:
\snippet btchat/chat.h declaration
@@ -157,38 +172,42 @@
\snippet btchat/chat.cpp Construct UI
- We create an instance of the ChatServer and respond to its clientConnected(),
- clientDiconnected(), and messageReceived() signals.
+ We create an instance of the \c ChatServer and respond to its
+ \c {clientConnected()}, \c {clientDiconnected()}, and
+ \c {messageReceived()} signals.
\snippet btchat/chat.cpp Create Chat Server
- In response to the clientConnected() and clientDisconnected() signals of the ChatServer, we
- display the typical "X has joined chat." and "Y has left." messages in the chat session.
+ In response to the \c {clientConnected()} and \c {clientDisconnected()}
+ signals of the \c ChatServer, we display the typical "X has joined chat."
+ and "Y has left." messages in the chat session.
\snippet btchat/chat.cpp clientConnected clientDisconnected
- Incoming messages from clients connected to the ChatServer are handled in the showMessage()
- slot. The message text tagged with the remote device name is displayed in the chat session.
+ Incoming messages from clients connected to the \c ChatServer are handled
+ in the \c {showMessage()} slot. The message text tagged with the remote
+ device name is displayed in the chat session.
\snippet btchat/chat.cpp showMessage
In response to the connect button being clicked, the application starts service discovery and
- presents a list of discovered chat services on remote devices. A ChatClient for the service
+ presents a list of discovered chat services on remote devices. A \c ChatClient for the service
is selected by the user.
\snippet btchat/chat.cpp Connect to remote service
- In reponse to the connected() signals from ChatClient, we display the a "Joined chat with X."
- message in the chat session.
+ In reponse to the \c {connected()} signals from \c ChatClient, we display
+ the "Joined chat with X." message in the chat session.
\snippet btchat/chat.cpp connected
- Messages are sent to all remote devices via the ChatServer and ChatClient instances by emitting
- the sendMessage() signal.
+ Messages are sent to all remote devices via the \c ChatServer and
+ \c ChatClient instances by emitting the \c {sendMessage()} signal.
\snippet btchat/chat.cpp sendClicked
- We need to clean up ChatClient instances when the remote device forces a disconnect.
+ We need to clean up \c ChatClient instances when the remote device forces
+ a disconnect.
\snippet btchat/chat.cpp clientDisconnected
*/
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24/bluetooth.png b/examples/bluetooth/btchat/icons/btchat/24x24/bluetooth.png
new file mode 100644
index 00000000..832dd042
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24/bluetooth.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24/bluetooth_dark.png b/examples/bluetooth/btchat/icons/btchat/24x24/bluetooth_dark.png
new file mode 100644
index 00000000..48b772d0
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24/bluetooth_dark.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24/send.png b/examples/bluetooth/btchat/icons/btchat/24x24/send.png
new file mode 100644
index 00000000..dfce248a
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24/send.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24/send_dark.png b/examples/bluetooth/btchat/icons/btchat/24x24/send_dark.png
new file mode 100644
index 00000000..66e78daf
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24/send_dark.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24@2/bluetooth.png b/examples/bluetooth/btchat/icons/btchat/24x24@2/bluetooth.png
new file mode 100644
index 00000000..12bbb81d
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24@2/bluetooth.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24@2/bluetooth_dark.png b/examples/bluetooth/btchat/icons/btchat/24x24@2/bluetooth_dark.png
new file mode 100644
index 00000000..f3456e6f
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24@2/bluetooth_dark.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24@2/send.png b/examples/bluetooth/btchat/icons/btchat/24x24@2/send.png
new file mode 100644
index 00000000..8c4d5d0e
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24@2/send.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24@2/send_dark.png b/examples/bluetooth/btchat/icons/btchat/24x24@2/send_dark.png
new file mode 100644
index 00000000..03b597c3
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24@2/send_dark.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24@3/bluetooth.png b/examples/bluetooth/btchat/icons/btchat/24x24@3/bluetooth.png
new file mode 100644
index 00000000..235b91aa
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24@3/bluetooth.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24@3/bluetooth_dark.png b/examples/bluetooth/btchat/icons/btchat/24x24@3/bluetooth_dark.png
new file mode 100644
index 00000000..c64aa4a9
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24@3/bluetooth_dark.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24@3/send.png b/examples/bluetooth/btchat/icons/btchat/24x24@3/send.png
new file mode 100644
index 00000000..3d15b197
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24@3/send.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24@3/send_dark.png b/examples/bluetooth/btchat/icons/btchat/24x24@3/send_dark.png
new file mode 100644
index 00000000..7f1a9f4d
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24@3/send_dark.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24@4/bluetooth.png b/examples/bluetooth/btchat/icons/btchat/24x24@4/bluetooth.png
new file mode 100644
index 00000000..bad3e2ea
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24@4/bluetooth.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24@4/bluetooth_dark.png b/examples/bluetooth/btchat/icons/btchat/24x24@4/bluetooth_dark.png
new file mode 100644
index 00000000..01f420b0
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24@4/bluetooth_dark.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24@4/send.png b/examples/bluetooth/btchat/icons/btchat/24x24@4/send.png
new file mode 100644
index 00000000..c931f7a0
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24@4/send.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/24x24@4/send_dark.png b/examples/bluetooth/btchat/icons/btchat/24x24@4/send_dark.png
new file mode 100644
index 00000000..8b801207
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/24x24@4/send_dark.png
Binary files differ
diff --git a/examples/bluetooth/btchat/icons/btchat/index.theme b/examples/bluetooth/btchat/icons/btchat/index.theme
new file mode 100644
index 00000000..3209f84f
--- /dev/null
+++ b/examples/bluetooth/btchat/icons/btchat/index.theme
@@ -0,0 +1,22 @@
+[Icon Theme]
+Name=btchat
+Directories=24x24,24x24@2,24x24@3,24x24@4
+
+[24x24]
+Size=24
+Type=Fixed
+
+[24x24@2]
+Size=24
+Scale=2
+Type=Fixed
+
+[24x24@3]
+Size=24
+Scale=3
+Type=Fixed
+
+[24x24@4]
+Size=24
+Scale=4
+Type=Fixed
diff --git a/examples/bluetooth/btchat/main.cpp b/examples/bluetooth/btchat/main.cpp
index e728efd2..1da4f9f5 100644
--- a/examples/bluetooth/btchat/main.cpp
+++ b/examples/bluetooth/btchat/main.cpp
@@ -1,68 +1,25 @@
-/****************************************************************************
-**
-** 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: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 "chat.h"
-#include <QtWidgets/qapplication.h>
-//#include <QtCore/QLoggingCategory>
+#include <QLoggingCategory>
+
+#include <QApplication>
+
+using namespace Qt::StringLiterals;
int main(int argc, char *argv[])
{
- //QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
- QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ // QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
QApplication app(argc, argv);
+ QIcon::setThemeName(u"btchat"_s);
+
Chat d;
QObject::connect(&d, &Chat::accepted, &app, &QApplication::quit);
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
d.showMaximized();
#else
d.show();
diff --git a/examples/bluetooth/btchat/remoteselector.cpp b/examples/bluetooth/btchat/remoteselector.cpp
index ec5d207c..dc501c82 100644
--- a/examples/bluetooth/btchat/remoteselector.cpp
+++ b/examples/bluetooth/btchat/remoteselector.cpp
@@ -1,72 +1,43 @@
-/****************************************************************************
-**
-** 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: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 "remoteselector.h"
#include "ui_remoteselector.h"
-#include <QtBluetooth/qbluetoothlocaldevice.h>
-#include <QtBluetooth/qbluetoothservicediscoveryagent.h>
+#include <QBluetoothAddress>
+#include <QBluetoothLocalDevice>
+#include <QBluetoothServiceDiscoveryAgent>
+#include <QBluetoothUuid>
-QT_USE_NAMESPACE
+#include <QGuiApplication>
+#include <QStyleHints>
+
+#include <QListWidget>
+
+using namespace Qt::StringLiterals;
RemoteSelector::RemoteSelector(const QBluetoothAddress &localAdapter, QWidget *parent)
: QDialog(parent), ui(new Ui::RemoteSelector)
{
ui->setupUi(this);
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
+ setWindowState(Qt::WindowMaximized);
+#endif
+
+ QStyleHints *styleHints = qGuiApp->styleHints();
+ updateIcon(styleHints->colorScheme());
+ connect(styleHints, &QStyleHints::colorSchemeChanged, this, &RemoteSelector::updateIcon);
+//! [createDiscoveryAgent]
m_discoveryAgent = new QBluetoothServiceDiscoveryAgent(localAdapter);
- connect(m_discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)),
- this, SLOT(serviceDiscovered(QBluetoothServiceInfo)));
- connect(m_discoveryAgent, SIGNAL(finished()), this, SLOT(discoveryFinished()));
- connect(m_discoveryAgent, SIGNAL(canceled()), this, SLOT(discoveryFinished()));
+ connect(m_discoveryAgent, &QBluetoothServiceDiscoveryAgent::serviceDiscovered,
+ this, &RemoteSelector::serviceDiscovered);
+ connect(m_discoveryAgent, &QBluetoothServiceDiscoveryAgent::finished,
+ this, &RemoteSelector::discoveryFinished);
+ connect(m_discoveryAgent, &QBluetoothServiceDiscoveryAgent::canceled,
+ this, &RemoteSelector::discoveryFinished);
+//! [createDiscoveryAgent]
}
RemoteSelector::~RemoteSelector()
@@ -83,9 +54,10 @@ void RemoteSelector::startDiscovery(const QBluetoothUuid &uuid)
ui->remoteDevices->clear();
+//! [startDiscovery]
m_discoveryAgent->setUuidFilter(uuid);
m_discoveryAgent->start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
-
+//! [startDiscovery]
}
void RemoteSelector::stopDiscovery()
@@ -115,11 +87,12 @@ void RemoteSelector::serviceDiscovered(const QBluetoothServiceInfo &serviceInfo)
qDebug() << "\tRFCOMM server channel:" << serviceInfo.serverChannel();
#endif
const QBluetoothAddress address = serviceInfo.device().address();
- for (const QBluetoothServiceInfo &info : qAsConst(m_discoveredServices)) {
+ for (const QBluetoothServiceInfo &info : std::as_const(m_discoveredServices)) {
if (info.device().address() == address)
return;
}
+//! [serviceDiscovered]
QString remoteName;
if (serviceInfo.device().name().isEmpty())
remoteName = address.toString();
@@ -132,6 +105,7 @@ void RemoteSelector::serviceDiscovered(const QBluetoothServiceInfo &serviceInfo)
m_discoveredServices.insert(item, serviceInfo);
ui->remoteDevices->addItem(item);
+//! [serviceDiscovered]
}
void RemoteSelector::discoveryFinished()
@@ -139,9 +113,16 @@ void RemoteSelector::discoveryFinished()
ui->status->setText(tr("Select the chat service to connect to."));
}
+void RemoteSelector::updateIcon(Qt::ColorScheme scheme)
+{
+ const QString bluetoothIconName = (scheme == Qt::ColorScheme::Dark) ? u"bluetooth_dark"_s
+ : u"bluetooth"_s;
+ const QIcon bluetoothIcon = QIcon::fromTheme(bluetoothIconName);
+ ui->iconLabel->setPixmap(bluetoothIcon.pixmap(24, 24, QIcon::Normal, QIcon::On));
+}
+
void RemoteSelector::on_remoteDevices_itemActivated(QListWidgetItem *item)
{
- qDebug() << "got click" << item->text();
m_service = m_discoveredServices.value(item);
if (m_discoveryAgent->isActive())
m_discoveryAgent->stop();
@@ -149,6 +130,25 @@ void RemoteSelector::on_remoteDevices_itemActivated(QListWidgetItem *item)
accept();
}
+void RemoteSelector::on_remoteDevices_itemClicked(QListWidgetItem *)
+{
+ ui->connectButton->setEnabled(true);
+ ui->connectButton->setFocus();
+}
+
+void RemoteSelector::on_connectButton_clicked()
+{
+ auto items = ui->remoteDevices->selectedItems();
+ if (items.size()) {
+ QListWidgetItem *item = items[0];
+ m_service = m_discoveredServices.value(item);
+ if (m_discoveryAgent->isActive())
+ m_discoveryAgent->stop();
+
+ accept();
+ }
+}
+
void RemoteSelector::on_cancelButton_clicked()
{
reject();
diff --git a/examples/bluetooth/btchat/remoteselector.h b/examples/bluetooth/btchat/remoteselector.h
index 54649ba9..c6fc665b 100644
--- a/examples/bluetooth/btchat/remoteselector.h
+++ b/examples/bluetooth/btchat/remoteselector.h
@@ -1,68 +1,20 @@
-/****************************************************************************
-**
-** 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: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
#ifndef REMOTESELECTOR_H
#define REMOTESELECTOR_H
-#include <QtWidgets/qdialog.h>
+#include <QDialog>
-#include <QtBluetooth/qbluetoothaddress.h>
-#include <QtBluetooth/qbluetoothserviceinfo.h>
-#include <QtBluetooth/qbluetoothuuid.h>
+#include <QBluetoothServiceInfo>
-QT_FORWARD_DECLARE_CLASS(QBluetoothServiceDiscoveryAgent)
-QT_FORWARD_DECLARE_CLASS(QListWidgetItem)
+QT_BEGIN_NAMESPACE
-QT_USE_NAMESPACE
+class QBluetoothAddress;
+class QBluetoothServiceDiscoveryAgent;
+class QBluetoothUuid;
+class QListWidgetItem;
-QT_BEGIN_NAMESPACE
namespace Ui {
class RemoteSelector;
}
@@ -90,8 +42,11 @@ private:
private slots:
void serviceDiscovered(const QBluetoothServiceInfo &serviceInfo);
void discoveryFinished();
+ void updateIcon(Qt::ColorScheme scheme);
void on_remoteDevices_itemActivated(QListWidgetItem *item);
+ void on_remoteDevices_itemClicked(QListWidgetItem *item);
void on_cancelButton_clicked();
+ void on_connectButton_clicked();
};
#endif // REMOTESELECTOR_H
diff --git a/examples/bluetooth/btchat/remoteselector.ui b/examples/bluetooth/btchat/remoteselector.ui
index d415f416..853f6105 100644
--- a/examples/bluetooth/btchat/remoteselector.ui
+++ b/examples/bluetooth/btchat/remoteselector.ui
@@ -15,6 +15,16 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
+ <widget class="QLabel" name="iconLabel">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QLabel" name="status">
<property name="text">
<string>Scanning...</string>
@@ -25,11 +35,38 @@
<widget class="QListWidget" name="remoteDevices"/>
</item>
<item>
- <widget class="QPushButton" name="cancelButton">
- <property name="text">
- <string>Cancel</string>
- </property>
- </widget>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="connectButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Connect</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
</layout>
</widget>
diff --git a/examples/bluetooth/btfiletransfer/btfiletransfer.pro b/examples/bluetooth/btfiletransfer/btfiletransfer.pro
deleted file mode 100644
index 92b81bef..00000000
--- a/examples/bluetooth/btfiletransfer/btfiletransfer.pro
+++ /dev/null
@@ -1,31 +0,0 @@
-TEMPLATE = app
-TARGET = btfiletransfer
-
-QT = core bluetooth widgets
-requires(qtConfig(filedialog))
-
-SOURCES = \
- main.cpp \
- remoteselector.cpp \
- progress.cpp \
- pindisplay.cpp
-
-HEADERS = \
- remoteselector.h \
- progress.h \
- pindisplay.h
-
-FORMS = \
- remoteselector.ui \
- progress.ui \
- pindisplay.ui
-
-OTHER_FILES += \
- busy.gif \
- pairing.gif
-
-RESOURCES += \
- btfiletransfer.qrc
-
-target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/btfiletransfer
-INSTALLS += target
diff --git a/examples/bluetooth/btfiletransfer/btfiletransfer.qrc b/examples/bluetooth/btfiletransfer/btfiletransfer.qrc
deleted file mode 100644
index 10697d5b..00000000
--- a/examples/bluetooth/btfiletransfer/btfiletransfer.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
-<RCC>
- <qresource prefix="/icons">
- <file>busy.gif</file>
- <file>pairing.gif</file>
- </qresource>
-</RCC>
diff --git a/examples/bluetooth/btfiletransfer/busy.gif b/examples/bluetooth/btfiletransfer/busy.gif
deleted file mode 100644
index e192ca89..00000000
--- a/examples/bluetooth/btfiletransfer/busy.gif
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/btfiletransfer/doc/images/btfiletransfer-example.png b/examples/bluetooth/btfiletransfer/doc/images/btfiletransfer-example.png
deleted file mode 100644
index 9485d6e8..00000000
--- a/examples/bluetooth/btfiletransfer/doc/images/btfiletransfer-example.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/btfiletransfer/doc/src/btfiletransfer.qdoc b/examples/bluetooth/btfiletransfer/doc/src/btfiletransfer.qdoc
deleted file mode 100644
index adcafc11..00000000
--- a/examples/bluetooth/btfiletransfer/doc/src/btfiletransfer.qdoc
+++ /dev/null
@@ -1,43 +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$
-**
-****************************************************************************/
-
-/*!
- \example btfiletransfer
- \title Bluetooth File Transfer Example
- \brief An example showing the use of Bluetooth Object Push Profile (OPP).
-
- The Bluetooth File Transfer example is an application to transfer files
- via a bluetooth connection. This example does not work on Android due to
- missing Object Push support.
-
- \image btfiletransfer-example.png
-
- \include examples-run.qdocinc
-
- \sa {Qt Bluetooth}
-
-*/
diff --git a/examples/bluetooth/btfiletransfer/main.cpp b/examples/bluetooth/btfiletransfer/main.cpp
deleted file mode 100644
index 1871e207..00000000
--- a/examples/bluetooth/btfiletransfer/main.cpp
+++ /dev/null
@@ -1,69 +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: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$
-**
-****************************************************************************/
-
-#include "remoteselector.h"
-
-#include <QApplication>
-
-int main(int argc, char *argv[])
-{
- QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
- QApplication app(argc, argv);
-
- RemoteSelector d;
- QObject::connect(&d, SIGNAL(accepted()), &app, SLOT(quit()));
- d.startDiscovery();
- d.show();
-
- app.exec();
-
- return 0;
-}
-
diff --git a/examples/bluetooth/btfiletransfer/pairing.gif b/examples/bluetooth/btfiletransfer/pairing.gif
deleted file mode 100644
index e147f3ec..00000000
--- a/examples/bluetooth/btfiletransfer/pairing.gif
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/btfiletransfer/pindisplay.cpp b/examples/bluetooth/btfiletransfer/pindisplay.cpp
deleted file mode 100644
index 7458fbf3..00000000
--- a/examples/bluetooth/btfiletransfer/pindisplay.cpp
+++ /dev/null
@@ -1,79 +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: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$
-**
-****************************************************************************/
-
-#include "pindisplay.h"
-#include "ui_pindisplay.h"
-
-pinDisplay::pinDisplay(QString title, QString pin, QWidget *parent) :
- QDialog(parent),
- ui(new Ui::pinDisplay)
-{
- ui->setupUi(this);
- ui->label->setText(title);
- ui->pin->setText(pin);
-
- connect(ui->buttonBox, SIGNAL(accepted()), this, SIGNAL(accepted()));
- connect(ui->buttonBox, SIGNAL(rejected()), this, SIGNAL(rejected()));
-}
-
-pinDisplay::~pinDisplay()
-{
- delete ui;
-}
-
-void pinDisplay::on_buttonBox_accepted()
-{
- deleteLater();
-}
-
-void pinDisplay::setOkCancel()
-{
- ui->buttonBox->addButton(QDialogButtonBox::Cancel);
-}
diff --git a/examples/bluetooth/btfiletransfer/pindisplay.h b/examples/bluetooth/btfiletransfer/pindisplay.h
deleted file mode 100644
index 7acc517e..00000000
--- a/examples/bluetooth/btfiletransfer/pindisplay.h
+++ /dev/null
@@ -1,79 +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: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$
-**
-****************************************************************************/
-
-#ifndef PINDISPLAY_H
-#define PINDISPLAY_H
-
-#include <QDialog>
-
-QT_BEGIN_NAMESPACE
-namespace Ui {
- class pinDisplay;
-}
-QT_END_NAMESPACE
-
-class pinDisplay : public QDialog
-{
- Q_OBJECT
-
-public:
- explicit pinDisplay(QString title, QString pin, QWidget *parent = nullptr);
- ~pinDisplay();
-
- void setOkCancel();
-
-private Q_SLOTS:
- void on_buttonBox_accepted();
-
-private:
- Ui::pinDisplay *ui;
-};
-
-#endif // PINDISPLAY_H
diff --git a/examples/bluetooth/btfiletransfer/pindisplay.ui b/examples/bluetooth/btfiletransfer/pindisplay.ui
deleted file mode 100644
index 02bf7d50..00000000
--- a/examples/bluetooth/btfiletransfer/pindisplay.ui
+++ /dev/null
@@ -1,89 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>pinDisplay</class>
- <widget class="QDialog" name="pinDisplay">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>240</width>
- <height>153</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Enter Pin Code</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QLabel" name="pin">
- <property name="font">
- <font>
- <family>Monospace</family>
- <pointsize>24</pointsize>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>012345</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="label">
- <property name="text">
- <string>TextLabel</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>pinDisplay</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>248</x>
- <y>254</y>
- </hint>
- <hint type="destinationlabel">
- <x>157</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>pinDisplay</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>316</x>
- <y>260</y>
- </hint>
- <hint type="destinationlabel">
- <x>286</x>
- <y>274</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
diff --git a/examples/bluetooth/btfiletransfer/progress.cpp b/examples/bluetooth/btfiletransfer/progress.cpp
deleted file mode 100644
index e72ef0c8..00000000
--- a/examples/bluetooth/btfiletransfer/progress.cpp
+++ /dev/null
@@ -1,107 +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: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$
-**
-****************************************************************************/
-
-#include "progress.h"
-#include "ui_progress.h"
-
-#include <qbluetoothdeviceinfo.h>
-#include <qbluetoothaddress.h>
-#include <qbluetoothtransferrequest.h>
-#include <qbluetoothtransferreply.h>
-
-QT_USE_NAMESPACE
-
-Progress::Progress(QWidget *parent) :
- QDialog(parent),
- ui(new Ui::Progress)
-{
- ui->setupUi(this);
- ui->progressBar->setRange(0, 1);
- connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(close()));
-}
-
-Progress::~Progress()
-{
- delete ui;
-}
-
-void Progress::setStatus(QString title, QString filename) {
- ui->titleLabel->setText(title);
- ui->statusLabel->setText(filename);
-}
-
-void Progress::finished(QBluetoothTransferReply *reply){
- if (reply->error() != QBluetoothTransferReply::NoError){
- ui->progressBar->setDisabled(true);
- ui->statusLabel->setText(tr("Failed: %1").arg(reply->errorString()));
- }
- else {
- ui->statusLabel->setText(tr("Transfer complete"));
- }
- ui->cancelButton->setText(tr("Dismiss"));
-}
-
-void Progress::uploadProgress(qint64 bytesSent, qint64 bytesTotal)
-{
- if (bytesSent == 0){
- start.start();
- }
-
- ui->progressBar->setMaximum(bytesTotal);
- ui->progressBar->setValue(bytesSent);
- if (bytesSent && bytesTotal &&
- (start.elapsed() > 1000) &&
- (bytesSent > start.elapsed()/1000)) {
-
- ui->statusLabel->setText(tr("Transferring...ETA: %1s")
- .arg(((bytesTotal-bytesSent)/(bytesSent/(start.elapsed()/1000)))));
- }
-}
-
diff --git a/examples/bluetooth/btfiletransfer/progress.h b/examples/bluetooth/btfiletransfer/progress.h
deleted file mode 100644
index afd72153..00000000
--- a/examples/bluetooth/btfiletransfer/progress.h
+++ /dev/null
@@ -1,87 +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: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$
-**
-****************************************************************************/
-
-#ifndef PROGRESS_H
-#define PROGRESS_H
-
-#include <QDialog>
-#include <QElapsedTimer>
-
-QT_FORWARD_DECLARE_CLASS(QBluetoothTransferReply)
-
-QT_USE_NAMESPACE
-
-QT_BEGIN_NAMESPACE
-namespace Ui {
- class Progress;
-}
-QT_END_NAMESPACE
-
-class Progress : public QDialog
-{
- Q_OBJECT
-
-public:
- explicit Progress(QWidget *parent = nullptr);
- ~Progress();
-
- void setStatus(QString title, QString filename);
-
-public Q_SLOTS:
- void finished(QBluetoothTransferReply *);
- void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
-
-private:
- Ui::Progress *ui;
-
- QElapsedTimer start;
-};
-
-#endif // PROGRESS_H
diff --git a/examples/bluetooth/btfiletransfer/progress.ui b/examples/bluetooth/btfiletransfer/progress.ui
deleted file mode 100644
index 3b151f06..00000000
--- a/examples/bluetooth/btfiletransfer/progress.ui
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>Progress</class>
- <widget class="QDialog" name="Progress">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>408</width>
- <height>115</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Transfer Progress</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QLabel" name="titleLabel">
- <property name="text">
- <string>Filename</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QProgressBar" name="progressBar">
- <property name="minimumSize">
- <size>
- <width>390</width>
- <height>0</height>
- </size>
- </property>
- <property name="value">
- <number>24</number>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="statusLabel">
- <property name="text">
- <string>Status</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="cancelButton">
- <property name="text">
- <string>Cancel</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/examples/bluetooth/btfiletransfer/remoteselector.cpp b/examples/bluetooth/btfiletransfer/remoteselector.cpp
deleted file mode 100644
index b3c60cb3..00000000
--- a/examples/bluetooth/btfiletransfer/remoteselector.cpp
+++ /dev/null
@@ -1,413 +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: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$
-**
-****************************************************************************/
-
-#include "remoteselector.h"
-#include "ui_remoteselector.h"
-
-#include <qbluetoothdeviceinfo.h>
-#include <qbluetoothaddress.h>
-#include <qbluetoothtransferrequest.h>
-#include <qbluetoothtransferreply.h>
-#include <qbluetoothlocaldevice.h>
-
-#include <QMovie>
-#include <QMessageBox>
-#include <QFileDialog>
-#include <QCheckBox>
-
-#include "progress.h"
-#include "pindisplay.h"
-
-QT_USE_NAMESPACE
-
-RemoteSelector::RemoteSelector(QWidget *parent)
-: QDialog(parent), ui(new Ui::RemoteSelector),
- m_localDevice(new QBluetoothLocalDevice), m_pindisplay(0),
- m_pairingError(false)
-{
- ui->setupUi(this);
-
- //Using default Bluetooth adapter
- QBluetoothAddress adapterAddress = m_localDevice->address();
-
- /*
- * In case of multiple Bluetooth adapters it is possible to
- * set which adapter will be used by providing MAC Address.
- * Example code:
- *
- * QBluetoothAddress adapterAddress("XX:XX:XX:XX:XX:XX");
- * m_discoveryAgent = new QBluetoothServiceDiscoveryAgent(adapterAddress);
- */
-
- m_discoveryAgent = new QBluetoothServiceDiscoveryAgent(adapterAddress);
-
- connect(m_discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)),
- this, SLOT(serviceDiscovered(QBluetoothServiceInfo)));
- connect(m_discoveryAgent, SIGNAL(finished()), this, SLOT(discoveryFinished()));
- connect(m_discoveryAgent, SIGNAL(canceled()), this, SLOT(discoveryFinished()));
-
- ui->remoteDevices->setColumnWidth(3, 75);
- ui->remoteDevices->setColumnWidth(4, 100);
-
- connect(m_localDevice, SIGNAL(pairingDisplayPinCode(QBluetoothAddress,QString)),
- this, SLOT(displayPin(QBluetoothAddress,QString)));
- connect(m_localDevice, SIGNAL(pairingDisplayConfirmation(QBluetoothAddress,QString)),
- this, SLOT(displayConfirmation(QBluetoothAddress,QString)));
- connect(m_localDevice, SIGNAL(pairingFinished(QBluetoothAddress,QBluetoothLocalDevice::Pairing)),
- this, SLOT(pairingFinished(QBluetoothAddress,QBluetoothLocalDevice::Pairing)));
- connect(m_localDevice, SIGNAL(error(QBluetoothLocalDevice::Error)),
- this, SLOT(pairingError(QBluetoothLocalDevice::Error)));
-
- ui->busyWidget->setMovie(new QMovie(":/icons/busy.gif"));
- ui->busyWidget->movie()->start();
-
- ui->pairingBusy->setMovie(new QMovie(":/icons/pairing.gif"));
- ui->pairingBusy->hide();
-
- ui->remoteDevices->clearContents();
- ui->remoteDevices->setRowCount(0);
-}
-
-RemoteSelector::~RemoteSelector()
-{
- delete ui;
- delete m_discoveryAgent;
- delete m_localDevice;
-}
-
-void RemoteSelector::startDiscovery(const QBluetoothUuid &uuid)
-{
- ui->stopButton->setDisabled(false);
- if (m_discoveryAgent->isActive())
- m_discoveryAgent->stop();
-
- m_discoveryAgent->setUuidFilter(uuid);
- m_discoveryAgent->start();
-
- if (!m_discoveryAgent->isActive() ||
- m_discoveryAgent->error() != QBluetoothServiceDiscoveryAgent::NoError) {
- ui->status->setText(tr("Cannot find remote services."));
- } else {
- ui->status->setText(tr("Scanning..."));
- ui->busyWidget->show();
- ui->busyWidget->movie()->start();
- }
-}
-
-QBluetoothServiceInfo RemoteSelector::service() const
-{
- return m_service;
-}
-
-void RemoteSelector::serviceDiscovered(const QBluetoothServiceInfo &serviceInfo)
-{
-#if 0
- qDebug() << "Discovered service on"
- << serviceInfo.device().name() << serviceInfo.device().address().toString();
- qDebug() << "\tService name:" << serviceInfo.serviceName();
- qDebug() << "\tDescription:"
- << serviceInfo.attribute(QBluetoothServiceInfo::ServiceDescription).toString();
- qDebug() << "\tProvider:"
- << serviceInfo.attribute(QBluetoothServiceInfo::ServiceProvider).toString();
- qDebug() << "\tL2CAP protocol service multiplexer:"
- << serviceInfo.protocolServiceMultiplexer();
- qDebug() << "\tRFCOMM server channel:" << serviceInfo.serverChannel();
-#endif
-
- QString remoteName;
- if (serviceInfo.device().name().isEmpty())
- remoteName = serviceInfo.device().address().toString();
- else
- remoteName = serviceInfo.device().name();
-
-// QListWidgetItem *item =
-// new QListWidgetItem(QString::fromLatin1("%1\t%2\t%3").arg(serviceInfo.device().address().toString(),
-// serviceInfo.device().name(), serviceInfo.serviceName()));
-
- const QBluetoothAddress address = serviceInfo.device().address();
- for (QBluetoothServiceInfo &info : m_discoveredServices) {
- if (info.device().address() == address){
- info = serviceInfo;
- return;
- }
- }
-
- int row = ui->remoteDevices->rowCount();
- ui->remoteDevices->insertRow(row);
- QTableWidgetItem *item = new QTableWidgetItem(address.toString());
- ui->remoteDevices->setItem(row, 0, item);
- item = new QTableWidgetItem(serviceInfo.device().name());
- ui->remoteDevices->setItem(row, 1, item);
- item = new QTableWidgetItem(serviceInfo.serviceName());
-
- ui->remoteDevices->setItem(row, 2, item);
-
- QBluetoothLocalDevice::Pairing p = m_localDevice->pairingStatus(address);
-
- ui->remoteDevices->blockSignals(true);
-
- item = new QTableWidgetItem();
- if ((p&QBluetoothLocalDevice::Paired) || (p&QBluetoothLocalDevice::AuthorizedPaired))
- item->setCheckState(Qt::Checked);
- else
- item->setCheckState(Qt::Unchecked);
- ui->remoteDevices->setItem(row, 3, item);
-
- item = new QTableWidgetItem();
- if (p&QBluetoothLocalDevice::AuthorizedPaired)
- item->setCheckState(Qt::Checked);
- else
- item->setCheckState(Qt::Unchecked);
-
- ui->remoteDevices->setItem(row, 4, item);
-
- ui->remoteDevices->blockSignals(false);
-
-
- m_discoveredServices.insert(row, serviceInfo);
-}
-
-void RemoteSelector::discoveryFinished()
-{
- ui->status->setText(tr("Select the device to send to."));
- ui->stopButton->setDisabled(true);
- ui->busyWidget->movie()->stop();
- ui->busyWidget->hide();
-}
-
-void RemoteSelector::startDiscovery()
-{
- startDiscovery(QBluetoothUuid(QBluetoothUuid::ObexObjectPush));
-}
-
-void RemoteSelector::on_refreshPB_clicked()
-{
- startDiscovery();
- ui->stopButton->setDisabled(false);
-}
-
-void RemoteSelector::on_fileSelectPB_clicked()
-{
- ui->fileName->setText(QFileDialog::getOpenFileName());
- if (m_service.isValid())
- ui->sendButton->setDisabled(false);
-}
-
-void RemoteSelector::on_sendButton_clicked()
-{
- QBluetoothTransferManager mgr;
- QBluetoothTransferRequest req(m_service.device().address());
-
- m_file = new QFile(ui->fileName->text());
-
- Progress *p = new Progress;
- p->setStatus("Sending to: " + m_service.device().name(), "Waiting for start");
- p->show();
-
- QBluetoothTransferReply *reply = mgr.put(req, m_file);
- //mgr is default parent
- //ensure that mgr doesn't take reply down when leaving scope
- reply->setParent(this);
- if (reply->error()){
- qDebug() << "Failed to send file";
- p->finished(reply);
- reply->deleteLater();
- return;
- }
-
- connect(reply, SIGNAL(transferProgress(qint64,qint64)), p, SLOT(uploadProgress(qint64,qint64)));
- connect(reply, SIGNAL(finished(QBluetoothTransferReply*)), p, SLOT(finished(QBluetoothTransferReply*)));
- connect(p, SIGNAL(rejected()), reply, SLOT(abort()));
-}
-
-void RemoteSelector::on_stopButton_clicked()
-{
- m_discoveryAgent->stop();
-}
-
-QString RemoteSelector::addressToName(const QBluetoothAddress &address) const
-{
- for (const QBluetoothServiceInfo &info : m_discoveredServices) {
- if (info.device().address() == address)
- return info.device().name();
- }
- return address.toString();
-}
-
-void RemoteSelector::displayPin(const QBluetoothAddress &address, QString pin)
-{
- if (m_pindisplay)
- m_pindisplay->deleteLater();
- m_pindisplay = new pinDisplay(QString("Enter pairing pin on: %1").arg(addressToName(address)), pin, this);
- m_pindisplay->show();
-}
-
-void RemoteSelector::displayConfirmation(const QBluetoothAddress &address, QString pin)
-{
- Q_UNUSED(address);
-
- if (m_pindisplay)
- m_pindisplay->deleteLater();
- m_pindisplay = new pinDisplay(QString("Confirm this pin is the same"), pin, this);
- connect(m_pindisplay, SIGNAL(accepted()), this, SLOT(displayConfAccepted()));
- connect(m_pindisplay, SIGNAL(rejected()), this, SLOT(displayConfReject()));
- m_pindisplay->setOkCancel();
- m_pindisplay->show();
-}
-
-void RemoteSelector::displayConfAccepted()
-{
- m_localDevice->pairingConfirmation(true);
-}
-void RemoteSelector::displayConfReject()
-{
- m_localDevice->pairingConfirmation(false);
-}
-
-void RemoteSelector::pairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing status)
-{
- QBluetoothServiceInfo service;
- int row = 0;
-
- ui->pairingBusy->hide();
- ui->pairingBusy->movie()->stop();
-
- ui->remoteDevices->blockSignals(true);
-
- for (int i = 0; i < m_discoveredServices.count(); i++){
- if (m_discoveredServices.value(i).device().address() == address){
- service = m_discoveredServices.value(i);
- row = i;
- break;
- }
- }
-
- if (m_pindisplay)
- delete m_pindisplay;
-
- QMessageBox msgBox;
- if (m_pairingError) {
- msgBox.setText("Pairing failed with " + address.toString());
- } else if (status == QBluetoothLocalDevice::Paired
- || status == QBluetoothLocalDevice::AuthorizedPaired) {
- msgBox.setText("Paired successfully with " + address.toString());
- } else {
- msgBox.setText("Pairing released with " + address.toString());
- }
-
- if (service.isValid()){
- if (status == QBluetoothLocalDevice::AuthorizedPaired){
- ui->remoteDevices->item(row, 3)->setCheckState(Qt::Checked);
- ui->remoteDevices->item(row, 4)->setCheckState(Qt::Checked);
- }
- else if (status == QBluetoothLocalDevice::Paired){
- ui->remoteDevices->item(row, 3)->setCheckState(Qt::Checked);
- ui->remoteDevices->item(row, 4)->setCheckState(Qt::Unchecked);
- }
- else {
- ui->remoteDevices->item(row, 3)->setCheckState(Qt::Unchecked);
- ui->remoteDevices->item(row, 4)->setCheckState(Qt::Unchecked);
- }
- }
-
- m_pairingError = false;
- msgBox.exec();
-
- ui->remoteDevices->blockSignals(false);
-}
-
-void RemoteSelector::pairingError(QBluetoothLocalDevice::Error error)
-{
- if (error != QBluetoothLocalDevice::PairingError)
- return;
-
- m_pairingError = true;
- pairingFinished(m_service.device().address(), QBluetoothLocalDevice::Unpaired);
-}
-
-void RemoteSelector::on_remoteDevices_cellClicked(int row, int column)
-{
- Q_UNUSED(column);
-
- m_service = m_discoveredServices.value(row);
- if (!ui->fileName->text().isEmpty()) {
- ui->sendButton->setDisabled(false);
- }
-}
-
-void RemoteSelector::on_remoteDevices_itemChanged(QTableWidgetItem* item)
-{
- int row = item->row();
- int column = item->column();
- m_service = m_discoveredServices.value(row);
-
- if (column < 3)
- return;
-
- if (item->checkState() == Qt::Unchecked && column == 3){
- m_localDevice->requestPairing(m_service.device().address(), QBluetoothLocalDevice::Unpaired);
- return; // don't continue and start movie
- }
- else if ((item->checkState() == Qt::Checked && column == 3) ||
- (item->checkState() == Qt::Unchecked && column == 4)){
- m_localDevice->requestPairing(m_service.device().address(), QBluetoothLocalDevice::Paired);
- ui->remoteDevices->blockSignals(true);
- ui->remoteDevices->item(row, column)->setCheckState(Qt::PartiallyChecked);
- ui->remoteDevices->blockSignals(false);
- }
- else if (item->checkState() == Qt::Checked && column == 4){
- m_localDevice->requestPairing(m_service.device().address(), QBluetoothLocalDevice::AuthorizedPaired);
- ui->remoteDevices->blockSignals(true);
- ui->remoteDevices->item(row, column)->setCheckState(Qt::PartiallyChecked);
- ui->remoteDevices->blockSignals(false);
- }
- ui->pairingBusy->show();
- ui->pairingBusy->movie()->start();
-}
diff --git a/examples/bluetooth/btfiletransfer/remoteselector.h b/examples/bluetooth/btfiletransfer/remoteselector.h
deleted file mode 100644
index 8266c8c4..00000000
--- a/examples/bluetooth/btfiletransfer/remoteselector.h
+++ /dev/null
@@ -1,122 +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: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$
-**
-****************************************************************************/
-
-#ifndef REMOTESELECTOR_H
-#define REMOTESELECTOR_H
-
-#include <QDialog>
-#include <QPointer>
-
-#include <qbluetoothuuid.h>
-#include <qbluetoothserviceinfo.h>
-#include <qbluetoothservicediscoveryagent.h>
-#include <qbluetoothlocaldevice.h>
-
-QT_FORWARD_DECLARE_CLASS(QModelIndex)
-QT_FORWARD_DECLARE_CLASS(QTableWidgetItem)
-QT_FORWARD_DECLARE_CLASS(QFile)
-
-class pinDisplay;
-
-QT_USE_NAMESPACE
-
-QT_BEGIN_NAMESPACE
-namespace Ui {
- class RemoteSelector;
-}
-QT_END_NAMESPACE
-
-class RemoteSelector : public QDialog
-{
- Q_OBJECT
-
-public:
- explicit RemoteSelector(QWidget *parent = nullptr);
- ~RemoteSelector();
-
- void startDiscovery(const QBluetoothUuid &uuid);
- QBluetoothServiceInfo service() const;
-
-private:
- Ui::RemoteSelector *ui;
-
- QBluetoothServiceDiscoveryAgent *m_discoveryAgent;
- QBluetoothServiceInfo m_service;
- QMap<int, QBluetoothServiceInfo> m_discoveredServices;
- QFile *m_file;
- QBluetoothLocalDevice *m_localDevice;
- QPointer<pinDisplay> m_pindisplay;
- bool m_pairingError;
-
- QString addressToName(const QBluetoothAddress &address) const;
-
-public Q_SLOTS:
- void startDiscovery();
-
-private slots:
- void serviceDiscovered(const QBluetoothServiceInfo &serviceInfo);
- void discoveryFinished();
- void on_refreshPB_clicked();
- void on_fileSelectPB_clicked();
- void on_sendButton_clicked();
- void on_stopButton_clicked();
-
- void pairingFinished(const QBluetoothAddress &address,QBluetoothLocalDevice::Pairing pairing);
- void pairingError(QBluetoothLocalDevice::Error error);
- void displayPin(const QBluetoothAddress &address, QString pin);
- void displayConfirmation(const QBluetoothAddress &address, QString pin);
- void displayConfReject();
- void displayConfAccepted();
-
- void on_remoteDevices_cellClicked(int row, int column);
- void on_remoteDevices_itemChanged(QTableWidgetItem* item);
-};
-
-#endif // REMOTESELECTOR_H
diff --git a/examples/bluetooth/btfiletransfer/remoteselector.ui b/examples/bluetooth/btfiletransfer/remoteselector.ui
deleted file mode 100644
index f99deaa7..00000000
--- a/examples/bluetooth/btfiletransfer/remoteselector.ui
+++ /dev/null
@@ -1,214 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>RemoteSelector</class>
- <widget class="QDialog" name="RemoteSelector">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>681</width>
- <height>394</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Available file transfer services</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QGridLayout" name="gridLayout">
- <property name="horizontalSpacing">
- <number>6</number>
- </property>
- <item row="7" column="0" colspan="2">
- <widget class="QLineEdit" name="fileName"/>
- </item>
- <item row="7" column="2">
- <widget class="QPushButton" name="fileSelectPB">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Select File</string>
- </property>
- </widget>
- </item>
- <item row="8" column="0" colspan="3">
- <widget class="QPushButton" name="sendButton">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Send</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0" colspan="3">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QLabel" name="busyWidget">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="maximumSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="baseSize">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
- </property>
- <property name="text">
- <string>TextLabel</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="status">
- <property name="text">
- <string>Scanning...</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="pairingBusy">
- <property name="text">
- <string>TextLabel</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="stopButton">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Stop</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="refreshPB">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Refresh</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="6" column="0" colspan="3">
- <widget class="QTableWidget" name="remoteDevices">
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAsNeeded</enum>
- </property>
- <property name="editTriggers">
- <set>QAbstractItemView::NoEditTriggers</set>
- </property>
- <property name="showDropIndicator" stdset="0">
- <bool>false</bool>
- </property>
- <property name="alternatingRowColors">
- <bool>true</bool>
- </property>
- <property name="selectionMode">
- <enum>QAbstractItemView::SingleSelection</enum>
- </property>
- <property name="selectionBehavior">
- <enum>QAbstractItemView::SelectRows</enum>
- </property>
- <property name="showGrid">
- <bool>false</bool>
- </property>
- <property name="wordWrap">
- <bool>false</bool>
- </property>
- <property name="rowCount">
- <number>1</number>
- </property>
- <attribute name="horizontalHeaderCascadingSectionResizes">
- <bool>true</bool>
- </attribute>
- <attribute name="horizontalHeaderDefaultSectionSize">
- <number>150</number>
- </attribute>
- <attribute name="horizontalHeaderStretchLastSection">
- <bool>true</bool>
- </attribute>
- <attribute name="verticalHeaderVisible">
- <bool>false</bool>
- </attribute>
- <attribute name="verticalHeaderCascadingSectionResizes">
- <bool>false</bool>
- </attribute>
- <row>
- <property name="text">
- <string>Test</string>
- </property>
- </row>
- <column>
- <property name="text">
- <string>MAC Address</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Device Name</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Device Service</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Paired</string>
- </property>
- <property name="toolTip">
- <string comment="Paired" extracomment="Paired"/>
- </property>
- <property name="whatsThis">
- <string comment="Paired" extracomment="Paired"/>
- </property>
- <property name="textAlignment">
- <set>AlignHCenter|AlignVCenter|AlignCenter</set>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Authorized</string>
- </property>
- <property name="textAlignment">
- <set>AlignHCenter|AlignVCenter|AlignCenter</set>
- </property>
- </column>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/examples/bluetooth/btscanner/device.cpp b/examples/bluetooth/btscanner/device.cpp
deleted file mode 100644
index b6a07db4..00000000
--- a/examples/bluetooth/btscanner/device.cpp
+++ /dev/null
@@ -1,229 +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: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$
-**
-****************************************************************************/
-
-#include "device.h"
-#include "service.h"
-
-#include <qbluetoothaddress.h>
-#include <qbluetoothdevicediscoveryagent.h>
-#include <qbluetoothlocaldevice.h>
-#include <QMenu>
-#include <QDebug>
-
-DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget *parent)
-: QDialog(parent), localDevice(new QBluetoothLocalDevice),
- ui(new Ui_DeviceDiscovery)
-{
- ui->setupUi(this);
-
- /*
- * In case of multiple Bluetooth adapters it is possible to set adapter
- * which will be used. Example code:
- *
- * QBluetoothAddress address("XX:XX:XX:XX:XX:XX");
- * discoveryAgent = new QBluetoothDeviceDiscoveryAgent(address);
- *
- **/
-
- discoveryAgent = new QBluetoothDeviceDiscoveryAgent();
-
- connect(ui->inquiryType, SIGNAL(toggled(bool)), this, SLOT(setGeneralUnlimited(bool)));
- connect(ui->scan, SIGNAL(clicked()), this, SLOT(startScan()));
-
- connect(discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
- this, SLOT(addDevice(QBluetoothDeviceInfo)));
- connect(discoveryAgent, SIGNAL(finished()), this, SLOT(scanFinished()));
-
- connect(ui->list, SIGNAL(itemActivated(QListWidgetItem*)),
- this, SLOT(itemActivated(QListWidgetItem*)));
-
- connect(localDevice, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)),
- this, SLOT(hostModeStateChanged(QBluetoothLocalDevice::HostMode)));
-
- hostModeStateChanged(localDevice->hostMode());
- // add context menu for devices to be able to pair device
- ui->list->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(ui->list, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(displayPairingMenu(QPoint)));
- connect(localDevice, SIGNAL(pairingFinished(QBluetoothAddress,QBluetoothLocalDevice::Pairing))
- , this, SLOT(pairingDone(QBluetoothAddress,QBluetoothLocalDevice::Pairing)));
-
-}
-
-DeviceDiscoveryDialog::~DeviceDiscoveryDialog()
-{
- delete discoveryAgent;
-}
-
-void DeviceDiscoveryDialog::addDevice(const QBluetoothDeviceInfo &info)
-{
- QString label = QString("%1 %2").arg(info.address().toString()).arg(info.name());
- QList<QListWidgetItem *> items = ui->list->findItems(label, Qt::MatchExactly);
- if (items.empty()) {
- QListWidgetItem *item = new QListWidgetItem(label);
- QBluetoothLocalDevice::Pairing pairingStatus = localDevice->pairingStatus(info.address());
- if (pairingStatus == QBluetoothLocalDevice::Paired || pairingStatus == QBluetoothLocalDevice::AuthorizedPaired )
- item->setForeground(QColor(Qt::green));
- else
- item->setForeground(QColor(Qt::black));
-
- ui->list->addItem(item);
- }
-
-}
-
-void DeviceDiscoveryDialog::startScan()
-{
- discoveryAgent->start();
- ui->scan->setEnabled(false);
- ui->inquiryType->setEnabled(false);
-}
-
-void DeviceDiscoveryDialog::scanFinished()
-{
- ui->scan->setEnabled(true);
- ui->inquiryType->setEnabled(true);
-}
-
-void DeviceDiscoveryDialog::setGeneralUnlimited(bool unlimited)
-{
- if (unlimited)
- discoveryAgent->setInquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry);
- else
- discoveryAgent->setInquiryType(QBluetoothDeviceDiscoveryAgent::LimitedInquiry);
-}
-
-void DeviceDiscoveryDialog::itemActivated(QListWidgetItem *item)
-{
- QString text = item->text();
-
- int index = text.indexOf(' ');
-
- if (index == -1)
- return;
-
- QBluetoothAddress address(text.left(index));
- QString name(text.mid(index + 1));
-
- ServiceDiscoveryDialog d(name, address);
- d.exec();
-}
-
-void DeviceDiscoveryDialog::on_discoverable_clicked(bool clicked)
-{
- if (clicked)
- localDevice->setHostMode(QBluetoothLocalDevice::HostDiscoverable);
- else
- localDevice->setHostMode(QBluetoothLocalDevice::HostConnectable);
-}
-
-void DeviceDiscoveryDialog::on_power_clicked(bool clicked)
-{
- if (clicked)
- localDevice->powerOn();
- else
- localDevice->setHostMode(QBluetoothLocalDevice::HostPoweredOff);
-}
-
-void DeviceDiscoveryDialog::hostModeStateChanged(QBluetoothLocalDevice::HostMode mode)
-{
- if (mode != QBluetoothLocalDevice::HostPoweredOff)
- ui->power->setChecked(true);
- else
- ui->power->setChecked( false);
-
- if (mode == QBluetoothLocalDevice::HostDiscoverable)
- ui->discoverable->setChecked(true);
- else
- ui->discoverable->setChecked(false);
-
- bool on = !(mode == QBluetoothLocalDevice::HostPoweredOff);
-
-
- ui->scan->setEnabled(on);
- ui->discoverable->setEnabled(on);
-}
-void DeviceDiscoveryDialog::displayPairingMenu(const QPoint &pos)
-{
- if (ui->list->count() == 0)
- return;
- QMenu menu(this);
- QAction *pairAction = menu.addAction("Pair");
- QAction *removePairAction = menu.addAction("Remove Pairing");
- QAction *chosenAction = menu.exec(ui->list->viewport()->mapToGlobal(pos));
- QListWidgetItem *currentItem = ui->list->currentItem();
-
- QString text = currentItem->text();
- int index = text.indexOf(' ');
- if (index == -1)
- return;
-
- QBluetoothAddress address (text.left(index));
- if (chosenAction == pairAction) {
- localDevice->requestPairing(address, QBluetoothLocalDevice::Paired);
- } else if (chosenAction == removePairAction) {
- localDevice->requestPairing(address, QBluetoothLocalDevice::Unpaired);
- }
-}
-void DeviceDiscoveryDialog::pairingDone(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing)
-{
- QList<QListWidgetItem *> items = ui->list->findItems(address.toString(), Qt::MatchContains);
-
- if (pairing == QBluetoothLocalDevice::Paired || pairing == QBluetoothLocalDevice::AuthorizedPaired ) {
- for (int var = 0; var < items.count(); ++var) {
- QListWidgetItem *item = items.at(var);
- item->setForeground(QColor(Qt::green));
- }
- } else {
- for (int var = 0; var < items.count(); ++var) {
- QListWidgetItem *item = items.at(var);
- item->setForeground(QColor(Qt::red));
- }
- }
-}
diff --git a/examples/bluetooth/btscanner/device.h b/examples/bluetooth/btscanner/device.h
deleted file mode 100644
index 35dc7965..00000000
--- a/examples/bluetooth/btscanner/device.h
+++ /dev/null
@@ -1,92 +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: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$
-**
-****************************************************************************/
-
-#ifndef DEVICE_H
-#define DEVICE_H
-
-#include "ui_device.h"
-
-#include <qbluetoothlocaldevice.h>
-
-#include <QDialog>
-
-QT_FORWARD_DECLARE_CLASS(QBluetoothDeviceDiscoveryAgent)
-QT_FORWARD_DECLARE_CLASS(QBluetoothDeviceInfo)
-
-QT_USE_NAMESPACE
-
-class DeviceDiscoveryDialog : public QDialog
-{
- Q_OBJECT
-
-public:
- DeviceDiscoveryDialog(QWidget *parent = nullptr);
- ~DeviceDiscoveryDialog();
-
-public slots:
- void addDevice(const QBluetoothDeviceInfo&);
- void on_power_clicked(bool clicked);
- void on_discoverable_clicked(bool clicked);
- void displayPairingMenu(const QPoint &pos);
- void pairingDone(const QBluetoothAddress&, QBluetoothLocalDevice::Pairing);
-private slots:
- void startScan();
- void scanFinished();
- void setGeneralUnlimited(bool unlimited);
- void itemActivated(QListWidgetItem *item);
- void hostModeStateChanged(QBluetoothLocalDevice::HostMode);
-
-private:
- QBluetoothDeviceDiscoveryAgent *discoveryAgent;
- QBluetoothLocalDevice *localDevice;
- Ui_DeviceDiscovery *ui;
-};
-
-#endif
diff --git a/examples/bluetooth/btscanner/doc/images/btscanner-example.png b/examples/bluetooth/btscanner/doc/images/btscanner-example.png
deleted file mode 100644
index 4a8f8f79..00000000
--- a/examples/bluetooth/btscanner/doc/images/btscanner-example.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/btscanner/doc/src/btscanner.qdoc b/examples/bluetooth/btscanner/doc/src/btscanner.qdoc
deleted file mode 100644
index c4e45650..00000000
--- a/examples/bluetooth/btscanner/doc/src/btscanner.qdoc
+++ /dev/null
@@ -1,41 +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$
-**
-****************************************************************************/
-
-/*!
- \example btscanner
- \title Bluetooth Scanner Example
- \brief An example showing how to locate Bluetooth devices.
-
- An example showing how to locate Bluetooth devices.
-
- \image btscanner-example.png
-
- \include examples-run.qdocinc
-
- \sa {Qt Bluetooth}
-
-*/
diff --git a/examples/bluetooth/btscanner/main.cpp b/examples/bluetooth/btscanner/main.cpp
deleted file mode 100644
index a84dcda9..00000000
--- a/examples/bluetooth/btscanner/main.cpp
+++ /dev/null
@@ -1,68 +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: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$
-**
-****************************************************************************/
-
-#include "device.h"
-
-#include <QApplication>
-
-int main(int argc, char *argv[])
-{
- QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
- QApplication app(argc, argv);
-
- DeviceDiscoveryDialog d;
- QObject::connect(&d, SIGNAL(accepted()), &app, SLOT(quit()));
- d.show();
-
- app.exec();
-
- return 0;
-}
-
diff --git a/examples/bluetooth/btscanner/service.cpp b/examples/bluetooth/btscanner/service.cpp
deleted file mode 100644
index 12e8bd2b..00000000
--- a/examples/bluetooth/btscanner/service.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2013 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: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$
-**
-****************************************************************************/
-
-#include "service.h"
-
-#include <qbluetoothaddress.h>
-#include <qbluetoothservicediscoveryagent.h>
-#include <qbluetoothserviceinfo.h>
-#include <qbluetoothlocaldevice.h>
-#include <qbluetoothuuid.h>
-
-
-ServiceDiscoveryDialog::ServiceDiscoveryDialog(const QString &name,
- const QBluetoothAddress &address, QWidget *parent)
-: QDialog(parent), ui(new Ui_ServiceDiscovery)
-{
- ui->setupUi(this);
-
- //Using default Bluetooth adapter
- QBluetoothLocalDevice localDevice;
- QBluetoothAddress adapterAddress = localDevice.address();
-
- /*
- * In case of multiple Bluetooth adapters it is possible to
- * set which adapter will be used by providing MAC Address.
- * Example code:
- *
- * QBluetoothAddress adapterAddress("XX:XX:XX:XX:XX:XX");
- * discoveryAgent = new QBluetoothServiceDiscoveryAgent(adapterAddress);
- */
-
- discoveryAgent = new QBluetoothServiceDiscoveryAgent(adapterAddress);
-
- discoveryAgent->setRemoteAddress(address);
-
- setWindowTitle(name);
-
- connect(discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)),
- this, SLOT(addService(QBluetoothServiceInfo)));
- connect(discoveryAgent, SIGNAL(finished()), ui->status, SLOT(hide()));
-
- discoveryAgent->start();
-}
-
-ServiceDiscoveryDialog::~ServiceDiscoveryDialog()
-{
- delete discoveryAgent;
- delete ui;
-}
-
-void ServiceDiscoveryDialog::addService(const QBluetoothServiceInfo &info)
-{
- if (info.serviceName().isEmpty())
- return;
-
- QString line = info.serviceName();
- if (!info.serviceDescription().isEmpty())
- line.append("\n\t" + info.serviceDescription());
- if (!info.serviceProvider().isEmpty())
- line.append("\n\t" + info.serviceProvider());
-
- ui->list->addItem(line);
-}
diff --git a/examples/bluetooth/btscanner/service.h b/examples/bluetooth/btscanner/service.h
deleted file mode 100644
index 93d1e12b..00000000
--- a/examples/bluetooth/btscanner/service.h
+++ /dev/null
@@ -1,80 +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: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$
-**
-****************************************************************************/
-
-#ifndef SERVICE_H
-#define SERVICE_H
-
-#include "ui_service.h"
-
-#include <QDialog>
-
-QT_FORWARD_DECLARE_CLASS(QBluetoothAddress)
-QT_FORWARD_DECLARE_CLASS(QBluetoothServiceInfo)
-QT_FORWARD_DECLARE_CLASS(QBluetoothServiceDiscoveryAgent)
-
-QT_USE_NAMESPACE
-
-class ServiceDiscoveryDialog : public QDialog
-{
- Q_OBJECT
-
-public:
- ServiceDiscoveryDialog(const QString &name, const QBluetoothAddress &address, QWidget *parent = nullptr);
- ~ServiceDiscoveryDialog();
-
-public slots:
- void addService(const QBluetoothServiceInfo&);
-
-private:
- QBluetoothServiceDiscoveryAgent *discoveryAgent;
- Ui_ServiceDiscovery *ui;
-};
-
-#endif
diff --git a/examples/bluetooth/chat/Button.qml b/examples/bluetooth/chat/Button.qml
deleted file mode 100644
index 8c0096c9..00000000
--- a/examples/bluetooth/chat/Button.qml
+++ /dev/null
@@ -1,93 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module.
-**
-** $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 QtQuick 2.2
-
-Rectangle {
- // Identifier of the item
- id: button
-
- // Attaches to the Text element's text content
- property string label
-
- // Set appearance properties
- radius: 3
- antialiasing: true
- border.width: 1
- border.color: "#35322f"
- color: "#14aaff"
- height: buttonLabel.height * 1.5
- width: buttonLabel.width * 1.5
-
- Text {
- id: buttonLabel
- anchors.centerIn: parent
- text: label // Bind the text to the parent's text
- color: "black"
- font.pointSize: 20
- }
-
- // buttonClick() is callable and a signal handler,
- // onButtonClick is automatically created
- signal buttonClick()
-
- // Define the clickable area to be the whole rectangle
- MouseArea {
- id: buttonMouseArea
- anchors.fill: parent // Stretch the area to the parent's dimension
- onClicked: buttonClick()
- }
-
-
- // Scale the button when pressed
- scale: buttonMouseArea.pressed ? 1.1 : 1.0
- // Animate the scale property change
- Behavior on scale { NumberAnimation { duration: 55 } }
-}
diff --git a/examples/bluetooth/chat/InputBox.qml b/examples/bluetooth/chat/InputBox.qml
deleted file mode 100644
index b37d9f57..00000000
--- a/examples/bluetooth/chat/InputBox.qml
+++ /dev/null
@@ -1,130 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module.
-**
-** $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 QtQuick 2.2
-
-FocusScope {
- id: focusScope
- width: 250; height: 28
-
- property string text: textInput.text
- signal clear
-
- onClear: {
- textInput.text=""
- }
-
- BorderImage {
- source: "images/lineedit-bg.png"
- width: parent.width; height: parent.height
- border { left: 4; top: 4; right: 4; bottom: 4 }
- }
-
- Text {
- id: typeSomething
- anchors.fill: parent; anchors.leftMargin: 8
- verticalAlignment: Text.AlignVCenter
- text: "Type something..."
- color: "gray"
- font.italic: true
- font.pointSize: 14
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: { focusScope.focus = true; }
- }
-
- TextInput {
- id: textInput
- anchors { left: parent.left; leftMargin: 8; right: clear.left; rightMargin: 8; verticalCenter: parent.verticalCenter }
- focus: true
- selectByMouse: true
- font.pointSize: 14
- }
-
- Image {
- id: clear
- anchors { right: parent.right; rightMargin: 8; verticalCenter: parent.verticalCenter }
- source: "images/clear.png"
- opacity: 0
-
- MouseArea {
- // allow area to grow beyond image size
- // easier to hit the area on high DPI devices
- anchors.centerIn: parent
- height:focusScope.height
- width: focusScope.height
- onClicked: {
- //toogle focus to be able to jump out of input method composer
- focusScope.focus = false;
- textInput.text = '';
- focusScope.focus = true;
- }
- }
- }
-
- states: State {
- name: "hasText"; when: (textInput.text != '' || textInput.inputMethodComposing)
- PropertyChanges { target: typeSomething; opacity: 0 }
- PropertyChanges { target: clear; opacity: 1 }
- }
-
- transitions: [
- Transition {
- from: ""; to: "hasText"
- NumberAnimation { exclude: typeSomething; properties: "opacity" }
- },
- Transition {
- from: "hasText"; to: ""
- NumberAnimation { properties: "opacity" }
- }
- ]
-}
diff --git a/examples/bluetooth/chat/Search.qml b/examples/bluetooth/chat/Search.qml
deleted file mode 100644
index 78a7f030..00000000
--- a/examples/bluetooth/chat/Search.qml
+++ /dev/null
@@ -1,107 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module.
-**
-** $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 QtQuick 2.2
-
-Rectangle {
- property bool animationRunning: true
-
- function appendText(newText) {
- searchText.text += newText
- }
- function setText(newText) {
- searchText.text = newText
- }
-
- width: searchText.width + 40;
- height: searchText.height + bluetoothImage.height + 40;
- color: "#d7d6d5"
- border.color: "black"
- border.width: 1
- radius: 5
-
- Behavior on height {
- NumberAnimation { duration: 300 }
- }
-
- Image {
- id: bluetoothImage
- source: "images/default.png"
- anchors.top: parent.top
- anchors.topMargin: 10
- anchors.horizontalCenter: parent.horizontalCenter
-
- RotationAnimation on rotation{
- id: ranimation
- target: bluetoothImage
- easing.type: Easing.InOutBack
- property: "rotation"
- from: 0
- to: 360
- duration: 2000
- loops: Animation.Infinite
- alwaysRunToEnd: true
- running: animationRunning
- }
- }
-
- Text {
- id: searchText
-
- anchors.top: bluetoothImage.bottom
- //anchors.bottom: parent.bottom
- anchors.topMargin: 10
- anchors.horizontalCenter: parent.horizontalCenter
- text: qsTr("Searching for chat service...");
- color: "black"
-
- }
-}
-
diff --git a/examples/bluetooth/chat/chat.pro b/examples/bluetooth/chat/chat.pro
deleted file mode 100644
index 36d815f9..00000000
--- a/examples/bluetooth/chat/chat.pro
+++ /dev/null
@@ -1,20 +0,0 @@
-QT = core bluetooth quick
-android: QT += androidextras #see QTBUG-61392
-SOURCES += qmlchat.cpp
-
-TARGET = qml_chat
-TEMPLATE = app
-
-RESOURCES += \
- chat.qrc
-
-OTHER_FILES += \
- chat.qml \
- InputBox.qml \
- Search.qml \
- Button.qml
-
-#DEFINES += QMLJSDEBUGGER
-
-target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/chat
-INSTALLS += target
diff --git a/examples/bluetooth/chat/chat.qml b/examples/bluetooth/chat/chat.qml
deleted file mode 100644
index 5c2818b2..00000000
--- a/examples/bluetooth/chat/chat.qml
+++ /dev/null
@@ -1,248 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module.
-**
-** $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 QtQuick 2.2
-import QtBluetooth 5.3
-
-Item {
- id: top
-
- Component.onCompleted: state = "begin"
-
- property string remoteDeviceName: ""
- property bool serviceFound: false
-
- //! [BtDiscoveryModel-1]
- BluetoothDiscoveryModel {
- id: btModel
- running: true
- discoveryMode: BluetoothDiscoveryModel.FullServiceDiscovery
- //! [BtDiscoveryModel-1]
- onRunningChanged : {
- if (!btModel.running && top.state == "begin" && !serviceFound) {
- searchBox.animationRunning = false;
- searchBox.appendText("\nNo service found. \n\nPlease start server\nand restart app.")
- }
- }
-
- onErrorChanged: {
- if (error != BluetoothDiscoveryModel.NoError && !btModel.running) {
- searchBox.animationRunning = false
- searchBox.appendText("\n\nDiscovery failed.\nPlease ensure Bluetooth is available.")
- }
- }
-
- //! [BtDiscoveryModel-2]
- onServiceDiscovered: {
- if (serviceFound)
- return
- serviceFound = true
- console.log("Found new service " + service.deviceAddress + " " + service.deviceName + " " + service.serviceName);
- searchBox.appendText("\nConnecting to server...")
- remoteDeviceName = service.deviceName
- socket.setService(service)
- }
- //! [BtDiscoveryModel-2]
- //! [BtDiscoveryModel-3]
- uuidFilter: targetUuid //e8e10f95-1a70-4b27-9ccf-02010264e9c8
- }
- //! [BtDiscoveryModel-3]
-
- //! [BluetoothSocket-1]
- BluetoothSocket {
- id: socket
- connected: true
-
- onSocketStateChanged: {
- switch (socketState) {
- case BluetoothSocket.Unconnected:
- case BluetoothSocket.NoServiceSet:
- searchBox.animationRunning = false;
- searchBox.setText("\nNo connection. \n\nPlease restart app.");
- top.state = "begin";
- break;
- case BluetoothSocket.Connected:
- console.log("Connected to server ");
- top.state = "chatActive"; // move to chat UI
- break;
- case BluetoothSocket.Connecting:
- case BluetoothSocket.ServiceLookup:
- case BluetoothSocket.Closing:
- case BluetoothSocket.Listening:
- case BluetoothSocket.Bound:
- break;
- }
- }
- //! [BluetoothSocket-1]
- //! [BluetoothSocket-3]
- onStringDataChanged: {
- console.log("Received data: " )
- var data = remoteDeviceName + ": " + socket.stringData;
- data = data.substring(0, data.indexOf('\n'))
- chatContent.append({content: data})
- //! [BluetoothSocket-3]
- console.log(data);
- //! [BluetoothSocket-4]
- }
- //! [BluetoothSocket-4]
- //! [BluetoothSocket-2]
- //...
- }
- //! [BluetoothSocket-2]
-
- ListModel {
- id: chatContent
- ListElement {
- content: "Connected to chat server"
- }
- }
-
-
- Rectangle {
- id: background
- z: 0
- anchors.fill: parent
- color: "#5d5b59"
- }
-
- Search {
- id: searchBox
- anchors.centerIn: top
- opacity: 1
- }
-
- Rectangle {
- id: chatBox
- opacity: 0
- anchors.centerIn: top
-
- color: "#5d5b59"
- border.color: "black"
- border.width: 1
- radius: 5
- anchors.fill: parent
-
- function sendMessage()
- {
- // toogle focus to force end of input method composer
- var hasFocus = input.focus;
- input.focus = false;
-
- var data = input.text
- input.clear()
- chatContent.append({content: "Me: " + data})
- //! [BluetoothSocket-5]
- socket.stringData = data
- //! [BluetoothSocket-5]
- chatView.positionViewAtEnd()
-
- input.focus = hasFocus;
- }
-
- Item {
- anchors.fill: parent
- anchors.margins: 10
-
- InputBox {
- id: input
- Keys.onReturnPressed: chatBox.sendMessage()
- height: sendButton.height
- width: parent.width - sendButton.width - 15
- anchors.left: parent.left
- }
-
- Button {
- id: sendButton
- anchors.right: parent.right
- label: "Send"
- onButtonClick: chatBox.sendMessage()
- }
-
-
- Rectangle {
- height: parent.height - input.height - 15
- width: parent.width;
- color: "#d7d6d5"
- anchors.bottom: parent.bottom
- border.color: "black"
- border.width: 1
- radius: 5
-
- ListView {
- id: chatView
- width: parent.width-5
- height: parent.height-5
- anchors.centerIn: parent
- model: chatContent
- clip: true
- delegate: Component {
- Text {
- font.pointSize: 14
- text: modelData
- }
- }
- }
- }
- }
- }
-
- states: [
- State {
- name: "begin"
- PropertyChanges { target: searchBox; opacity: 1 }
- PropertyChanges { target: chatBox; opacity: 0 }
- },
- State {
- name: "chatActive"
- PropertyChanges { target: searchBox; opacity: 0 }
- PropertyChanges { target: chatBox; opacity: 1 }
- }
- ]
-}
diff --git a/examples/bluetooth/chat/chat.qrc b/examples/bluetooth/chat/chat.qrc
deleted file mode 100644
index f2219f5b..00000000
--- a/examples/bluetooth/chat/chat.qrc
+++ /dev/null
@@ -1,11 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>chat.qml</file>
- <file>images/clear.png</file>
- <file>images/lineedit-bg.png</file>
- <file>InputBox.qml</file>
- <file>images/default.png</file>
- <file>Search.qml</file>
- <file>Button.qml</file>
- </qresource>
-</RCC>
diff --git a/examples/bluetooth/chat/doc/images/chat-view.png b/examples/bluetooth/chat/doc/images/chat-view.png
deleted file mode 100644
index 81785fa2..00000000
--- a/examples/bluetooth/chat/doc/images/chat-view.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/chat/doc/src/chat.qdoc b/examples/bluetooth/chat/doc/src/chat.qdoc
deleted file mode 100644
index 6fdf9b70..00000000
--- a/examples/bluetooth/chat/doc/src/chat.qdoc
+++ /dev/null
@@ -1,84 +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$
-**
-****************************************************************************/
-
-/*!
- \example chat
- \title Bluetooth QML Chat Example
- \brief An example demonstrating communication through Bluetooth QML API.
-
- \e {Bluetooth QML Chat} example shows how to use the \l{Qt Bluetooth} QML API to communicate
- with another application on a remote device using Bluetooth.
-
- \image chat-view.png
-
- The Bluetooth QML Chat example implements a simple chat program between two parties. The
- application acts as client and attempts to connect to a Bluetooth socket server. It uses
- the \l BluetoothDiscoveryModel type to find the server and \l BluetoothSocket type to
- facilitate the data exchange.
-
- \include examples-run.qdocinc
-
- The example only works in connection with the \l {btchat}{Bluetooth Chat Example}.
- The Bluetooth Chat example launches the chat service and advertises it via the
- Bluetooth SDP protocol. It is important that the device running the Bluetooth Chat
- example actively advertises its SDP services.
- This can be checked using the \l QBluetoothLocalDevice::hostMode property.
-
- \section1 Interacting with the Server
-
- The example application immediately starts the service discovery using the
- \l BluetoothDiscoveryModel type:
-
- \snippet chat/chat.qml BtDiscoveryModel-1
- \snippet chat/chat.qml BtDiscoveryModel-3
-
- The \l {BluetoothDiscoveryModel::uuidFilter}{uuidFilter} property is used to only search for
- the chat server UUID and the \l {BluetoothDiscoveryModel::running}{running}
- property activates the search. Once a service with a matching UUID is found the model emits the
- \l {BluetoothDiscoveryModel::serviceDiscovered}{serviceDiscovered(BluetoothService)} signal.
-
- \snippet chat/chat.qml BtDiscoveryModel-2
-
- The \l BluetoothService type encapsulates the details of the found chat server, such as the
- \l {BluetoothService::serviceName}{name} and \l {BluetoothService::serviceDescription}{description} of the
- service, as well as the \l{BluetoothService::deviceName}{name} and \l {BluetoothService::deviceAddress}{address}
- of the Bluetooth device offering the chat server. It is passed to the \l BluetoothSocket
- to establish the connection.
-
- Once the connection is established the socket's state is managed as follows:
- \snippet chat/chat.qml BluetoothSocket-1
- \snippet chat/chat.qml BluetoothSocket-2
-
- The payload is received via the \l {BluetoothSocket::stringData}{stringData} property:
-
- \snippet chat/chat.qml BluetoothSocket-3
- \snippet chat/chat.qml BluetoothSocket-4
-
- And sent by setting the same property:
-
- \snippet chat/chat.qml BluetoothSocket-5
-*/
diff --git a/examples/bluetooth/chat/images/clear.png b/examples/bluetooth/chat/images/clear.png
deleted file mode 100644
index c20a9cfb..00000000
--- a/examples/bluetooth/chat/images/clear.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/chat/images/default.png b/examples/bluetooth/chat/images/default.png
deleted file mode 100644
index a1a74af5..00000000
--- a/examples/bluetooth/chat/images/default.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/chat/images/lineedit-bg.png b/examples/bluetooth/chat/images/lineedit-bg.png
deleted file mode 100644
index e0d93cd1..00000000
--- a/examples/bluetooth/chat/images/lineedit-bg.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/chat/qmlchat.cpp b/examples/bluetooth/chat/qmlchat.cpp
deleted file mode 100644
index 6c8d2fa7..00000000
--- a/examples/bluetooth/chat/qmlchat.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module.
-**
-** $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$
-**
-****************************************************************************/
-
-#include <QtGui/QGuiApplication>
-#include <QtQuick/QQuickView>
-#include <QtQml/QQmlEngine>
-#include <QtQml/QQmlContext>
-#include <QDebug>
-#include <QBluetoothLocalDevice>
-#include <QtCore/QLoggingCategory>
-#ifdef Q_OS_ANDROID
-#include <QtAndroidExtras/QtAndroid>
-#endif
-
-int main(int argc, char *argv[])
-{
- //QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
- QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
- QGuiApplication application(argc, argv);
-
- QList<QBluetoothHostInfo> infos = QBluetoothLocalDevice::allDevices();
- if (infos.isEmpty())
- qWarning() << "Missing Bluetooth local device. "
- "Example will not work properly.";
-
- const QString mainQmlApp = QLatin1String("qrc:/chat.qml");
- QQuickView view;
-
-#ifdef Q_OS_ANDROID
- //workaround for Android's SDP discovery bug (see QTBUG-61392)
- QString uuid;
- if (QtAndroid::androidSdkVersion() >= 23)
- uuid = QStringLiteral("c8e96402-0102-cf9c-274b-701a950fe1e8");
- else
- uuid = QStringLiteral("e8e10f95-1a70-4b27-9ccf-02010264e9c8");
-#else
- const QString uuid(QStringLiteral("e8e10f95-1a70-4b27-9ccf-02010264e9c8"));
-#endif
-
- view.engine()->rootContext()->setContextProperty(QStringLiteral("targetUuid"), uuid);
- view.setSource(QUrl(mainQmlApp));
- view.setResizeMode(QQuickView::SizeRootObjectToView);
- // Qt.quit() called in embedded .qml by default only emits
- // quit() signal, so do this (optionally use Qt.exit()).
- QObject::connect(view.engine(), SIGNAL(quit()), qApp, SLOT(quit()));
- view.setGeometry(QRect(100, 100, 360, 480));
- view.show();
- return application.exec();
-}
diff --git a/examples/bluetooth/heartrate-game/App.qml b/examples/bluetooth/heartrate-game/App.qml
new file mode 100644
index 00000000..db6aa714
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/App.qml
@@ -0,0 +1,99 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Layouts
+import HeartRateGame
+
+Item {
+ id: app
+
+ required property ConnectionHandler connectionHandler
+ required property DeviceFinder deviceFinder
+ required property DeviceHandler deviceHandler
+
+ anchors.fill: parent
+ opacity: 0.0
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: 500
+ }
+ }
+
+ property int __currentIndex: 0
+
+ TitleBar {
+ id: titleBar
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ currentIndex: app.__currentIndex
+
+ onTitleClicked: (index) => {
+ if (index < app.__currentIndex)
+ app.__currentIndex = index
+ }
+ }
+
+ StackLayout {
+ id: pageStack
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: titleBar.bottom
+ anchors.bottom: parent.bottom
+ currentIndex: app.__currentIndex
+
+ Connect {
+ connectionHandler: app.connectionHandler
+ deviceFinder: app.deviceFinder
+ deviceHandler: app.deviceHandler
+
+ onShowMeasurePage: app.__currentIndex = 1
+ }
+ Measure {
+ id: measurePage
+ deviceHandler: app.deviceHandler
+
+ onShowStatsPage: app.__currentIndex = 2
+ }
+ Stats {
+ deviceHandler: app.deviceHandler
+ }
+
+ onCurrentIndexChanged: {
+ if (currentIndex === 0)
+ measurePage.close()
+ }
+ }
+
+ BluetoothAlarmDialog {
+ id: btAlarmDialog
+ anchors.fill: parent
+ visible: !app.connectionHandler.alive || permissionError
+ permissionError: !app.connectionHandler.hasPermission
+ }
+
+ Keys.onReleased: (event) => {
+ switch (event.key) {
+ case Qt.Key_Escape:
+ case Qt.Key_Back:
+ {
+ if (app.__currentIndex > 0) {
+ app.__currentIndex = app.__currentIndex - 1
+ event.accepted = true
+ } else {
+ Qt.quit()
+ }
+ break
+ }
+ default:
+ break
+ }
+ }
+
+ Component.onCompleted: {
+ forceActiveFocus()
+ app.opacity = 1.0
+ }
+}
diff --git a/examples/bluetooth/heartrate-game/BluetoothAlarmDialog.qml b/examples/bluetooth/heartrate-game/BluetoothAlarmDialog.qml
new file mode 100644
index 00000000..5cc8f393
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/BluetoothAlarmDialog.qml
@@ -0,0 +1,80 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+Item {
+ id: root
+
+ property bool permissionError: false
+
+ anchors.fill: parent
+
+ Rectangle {
+ anchors.fill: parent
+ color: "black"
+ opacity: 0.9
+ }
+
+ MouseArea {
+ id: eventEater
+ }
+
+ Rectangle {
+ id: dialogFrame
+
+ anchors.centerIn: parent
+ width: parent.width * 0.8
+ height: parent.height * 0.6
+ border.color: "#454545"
+ color: GameSettings.backgroundColor
+ radius: width * 0.05
+
+ Item {
+ id: dialogContainer
+ anchors.fill: parent
+ anchors.margins: parent.width*0.05
+
+ Image {
+ id: offOnImage
+ anchors.left: quitButton.left
+ anchors.right: quitButton.right
+ anchors.top: parent.top
+ height: GameSettings.heightForWidth(width, sourceSize)
+ source: "images/bt_off_to_on.png"
+ }
+
+ Text {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: offOnImage.bottom
+ anchors.bottom: quitButton.top
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ wrapMode: Text.WordWrap
+ font.pixelSize: GameSettings.smallFontSize
+ color: GameSettings.textColor
+ text: root.permissionError
+ ? qsTr("Bluetooth permissions are not granted. Please grant the permissions in the system settings.")
+ : qsTr("This application cannot be used without Bluetooth. Please switch Bluetooth ON to continue.")
+ }
+
+ GameButton {
+ id: quitButton
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: dialogContainer.width * 0.6
+ height: GameSettings.buttonHeight
+ onClicked: Qt.quit()
+
+ Text {
+ anchors.centerIn: parent
+ color: GameSettings.textColor
+ font.pixelSize: GameSettings.microFontSize
+ text: qsTr("QUIT")
+ }
+ }
+ }
+ }
+}
+
diff --git a/examples/bluetooth/heartrate-game/BottomLine.qml b/examples/bluetooth/heartrate-game/BottomLine.qml
new file mode 100644
index 00000000..80fdaa8c
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/BottomLine.qml
@@ -0,0 +1,11 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+Rectangle {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ width: parent.width
+ height: parent.height * 0.05
+}
diff --git a/examples/bluetooth/heartrate-game/CMakeLists.txt b/examples/bluetooth/heartrate-game/CMakeLists.txt
new file mode 100644
index 00000000..7677bcb4
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/CMakeLists.txt
@@ -0,0 +1,91 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(heartrate-game LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/bluetooth/heartrate-game")
+
+find_package(Qt6 REQUIRED COMPONENTS Bluetooth Core Gui Qml Quick)
+
+qt_standard_project_setup(REQUIRES 6.5)
+
+qt_add_executable(heartrate-game
+ heartrate-global.h
+ main.cpp
+)
+
+set_target_properties(heartrate-game PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(heartrate-game PRIVATE
+ Qt6::Bluetooth
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Qml
+ Qt6::Quick
+)
+
+set_source_files_properties(GameSettings.qml PROPERTIES
+ QT_QML_SINGLETON_TYPE TRUE
+)
+
+qt_add_qml_module(heartrate-game
+ URI HeartRateGame
+ VERSION 1.0
+ SOURCES
+ bluetoothbaseclass.cpp bluetoothbaseclass.h
+ connectionhandler.cpp connectionhandler.h
+ devicefinder.cpp devicefinder.h
+ devicehandler.cpp devicehandler.h
+ deviceinfo.cpp deviceinfo.h
+ QML_FILES
+ App.qml
+ BluetoothAlarmDialog.qml
+ BottomLine.qml
+ Connect.qml
+ GameButton.qml
+ GamePage.qml
+ GameSettings.qml
+ Measure.qml
+ SplashScreen.qml
+ Stats.qml
+ StatsLabel.qml
+ TitleBar.qml
+ Main.qml
+ RESOURCES
+ images/alert.svg
+ images/bluetooth.svg
+ images/bt_off_to_on.png
+ images/clock.svg
+ images/heart.png
+ images/logo.png
+ images/progress.svg
+ images/search.svg
+)
+
+if (APPLE)
+ # Using absolute path for shared plist files is a Ninja bug workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../shared ABSOLUTE)
+ if (IOS)
+ set_target_properties(heartrate-game PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.cmake.ios.plist"
+ )
+ else()
+ set_target_properties(heartrate-game PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.cmake.macos.plist"
+ )
+ endif()
+endif()
+
+install(TARGETS heartrate-game
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/bluetooth/heartrate-game/Connect.qml b/examples/bluetooth/heartrate-game/Connect.qml
new file mode 100644
index 00000000..ed5fb63d
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/Connect.qml
@@ -0,0 +1,155 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+import QtQuick
+import HeartRateGame
+
+GamePage {
+ id: connectPage
+
+ required property ConnectionHandler connectionHandler
+ required property DeviceFinder deviceFinder
+ required property DeviceHandler deviceHandler
+
+ signal showMeasurePage
+
+ errorMessage: deviceFinder.error
+ infoMessage: deviceFinder.info
+ iconType: deviceFinder.icon
+
+ Text {
+ id: viewCaption
+ anchors {
+ top: parent.top
+ topMargin: GameSettings.fieldMargin + connectPage.messageHeight
+ horizontalCenter: parent.horizontalCenter
+ }
+ width: parent.width - GameSettings.fieldMargin * 2
+ height: GameSettings.fieldHeight
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ color: GameSettings.textColor
+ font.pixelSize: GameSettings.smallFontSize
+ text: qsTr("Found Devices")
+ }
+
+ Rectangle {
+ id: viewContainer
+ anchors.top: viewCaption.bottom
+ // only BlueZ platform has address type selection
+ anchors.bottom: connectPage.connectionHandler.requiresAddressType ? addressTypeButton.top
+ : searchButton.top
+ anchors.bottomMargin: GameSettings.fieldMargin
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: parent.width - GameSettings.fieldMargin * 2
+ color: GameSettings.viewColor
+ radius: GameSettings.buttonRadius
+
+ ListView {
+ id: devices
+ anchors.fill: parent
+ model: connectPage.deviceFinder.devices
+ clip: true
+
+ delegate: Rectangle {
+ id: box
+
+ required property int index
+ required property var modelData
+
+ height: GameSettings.fieldHeight * 1.2
+ width: devices.width
+ color: index % 2 === 0 ? GameSettings.delegate1Color : GameSettings.delegate2Color
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ connectPage.deviceFinder.connectToService(box.modelData.deviceAddress)
+ connectPage.showMeasurePage()
+ }
+ }
+
+ Text {
+ id: device
+ font.pixelSize: GameSettings.microFontSize
+ text: box.modelData.deviceName
+ anchors.top: parent.top
+ anchors.topMargin: parent.height * 0.15
+ anchors.leftMargin: parent.height * 0.15
+ anchors.left: parent.left
+ color: GameSettings.textColor
+ }
+
+ Text {
+ id: deviceAddress
+ font.pixelSize: GameSettings.microFontSize
+ text: box.modelData.deviceAddress
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: parent.height * 0.15
+ anchors.rightMargin: parent.height * 0.15
+ anchors.right: parent.right
+ color: Qt.darker(GameSettings.textColor)
+ }
+ }
+ }
+ }
+
+ GameButton {
+ id: addressTypeButton
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: searchButton.top
+ anchors.bottomMargin: GameSettings.fieldMargin * 0.5
+ width: viewContainer.width
+ height: GameSettings.fieldHeight
+ visible: connectPage.connectionHandler.requiresAddressType // only required on BlueZ
+ state: "public"
+ onClicked: state === "public" ? state = "random" : state = "public"
+
+ states: [
+ State {
+ name: "public"
+ PropertyChanges {
+ addressTypeText.text: qsTr("PUBLIC ADDRESS")
+ }
+ PropertyChanges {
+ connectPage.deviceHandler.addressType: DeviceHandler.PublicAddress
+ }
+ },
+ State {
+ name: "random"
+ PropertyChanges {
+ addressTypeText.text: qsTr("RANDOM ADDRESS")
+ }
+ PropertyChanges {
+ connectPage.deviceHandler.addressType: DeviceHandler.RandomAddress
+ }
+ }
+ ]
+
+ Text {
+ id: addressTypeText
+ anchors.centerIn: parent
+ font.pixelSize: GameSettings.microFontSize
+ color: GameSettings.textDarkColor
+ }
+ }
+
+ GameButton {
+ id: searchButton
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: GameSettings.fieldMargin
+ width: viewContainer.width
+ height: GameSettings.fieldHeight
+ enabled: !connectPage.deviceFinder.scanning
+ onClicked: connectPage.deviceFinder.startSearch()
+
+ Text {
+ anchors.centerIn: parent
+ font.pixelSize: GameSettings.microFontSize
+ text: qsTr("START SEARCH")
+ color: GameSettings.textDarkColor
+ }
+ }
+}
diff --git a/examples/bluetooth/heartrate-game/GameButton.qml b/examples/bluetooth/heartrate-game/GameButton.qml
new file mode 100644
index 00000000..8e876010
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/GameButton.qml
@@ -0,0 +1,39 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+Rectangle {
+ id: button
+ color: baseColor
+ onEnabledChanged: checkColor()
+ radius: GameSettings.buttonRadius
+
+ property color baseColor: GameSettings.buttonColor
+ property color pressedColor: GameSettings.buttonPressedColor
+ property color disabledColor: GameSettings.disabledButtonColor
+
+ signal clicked
+
+ function checkColor() {
+ if (!button.enabled) {
+ button.color = disabledColor
+ } else {
+ if (mouseArea.containsPress)
+ button.color = pressedColor
+ else
+ button.color = baseColor
+ }
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ onPressed: button.checkColor()
+ onReleased: button.checkColor()
+ onClicked: {
+ button.checkColor()
+ button.clicked()
+ }
+ }
+}
diff --git a/examples/bluetooth/heartrate-game/GamePage.qml b/examples/bluetooth/heartrate-game/GamePage.qml
new file mode 100644
index 00000000..ff81e9cd
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/GamePage.qml
@@ -0,0 +1,77 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import HeartRateGame
+
+Item {
+ id: page
+
+ property string errorMessage: ""
+ property string infoMessage: ""
+ property real messageHeight: msg.height
+ property bool hasError: errorMessage != ""
+ property bool hasInfo: infoMessage != ""
+ property int iconType: BluetoothBaseClass.IconNone
+
+ function iconTypeToName(icon: int) : string {
+ switch (icon) {
+ case BluetoothBaseClass.IconNone: return ""
+ case BluetoothBaseClass.IconBluetooth: return "images/bluetooth.svg"
+ case BluetoothBaseClass.IconError: return "images/alert.svg"
+ case BluetoothBaseClass.IconProgress: return "images/progress.svg"
+ case BluetoothBaseClass.IconSearch: return "images/search.svg"
+ }
+ }
+
+ Rectangle {
+ id: msg
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ topMargin: GameSettings.fieldMargin * 0.5
+ leftMargin: GameSettings.fieldMargin
+ rightMargin: GameSettings.fieldMargin
+ }
+ height: GameSettings.fieldHeight
+ radius: GameSettings.buttonRadius
+ color: page.hasError ? GameSettings.errorColor : "transparent"
+ visible: page.hasError || page.hasInfo
+ border {
+ width: 1
+ color: page.hasError ? GameSettings.errorColor : GameSettings.infoColor
+ }
+
+ Image {
+ id: icon
+ readonly property int imgSize: GameSettings.fieldHeight * 0.5
+ anchors {
+ left: parent.left
+ leftMargin: GameSettings.fieldMargin * 0.5
+ verticalCenter: parent.verticalCenter
+ }
+ visible: source.toString() !== ""
+ source: page.iconTypeToName(page.iconType)
+ sourceSize.width: imgSize
+ sourceSize.height: imgSize
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Text {
+ id: error
+ anchors {
+ fill: parent
+ leftMargin: GameSettings.fieldMargin + icon.width
+ rightMargin: GameSettings.fieldMargin + icon.width
+ }
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ minimumPixelSize: 5
+ font.pixelSize: GameSettings.microFontSize
+ fontSizeMode: Text.Fit
+ color: page.hasError ? GameSettings.textColor : GameSettings.infoColor
+ text: page.hasError ? page.errorMessage : page.infoMessage
+ }
+ }
+}
diff --git a/examples/bluetooth/heartrate-game/GameSettings.qml b/examples/bluetooth/heartrate-game/GameSettings.qml
new file mode 100644
index 00000000..4032787c
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/GameSettings.qml
@@ -0,0 +1,61 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma Singleton
+import QtQuick
+
+QtObject {
+ property int wHeight
+ property int wWidth
+
+ // Colors
+ readonly property color lightGreenColor: "#80ebb6"
+ readonly property color backgroundColor: "#2c3038"
+ readonly property color buttonColor: "#2cde85"
+ readonly property color buttonPressedColor: lightGreenColor
+ readonly property color disabledButtonColor: "#808080"
+ readonly property color viewColor: "#262626"
+ readonly property color delegate1Color: "#262626"
+ readonly property color delegate2Color: "#404040"
+ readonly property color textColor: "#ffffff"
+ readonly property color textDarkColor: "#0d0d0d"
+ readonly property color textInfoColor: lightGreenColor
+ readonly property color sliderColor: "#00414a"
+ readonly property color sliderBorderColor: lightGreenColor
+ readonly property color sliderTextColor: lightGreenColor
+ readonly property color errorColor: "#ba3f62"
+ readonly property color infoColor: lightGreenColor
+ readonly property color titleColor: "#202227"
+ readonly property color selectedTitleColor: "#19545c"
+ readonly property color hoverTitleColor: Qt.rgba(selectedTitleColor.r,
+ selectedTitleColor.g,
+ selectedTitleColor.b,
+ 0.25)
+ readonly property color bottomLineColor: "#e6e6e6"
+ readonly property color heartRateColor: "#f80067"
+
+ // All the fonts are given for the window of certain size.
+ // Resizing the window changes all the fonts accordingly
+ readonly property int defaultSize: 500
+ readonly property real fontScaleFactor: Math.min(wWidth, wHeight) / defaultSize
+
+ // Font sizes
+ readonly property real microFontSize: 16 * fontScaleFactor
+ readonly property real tinyFontSize: 20 * fontScaleFactor
+ readonly property real smallFontSize: 24 * fontScaleFactor
+ readonly property real mediumFontSize: 32 * fontScaleFactor
+ readonly property real bigFontSize: 36 * fontScaleFactor
+ readonly property real largeFontSize: 54 * fontScaleFactor
+ readonly property real hugeFontSize: 128 * fontScaleFactor
+
+ // Some other values
+ property real fieldHeight: wHeight * 0.08
+ property real fieldMargin: fieldHeight * 0.5
+ property real buttonHeight: wHeight * 0.08
+ property real buttonRadius: buttonHeight * 0.1
+
+ // Some help functions
+ function heightForWidth(w, ss) {
+ return w / ss.width * ss.height
+ }
+}
diff --git a/examples/bluetooth/heartrate-game/Main.qml b/examples/bluetooth/heartrate-game/Main.qml
new file mode 100644
index 00000000..e26f9b00
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/Main.qml
@@ -0,0 +1,71 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Window
+import HeartRateGame
+
+Window {
+ id: wroot
+ visible: true
+ width: 720 * .7
+ height: 1240 * .7
+ title: qsTr("HeartRateGame")
+ color: GameSettings.backgroundColor
+
+ required property ConnectionHandler connectionHandler
+ required property DeviceFinder deviceFinder
+ required property DeviceHandler deviceHandler
+
+ Component.onCompleted: {
+ GameSettings.wWidth = Qt.binding(function () {
+ return width
+ })
+ GameSettings.wHeight = Qt.binding(function () {
+ return height
+ })
+ }
+
+ Loader {
+ id: splashLoader
+ anchors.fill: parent
+ asynchronous: false
+ visible: true
+
+ sourceComponent: SplashScreen {
+ appIsReady: appLoader.status === Loader.Ready
+ onReadyChanged: {
+ if (ready) {
+ appLoader.visible = true
+ splashLoader.visible = false
+ splashLoader.active = false
+ }
+ }
+ }
+
+ onStatusChanged: {
+ if (status === Loader.Ready)
+ appLoader.active = true
+ }
+ }
+
+ Loader {
+ id: appLoader
+ anchors.fill: parent
+ active: false
+ asynchronous: true
+ visible: false
+
+ sourceComponent: App {
+ connectionHandler: wroot.connectionHandler
+ deviceFinder: wroot.deviceFinder
+ deviceHandler: wroot.deviceHandler
+ }
+
+ onStatusChanged: {
+ if (status === Loader.Error)
+ Qt.quit()
+ }
+ }
+}
diff --git a/examples/bluetooth/heartrate-game/Measure.qml b/examples/bluetooth/heartrate-game/Measure.qml
new file mode 100644
index 00000000..04ebeb09
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/Measure.qml
@@ -0,0 +1,325 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import HeartRateGame
+
+GamePage {
+ id: measurePage
+
+ required property DeviceHandler deviceHandler
+
+ errorMessage: deviceHandler.error
+ infoMessage: deviceHandler.info
+ iconType: deviceHandler.icon
+
+ property real __timeCounter: 0
+ property real __maxTimeCount: 60
+
+ readonly property string relaxText: qsTr("Relax!")
+ readonly property string startText: qsTr("When you are ready,\npress Start.")
+ readonly property string instructionText: qsTr("You have %1s time to increase heart\nrate as much as possible.").arg(__maxTimeCount)
+ readonly property string goodLuckText: qsTr("Good luck!")
+
+ signal showStatsPage
+
+ function close() {
+ deviceHandler.stopMeasurement()
+ deviceHandler.disconnectService()
+ }
+
+ function start() {
+ if (!deviceHandler.measuring) {
+ __timeCounter = 0
+ deviceHandler.startMeasurement()
+ }
+ }
+
+ function stop() {
+ if (deviceHandler.measuring)
+ deviceHandler.stopMeasurement()
+
+ measurePage.showStatsPage()
+ }
+
+ Timer {
+ id: measureTimer
+ interval: 1000
+ running: measurePage.deviceHandler.measuring
+ repeat: true
+ onTriggered: {
+ measurePage.__timeCounter++
+ if (measurePage.__timeCounter >= measurePage.__maxTimeCount)
+ measurePage.stop()
+ }
+ }
+
+ Column {
+ anchors.centerIn: parent
+ spacing: GameSettings.fieldHeight * 0.5
+
+ Rectangle {
+ id: circle
+
+ readonly property bool hintVisible: !measurePage.deviceHandler.measuring
+ readonly property real innerSpacing: Math.min(width * 0.05, 25)
+
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: Math.min(measurePage.width, measurePage.height - GameSettings.fieldHeight * 4)
+ - 2 * GameSettings.fieldMargin
+ height: width
+ radius: width * 0.5
+ color: GameSettings.viewColor
+
+ Text {
+ id: relaxTextBox
+ anchors {
+ bottom: startTextBox.top
+ bottomMargin: parent.innerSpacing
+ horizontalCenter: parent.horizontalCenter
+ }
+ width: parent.width * 0.6
+ height: parent.height * 0.1
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: measurePage.relaxText
+ visible: circle.hintVisible
+ color: GameSettings.textColor
+ fontSizeMode: Text.Fit
+ font.pixelSize: GameSettings.smallFontSize
+ font.bold: true
+ }
+
+ Text {
+ id: startTextBox
+ anchors {
+ bottom: heart.top
+ bottomMargin: parent.innerSpacing
+ horizontalCenter: parent.horizontalCenter
+ }
+ width: parent.width * 0.8
+ height: parent.height * 0.15
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: measurePage.startText
+ visible: circle.hintVisible
+ color: GameSettings.textColor
+ fontSizeMode: Text.Fit
+ font.pixelSize: GameSettings.tinyFontSize
+ }
+
+ Text {
+ id: measureTextBox
+ anchors {
+ bottom: heart.top
+ horizontalCenter: parent.horizontalCenter
+ }
+ width: parent.width * 0.7
+ height: parent.height * 0.35
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: measurePage.deviceHandler.hr
+ visible: measurePage.deviceHandler.measuring
+ color: GameSettings.heartRateColor
+ fontSizeMode: Text.Fit
+ font.pixelSize: GameSettings.hugeFontSize
+ font.bold: true
+ }
+
+ Image {
+ id: heart
+ anchors.centerIn: circle
+ width: parent.width * 0.2
+ height: width
+ fillMode: Image.PreserveAspectFit
+ source: "images/heart.png"
+ smooth: true
+ antialiasing: true
+
+ SequentialAnimation {
+ id: heartAnim
+ running: measurePage.deviceHandler.measuring
+ loops: Animation.Infinite
+ alwaysRunToEnd: true
+ PropertyAnimation {
+ target: heart
+ property: "scale"
+ to: 1.4
+ duration: 500
+ easing.type: Easing.InQuad
+ }
+ PropertyAnimation {
+ target: heart
+ property: "scale"
+ to: 1.0
+ duration: 500
+ easing.type: Easing.OutQuad
+ }
+ }
+ }
+
+ Text {
+ id: instructionTextBox
+ anchors {
+ top: heart.bottom
+ topMargin: parent.innerSpacing
+ horizontalCenter: parent.horizontalCenter
+ }
+ width: parent.width * 0.8
+ height: parent.height * 0.15
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: measurePage.instructionText
+ visible: circle.hintVisible
+ color: GameSettings.textColor
+ fontSizeMode: Text.Fit
+ font.pixelSize: GameSettings.tinyFontSize
+ }
+
+ Text {
+ id: goodLuckBox
+ anchors {
+ top: instructionTextBox.bottom
+ topMargin: parent.innerSpacing
+ horizontalCenter: parent.horizontalCenter
+ }
+ width: parent.width * 0.6
+ height: parent.height * 0.1
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: measurePage.goodLuckText
+ visible: circle.hintVisible
+ color: GameSettings.textColor
+ fontSizeMode: Text.Fit
+ font.pixelSize: GameSettings.smallFontSize
+ font.bold: true
+ }
+
+ Item {
+ id: minMaxContainer
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: parent.width * 0.7
+ height: parent.height * 0.15
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: parent.height * 0.16
+ visible: measurePage.deviceHandler.measuring
+
+ Text {
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width * 0.35
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ text: measurePage.deviceHandler.minHR
+ color: GameSettings.textColor
+ fontSizeMode: Text.Fit
+ font.pixelSize: GameSettings.largeFontSize
+
+ Text {
+ anchors.left: parent.left
+ anchors.bottom: parent.top
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ width: parent.width
+ fontSizeMode: Text.Fit
+ font.pixelSize: GameSettings.mediumFontSize
+ color: parent.color
+ text: "MIN"
+ }
+ }
+
+ Text {
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ width: parent.width * 0.35
+ text: measurePage.deviceHandler.maxHR
+ color: GameSettings.textColor
+ fontSizeMode: Text.Fit
+ font.pixelSize: GameSettings.largeFontSize
+
+ Text {
+ anchors.right: parent.right
+ anchors.bottom: parent.top
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ width: parent.width
+ fontSizeMode: Text.Fit
+ font.pixelSize: GameSettings.mediumFontSize
+ color: parent.color
+ text: "MAX"
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ id: timeSlider
+ color: GameSettings.viewColor
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: circle.width
+ height: GameSettings.fieldHeight
+ radius: GameSettings.buttonRadius
+ border {
+ width: 1
+ color: GameSettings.sliderBorderColor
+ }
+
+ Rectangle {
+ anchors {
+ top: parent.top
+ topMargin: parent.border.width
+ left: parent.left
+ leftMargin: parent.border.width
+ }
+ height: parent.height - 2 * parent.border.width
+ width: Math.min(1.0, measurePage.__timeCounter / measurePage.__maxTimeCount)
+ * (parent.width - 2 * parent.border.width)
+ radius: parent.radius
+ color: GameSettings.sliderColor
+ }
+
+ Image {
+ readonly property int imgSize: GameSettings.fieldHeight * 0.5
+ anchors {
+ verticalCenter: parent.verticalCenter
+ left: parent.left
+ leftMargin: GameSettings.fieldMargin * 0.5
+ }
+ source: "images/clock.svg"
+ sourceSize.width: imgSize
+ sourceSize.height: imgSize
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Text {
+ anchors.centerIn: parent
+ color: GameSettings.sliderTextColor
+ text: (measurePage.__maxTimeCount - measurePage.__timeCounter).toFixed(0) + " s"
+ font.pixelSize: GameSettings.smallFontSize
+ }
+ }
+ }
+
+ GameButton {
+ id: startButton
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: GameSettings.fieldMargin
+ width: circle.width
+ height: GameSettings.fieldHeight
+ enabled: measurePage.deviceHandler.alive && !measurePage.deviceHandler.measuring
+ && measurePage.errorMessage === ""
+ radius: GameSettings.buttonRadius
+
+ onClicked: measurePage.start()
+
+ Text {
+ anchors.centerIn: parent
+ font.pixelSize: GameSettings.microFontSize
+ text: qsTr("START")
+ color: GameSettings.textDarkColor
+ }
+ }
+}
diff --git a/examples/bluetooth/heartrate-game/SplashScreen.qml b/examples/bluetooth/heartrate-game/SplashScreen.qml
new file mode 100644
index 00000000..918319d7
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/SplashScreen.qml
@@ -0,0 +1,30 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import HeartRateGame
+
+Item {
+ id: root
+
+ property bool appIsReady: false
+ property bool splashIsReady: false
+ property bool ready: appIsReady && splashIsReady
+
+ anchors.fill: parent
+
+ Image {
+ anchors.centerIn: parent
+ width: Math.min(parent.height, parent.width) * 0.6
+ height: GameSettings.heightForWidth(width, sourceSize)
+ source: "images/logo.png"
+ }
+
+ Timer {
+ id: splashTimer
+ interval: 1000
+ onTriggered: root.splashIsReady = true
+ }
+
+ Component.onCompleted: splashTimer.start()
+}
diff --git a/examples/bluetooth/heartrate-game/Stats.qml b/examples/bluetooth/heartrate-game/Stats.qml
new file mode 100644
index 00000000..87487c94
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/Stats.qml
@@ -0,0 +1,80 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import HeartRateGame
+
+GamePage {
+ id: statsPage
+
+ required property DeviceHandler deviceHandler
+
+ Column {
+ anchors.centerIn: parent
+ width: parent.width
+
+ Rectangle {
+ id: resultRect
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: height
+ height: statsPage.height / 2 - GameSettings.fieldHeight
+ radius: height / 2
+ color: GameSettings.viewColor
+
+ Column {
+ anchors.centerIn: parent
+
+ Text {
+ id: resultCaption
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: resultRect.width * 0.8
+ height: resultRect.height * 0.15
+ horizontalAlignment: Text.AlignHCenter
+ fontSizeMode: Text.Fit
+ font.pixelSize: GameSettings.bigFontSize
+ color: GameSettings.textColor
+ text: qsTr("RESULT")
+ }
+
+ Text {
+ id: resultValue
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: resultRect.width * 0.8
+ height: resultRect.height * 0.4
+ horizontalAlignment: Text.AlignHCenter
+ fontSizeMode: Text.Fit
+ font.pixelSize: GameSettings.hugeFontSize
+ font.bold: true
+ color: GameSettings.heartRateColor
+ text: (statsPage.deviceHandler.maxHR - statsPage.deviceHandler.minHR).toFixed(0)
+ }
+ }
+ }
+
+
+ Item {
+ height: GameSettings.fieldHeight
+ width: 1
+ }
+
+ StatsLabel {
+ title: qsTr("MIN")
+ value: statsPage.deviceHandler.minHR.toFixed(0)
+ }
+
+ StatsLabel {
+ title: qsTr("MAX")
+ value: statsPage.deviceHandler.maxHR.toFixed(0)
+ }
+
+ StatsLabel {
+ title: qsTr("AVG")
+ value: statsPage.deviceHandler.average.toFixed(1)
+ }
+
+ StatsLabel {
+ title: qsTr("CALORIES")
+ value: statsPage.deviceHandler.calories.toFixed(3)
+ }
+ }
+}
diff --git a/examples/bluetooth/heartrate-game/StatsLabel.qml b/examples/bluetooth/heartrate-game/StatsLabel.qml
new file mode 100644
index 00000000..0ea4249a
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/StatsLabel.qml
@@ -0,0 +1,34 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+Item {
+ height: GameSettings.fieldHeight
+ width: parent.width
+
+ property alias title: leftText.text
+ property alias value: rightText.text
+
+ Text {
+ id: leftText
+ anchors.left: parent.left
+ height: parent.height
+ width: parent.width * 0.45
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ font.pixelSize: GameSettings.mediumFontSize
+ color: GameSettings.textColor
+ }
+
+ Text {
+ id: rightText
+ anchors.right: parent.right
+ height: parent.height
+ width: parent.width * 0.45
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ font.pixelSize: GameSettings.mediumFontSize
+ color: GameSettings.textColor
+ }
+}
diff --git a/examples/bluetooth/heartrate-game/TitleBar.qml b/examples/bluetooth/heartrate-game/TitleBar.qml
new file mode 100644
index 00000000..ccec7608
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/TitleBar.qml
@@ -0,0 +1,63 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+import QtQuick
+
+Rectangle {
+ id: titleBar
+
+ property var __titles: ["CONNECT", "MEASURE", "STATS"]
+ property int currentIndex: 0
+
+ signal titleClicked(int index)
+
+ height: GameSettings.fieldHeight
+ color: GameSettings.titleColor
+
+ Rectangle {
+ anchors.bottom: parent.bottom
+ width: parent.width / 3
+ height: parent.height
+ x: titleBar.currentIndex * width
+ color: GameSettings.selectedTitleColor
+
+ BottomLine {
+ color: GameSettings.bottomLineColor
+ }
+
+ Behavior on x {
+ NumberAnimation {
+ duration: 200
+ }
+ }
+ }
+
+ Repeater {
+ model: 3
+ Rectangle {
+ id: caption
+ required property int index
+ property bool hoveredOrPressed: mouseArea.pressed || mouseArea.containsMouse
+ width: titleBar.width / 3
+ height: titleBar.height
+ x: index * width
+ color: (titleBar.currentIndex !== index) && hoveredOrPressed
+ ? GameSettings.hoverTitleColor : "transparent"
+ Text {
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: titleBar.__titles[caption.index]
+ font.pixelSize: GameSettings.microFontSize
+ color: GameSettings.textColor
+ }
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ onClicked: titleBar.titleClicked(caption.index)
+ }
+ }
+ }
+}
diff --git a/examples/bluetooth/heartrate-game/bluetoothbaseclass.cpp b/examples/bluetooth/heartrate-game/bluetoothbaseclass.cpp
index 7f6a8f63..4c60b180 100644
--- a/examples/bluetooth/heartrate-game/bluetoothbaseclass.cpp
+++ b/examples/bluetooth/heartrate-game/bluetoothbaseclass.cpp
@@ -1,52 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "bluetoothbaseclass.h"
@@ -80,8 +33,22 @@ void BluetoothBaseClass::setInfo(const QString &info)
}
}
+BluetoothBaseClass::IconType BluetoothBaseClass::icon() const
+{
+ return m_icon;
+}
+
+void BluetoothBaseClass::setIcon(IconType icon)
+{
+ if (m_icon != icon) {
+ m_icon = icon;
+ emit iconChanged();
+ }
+}
+
void BluetoothBaseClass::clearMessages()
{
setInfo("");
setError("");
+ setIcon(IconNone);
}
diff --git a/examples/bluetooth/heartrate-game/bluetoothbaseclass.h b/examples/bluetooth/heartrate-game/bluetoothbaseclass.h
index 5a043b3d..fba014f5 100644
--- a/examples/bluetooth/heartrate-game/bluetoothbaseclass.h
+++ b/examples/bluetooth/heartrate-game/bluetoothbaseclass.h
@@ -1,65 +1,34 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef BLUETOOTHBASECLASS_H
#define BLUETOOTHBASECLASS_H
#include <QObject>
+#include <QQmlEngine>
+
class BluetoothBaseClass : public QObject
{
Q_OBJECT
+
Q_PROPERTY(QString error READ error WRITE setError NOTIFY errorChanged)
Q_PROPERTY(QString info READ info WRITE setInfo NOTIFY infoChanged)
+ Q_PROPERTY(IconType icon READ icon WRITE setIcon NOTIFY iconChanged)
+
+ QML_ELEMENT
+ QML_UNCREATABLE("BluetoothBaseClass is not intended to be created directly")
public:
+ enum IconType : int {
+ IconNone,
+ IconBluetooth,
+ IconError,
+ IconProgress,
+ IconSearch
+ };
+ Q_ENUM(IconType)
+
explicit BluetoothBaseClass(QObject *parent = nullptr);
QString error() const;
@@ -68,15 +37,20 @@ public:
QString info() const;
void setInfo(const QString& info);
+ IconType icon() const;
+ void setIcon(IconType icon);
+
void clearMessages();
signals:
void errorChanged();
void infoChanged();
+ void iconChanged();
private:
QString m_error;
QString m_info;
+ IconType m_icon = IconNone;
};
#endif // BLUETOOTHBASECLASS_H
diff --git a/examples/bluetooth/heartrate-game/connectionhandler.cpp b/examples/bluetooth/heartrate-game/connectionhandler.cpp
index 3388c0a8..87e64624 100644
--- a/examples/bluetooth/heartrate-game/connectionhandler.cpp
+++ b/examples/bluetooth/heartrate-game/connectionhandler.cpp
@@ -1,73 +1,42 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 "heartrate-global.h"
#include "connectionhandler.h"
-#include <QtBluetooth/qtbluetooth-config.h>
-#include <QtCore/qsystemdetection.h>
+#include "heartrate-global.h"
+
+#include <qtbluetooth-config.h>
+
+#include <QtSystemDetection>
+
+#if QT_CONFIG(permissions)
+#include <QCoreApplication>
+#include <QPermissions>
+#endif
ConnectionHandler::ConnectionHandler(QObject *parent) : QObject(parent)
{
- connect(&m_localDevice, &QBluetoothLocalDevice::hostModeStateChanged,
- this, &ConnectionHandler::hostModeChanged);
+ initLocalDevice();
}
bool ConnectionHandler::alive() const
{
-#if defined(SIMULATOR) || defined(QT_PLATFORM_UIKIT)
+
+#ifdef QT_PLATFORM_UIKIT
return true;
+
#else
- return m_localDevice.isValid() && m_localDevice.hostMode() != QBluetoothLocalDevice::HostPoweredOff;
+ if (simulator)
+ return true;
+ return m_localDevice && m_localDevice->isValid()
+ && m_localDevice->hostMode() != QBluetoothLocalDevice::HostPoweredOff;
#endif
}
+bool ConnectionHandler::hasPermission() const
+{
+ return m_hasPermission;
+}
+
bool ConnectionHandler::requiresAddressType() const
{
#if QT_CONFIG(bluez)
@@ -79,15 +48,37 @@ bool ConnectionHandler::requiresAddressType() const
QString ConnectionHandler::name() const
{
- return m_localDevice.name();
+ return m_localDevice ? m_localDevice->name() : QString();
}
QString ConnectionHandler::address() const
{
- return m_localDevice.address().toString();
+ return m_localDevice ? m_localDevice->address().toString() : QString();
}
void ConnectionHandler::hostModeChanged(QBluetoothLocalDevice::HostMode /*mode*/)
{
emit deviceChanged();
}
+
+void ConnectionHandler::initLocalDevice()
+{
+#if QT_CONFIG(permissions)
+ QBluetoothPermission permission{};
+ permission.setCommunicationModes(QBluetoothPermission::Access);
+ switch (qApp->checkPermission(permission)) {
+ case Qt::PermissionStatus::Undetermined:
+ qApp->requestPermission(permission, this, &ConnectionHandler::initLocalDevice);
+ return;
+ case Qt::PermissionStatus::Denied:
+ return;
+ case Qt::PermissionStatus::Granted:
+ break; // proceed to initialization
+ }
+#endif
+ m_localDevice = new QBluetoothLocalDevice(this);
+ connect(m_localDevice, &QBluetoothLocalDevice::hostModeStateChanged,
+ this, &ConnectionHandler::hostModeChanged);
+ m_hasPermission = true;
+ emit deviceChanged();
+}
diff --git a/examples/bluetooth/heartrate-game/connectionhandler.h b/examples/bluetooth/heartrate-game/connectionhandler.h
index 9f5a42cc..e51fcbef 100644
--- a/examples/bluetooth/heartrate-game/connectionhandler.h
+++ b/examples/bluetooth/heartrate-game/connectionhandler.h
@@ -1,71 +1,31 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef CONNECTIONHANDLER_H
#define CONNECTIONHANDLER_H
-#include <QObject>
#include <QBluetoothLocalDevice>
+#include <QObject>
+
+#include <QQmlEngine>
+
class ConnectionHandler : public QObject
{
+ Q_OBJECT
+
Q_PROPERTY(bool alive READ alive NOTIFY deviceChanged)
+ Q_PROPERTY(bool hasPermission READ hasPermission NOTIFY deviceChanged)
Q_PROPERTY(QString name READ name NOTIFY deviceChanged)
Q_PROPERTY(QString address READ address NOTIFY deviceChanged)
Q_PROPERTY(bool requiresAddressType READ requiresAddressType CONSTANT)
- Q_OBJECT
+ QML_ELEMENT
public:
explicit ConnectionHandler(QObject *parent = nullptr);
bool alive() const;
+ bool hasPermission() const;
bool requiresAddressType() const;
QString name() const;
QString address() const;
@@ -75,9 +35,11 @@ signals:
private slots:
void hostModeChanged(QBluetoothLocalDevice::HostMode mode);
+ void initLocalDevice();
private:
- QBluetoothLocalDevice m_localDevice;
+ QBluetoothLocalDevice *m_localDevice = nullptr;
+ bool m_hasPermission = false;
};
#endif // CONNECTIONHANDLER_H
diff --git a/examples/bluetooth/heartrate-game/devicefinder.cpp b/examples/bluetooth/heartrate-game/devicefinder.cpp
index 19ebee90..eaa70ca8 100644
--- a/examples/bluetooth/heartrate-game/devicefinder.cpp
+++ b/examples/bluetooth/heartrate-game/devicefinder.cpp
@@ -1,56 +1,17 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "devicefinder.h"
#include "devicehandler.h"
#include "deviceinfo.h"
+#include "heartrate-global.h"
+
+#include <QBluetoothDeviceInfo>
+
+#if QT_CONFIG(permissions)
+#include <QCoreApplication>
+#include <QPermissions>
+#endif
DeviceFinder::DeviceFinder(DeviceHandler *handler, QObject *parent):
BluetoothBaseClass(parent),
@@ -58,22 +19,27 @@ DeviceFinder::DeviceFinder(DeviceHandler *handler, QObject *parent):
{
//! [devicediscovery-1]
m_deviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
- m_deviceDiscoveryAgent->setLowEnergyDiscoveryTimeout(5000);
+ m_deviceDiscoveryAgent->setLowEnergyDiscoveryTimeout(15000);
- connect(m_deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &DeviceFinder::addDevice);
- connect(m_deviceDiscoveryAgent, static_cast<void (QBluetoothDeviceDiscoveryAgent::*)(QBluetoothDeviceDiscoveryAgent::Error)>(&QBluetoothDeviceDiscoveryAgent::error),
+ connect(m_deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
+ this, &DeviceFinder::addDevice);
+ connect(m_deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::errorOccurred,
this, &DeviceFinder::scanError);
- connect(m_deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &DeviceFinder::scanFinished);
- connect(m_deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::canceled, this, &DeviceFinder::scanFinished);
+ connect(m_deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished,
+ this, &DeviceFinder::scanFinished);
+ connect(m_deviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::canceled,
+ this, &DeviceFinder::scanFinished);
//! [devicediscovery-1]
-#ifdef SIMULATOR
- m_demoTimer.setSingleShot(true);
- m_demoTimer.setInterval(2000);
- connect(&m_demoTimer, &QTimer::timeout, this, &DeviceFinder::scanFinished);
-#endif
+ if (simulator) {
+ m_demoTimer.setSingleShot(true);
+ m_demoTimer.setInterval(2000);
+ connect(&m_demoTimer, &QTimer::timeout, this, &DeviceFinder::scanFinished);
+ }
+
+ resetMessages();
}
DeviceFinder::~DeviceFinder()
@@ -84,6 +50,23 @@ DeviceFinder::~DeviceFinder()
void DeviceFinder::startSearch()
{
+#if QT_CONFIG(permissions)
+ //! [permissions]
+ QBluetoothPermission permission{};
+ permission.setCommunicationModes(QBluetoothPermission::Access);
+ switch (qApp->checkPermission(permission)) {
+ case Qt::PermissionStatus::Undetermined:
+ qApp->requestPermission(permission, this, &DeviceFinder::startSearch);
+ return;
+ case Qt::PermissionStatus::Denied:
+ setError(tr("Bluetooth permissions not granted!"));
+ setIcon(IconError);
+ return;
+ case Qt::PermissionStatus::Granted:
+ break; // proceed to search
+ }
+ //! [permissions]
+#endif // QT_CONFIG(permissions)
clearMessages();
m_deviceHandler->setDevice(nullptr);
qDeleteAll(m_devices);
@@ -91,15 +74,17 @@ void DeviceFinder::startSearch()
emit devicesChanged();
-#ifdef SIMULATOR
- m_demoTimer.start();
-#else
- //! [devicediscovery-2]
- m_deviceDiscoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
- //! [devicediscovery-2]
-#endif
+ if (simulator) {
+ m_demoTimer.start();
+ } else {
+ //! [devicediscovery-2]
+ m_deviceDiscoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
+ //! [devicediscovery-2]
+ }
+
emit scanningChanged();
setInfo(tr("Scanning for devices..."));
+ setIcon(IconProgress);
}
//! [devicediscovery-3]
@@ -107,8 +92,20 @@ void DeviceFinder::addDevice(const QBluetoothDeviceInfo &device)
{
// If device is LowEnergy-device, add it to the list
if (device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) {
- m_devices.append(new DeviceInfo(device));
+ auto devInfo = new DeviceInfo(device);
+ auto it = std::find_if(m_devices.begin(), m_devices.end(),
+ [devInfo](DeviceInfo *dev) {
+ return devInfo->getAddress() == dev->getAddress();
+ });
+ if (it == m_devices.end()) {
+ m_devices.append(devInfo);
+ } else {
+ auto oldDev = *it;
+ *it = devInfo;
+ delete oldDev;
+ }
setInfo(tr("Low Energy device found. Scanning more..."));
+ setIcon(IconProgress);
//! [devicediscovery-3]
emit devicesChanged();
//! [devicediscovery-4]
@@ -125,33 +122,44 @@ void DeviceFinder::scanError(QBluetoothDeviceDiscoveryAgent::Error error)
setError(tr("Writing or reading from the device resulted in an error."));
else
setError(tr("An unknown error has occurred."));
+ setIcon(IconError);
}
void DeviceFinder::scanFinished()
{
-#ifdef SIMULATOR
- // Only for testing
- for (int i = 0; i < 4; i++)
- m_devices.append(new DeviceInfo(QBluetoothDeviceInfo()));
-#endif
+ if (simulator) {
+ // Only for testing
+ for (int i = 0; i < 4; i++)
+ m_devices.append(new DeviceInfo(QBluetoothDeviceInfo()));
+ }
- if (m_devices.isEmpty())
+ if (m_devices.isEmpty()) {
setError(tr("No Low Energy devices found."));
- else
+ setIcon(IconError);
+ } else {
setInfo(tr("Scanning done."));
+ setIcon(IconBluetooth);
+ }
emit scanningChanged();
emit devicesChanged();
}
+void DeviceFinder::resetMessages()
+{
+ setError("");
+ setInfo(tr("Start search to find devices"));
+ setIcon(IconSearch);
+}
+
void DeviceFinder::connectToService(const QString &address)
{
m_deviceDiscoveryAgent->stop();
DeviceInfo *currentDevice = nullptr;
- for (QObject *entry : qAsConst(m_devices)) {
+ for (QObject *entry : std::as_const(m_devices)) {
auto device = qobject_cast<DeviceInfo *>(entry);
- if (device && device->getAddress() == address ) {
+ if (device && device->getAddress() == address) {
currentDevice = device;
break;
}
@@ -160,16 +168,14 @@ void DeviceFinder::connectToService(const QString &address)
if (currentDevice)
m_deviceHandler->setDevice(currentDevice);
- clearMessages();
+ resetMessages();
}
bool DeviceFinder::scanning() const
{
-#ifdef SIMULATOR
- return m_demoTimer.isActive();
-#else
+ if (simulator)
+ return m_demoTimer.isActive();
return m_deviceDiscoveryAgent->isActive();
-#endif
}
QVariant DeviceFinder::devices()
diff --git a/examples/bluetooth/heartrate-game/devicefinder.h b/examples/bluetooth/heartrate-game/devicefinder.h
index 6dbb5692..703ef2c2 100644
--- a/examples/bluetooth/heartrate-game/devicefinder.h
+++ b/examples/bluetooth/heartrate-game/devicefinder.h
@@ -1,64 +1,21 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef DEVICEFINDER_H
#define DEVICEFINDER_H
-#include "heartrate-global.h"
#include "bluetoothbaseclass.h"
+#include <QBluetoothDeviceDiscoveryAgent>
+
#include <QTimer>
#include <QVariant>
-#include <QBluetoothDeviceDiscoveryAgent>
-#include <QBluetoothDeviceInfo>
+#include <QQmlEngine>
+
+QT_BEGIN_NAMESPACE
+class QBluetoothDeviceInfo;
+QT_END_NAMESPACE
class DeviceInfo;
class DeviceHandler;
@@ -70,6 +27,9 @@ class DeviceFinder: public BluetoothBaseClass
Q_PROPERTY(bool scanning READ scanning NOTIFY scanningChanged)
Q_PROPERTY(QVariant devices READ devices NOTIFY devicesChanged)
+ QML_ELEMENT
+ QML_UNCREATABLE("This class is not intended to be created directly")
+
public:
DeviceFinder(DeviceHandler *handler, QObject *parent = nullptr);
~DeviceFinder();
@@ -82,7 +42,7 @@ public slots:
void connectToService(const QString &address);
private slots:
- void addDevice(const QBluetoothDeviceInfo&);
+ void addDevice(const QBluetoothDeviceInfo &device);
void scanError(QBluetoothDeviceDiscoveryAgent::Error error);
void scanFinished();
@@ -91,13 +51,13 @@ signals:
void devicesChanged();
private:
+ void resetMessages();
+
DeviceHandler *m_deviceHandler;
QBluetoothDeviceDiscoveryAgent *m_deviceDiscoveryAgent;
- QList<QObject*> m_devices;
+ QList<DeviceInfo *> m_devices;
-#ifdef SIMULATOR
QTimer m_demoTimer;
-#endif
};
#endif // DEVICEFINDER_H
diff --git a/examples/bluetooth/heartrate-game/devicehandler.cpp b/examples/bluetooth/heartrate-game/devicehandler.cpp
index 83a4fbbe..c264d771 100644
--- a/examples/bluetooth/heartrate-game/devicehandler.cpp
+++ b/examples/bluetooth/heartrate-game/devicehandler.cpp
@@ -1,73 +1,23 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-#include "heartrate-global.h"
#include "devicehandler.h"
#include "deviceinfo.h"
+#include "heartrate-global.h"
+
#include <QtEndian>
#include <QRandomGenerator>
DeviceHandler::DeviceHandler(QObject *parent) :
- BluetoothBaseClass(parent),
- m_foundHeartRateService(false),
- m_measuring(false),
- m_currentValue(0),
- m_min(0), m_max(0), m_sum(0), m_avg(0), m_calories(0)
+ BluetoothBaseClass(parent)
{
-#ifdef SIMULATOR
- m_demoTimer.setSingleShot(false);
- m_demoTimer.setInterval(2000);
- connect(&m_demoTimer, &QTimer::timeout, this, &DeviceHandler::updateDemoHR);
- m_demoTimer.start();
- updateDemoHR();
-#endif
+ if (simulator) {
+ m_demoTimer.setSingleShot(false);
+ m_demoTimer.setInterval(2000);
+ connect(&m_demoTimer, &QTimer::timeout, this, &DeviceHandler::updateDemoHR);
+ m_demoTimer.start();
+ updateDemoHR();
+ }
}
void DeviceHandler::setAddressType(AddressType type)
@@ -95,10 +45,11 @@ void DeviceHandler::setDevice(DeviceInfo *device)
clearMessages();
m_currentDevice = device;
-#ifdef SIMULATOR
- setInfo(tr("Demo device connected."));
- return;
-#endif
+ if (simulator) {
+ setInfo(tr("Demo device connected."));
+ setIcon(IconBluetooth);
+ return;
+ }
// Disconnect and delete old connection
if (m_control) {
@@ -121,17 +72,20 @@ void DeviceHandler::setDevice(DeviceInfo *device)
connect(m_control, &QLowEnergyController::discoveryFinished,
this, &DeviceHandler::serviceScanDone);
- connect(m_control, static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
- this, [this](QLowEnergyController::Error error) {
- Q_UNUSED(error);
- setError("Cannot connect to remote device.");
- });
+ connect(m_control, &QLowEnergyController::errorOccurred, this,
+ [this](QLowEnergyController::Error error) {
+ Q_UNUSED(error);
+ setError("Cannot connect to remote device.");
+ setIcon(IconError);
+ });
connect(m_control, &QLowEnergyController::connected, this, [this]() {
setInfo("Controller connected. Search services...");
+ setIcon(IconProgress);
m_control->discoverServices();
});
connect(m_control, &QLowEnergyController::disconnected, this, [this]() {
setError("LowEnergy controller disconnected");
+ setIcon(IconError);
});
// Connect
@@ -164,8 +118,9 @@ void DeviceHandler::stopMeasurement()
//! [Filter HeartRate service 1]
void DeviceHandler::serviceDiscovered(const QBluetoothUuid &gatt)
{
- if (gatt == QBluetoothUuid(QBluetoothUuid::HeartRate)) {
+ if (gatt == QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::HeartRate)) {
setInfo("Heart Rate service discovered. Waiting for service scan to be done...");
+ setIcon(IconProgress);
m_foundHeartRateService = true;
}
}
@@ -174,6 +129,7 @@ void DeviceHandler::serviceDiscovered(const QBluetoothUuid &gatt)
void DeviceHandler::serviceScanDone()
{
setInfo("Service scan done.");
+ setIcon(IconBluetooth);
// Delete old service if available
if (m_service) {
@@ -184,7 +140,7 @@ void DeviceHandler::serviceScanDone()
//! [Filter HeartRate service 2]
// If heartRateService found, create new service
if (m_foundHeartRateService)
- m_service = m_control->createServiceObject(QBluetoothUuid(QBluetoothUuid::HeartRate), this);
+ m_service = m_control->createServiceObject(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::HeartRate), this);
if (m_service) {
connect(m_service, &QLowEnergyService::stateChanged, this, &DeviceHandler::serviceStateChanged);
@@ -193,6 +149,7 @@ void DeviceHandler::serviceScanDone()
m_service->discoverDetails();
} else {
setError("Heart Rate Service not found.");
+ setIcon(IconError);
}
//! [Filter HeartRate service 2]
}
@@ -202,20 +159,24 @@ void DeviceHandler::serviceScanDone()
void DeviceHandler::serviceStateChanged(QLowEnergyService::ServiceState s)
{
switch (s) {
- case QLowEnergyService::DiscoveringServices:
+ case QLowEnergyService::RemoteServiceDiscovering:
setInfo(tr("Discovering services..."));
+ setIcon(IconProgress);
break;
- case QLowEnergyService::ServiceDiscovered:
+ case QLowEnergyService::RemoteServiceDiscovered:
{
setInfo(tr("Service discovered."));
+ setIcon(IconBluetooth);
- const QLowEnergyCharacteristic hrChar = m_service->characteristic(QBluetoothUuid(QBluetoothUuid::HeartRateMeasurement));
+ const QLowEnergyCharacteristic hrChar =
+ m_service->characteristic(QBluetoothUuid(QBluetoothUuid::CharacteristicType::HeartRateMeasurement));
if (!hrChar.isValid()) {
setError("HR Data not found.");
+ setIcon(IconError);
break;
}
- m_notificationDesc = hrChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
+ m_notificationDesc = hrChar.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
if (m_notificationDesc.isValid())
m_service->writeDescriptor(m_notificationDesc, QByteArray::fromHex("0100"));
@@ -234,7 +195,7 @@ void DeviceHandler::serviceStateChanged(QLowEnergyService::ServiceState s)
void DeviceHandler::updateHeartRateValue(const QLowEnergyCharacteristic &c, const QByteArray &value)
{
// ignore any other characteristic change -> shouldn't really happen though
- if (c.uuid() != QBluetoothUuid(QBluetoothUuid::HeartRateMeasurement))
+ if (c.uuid() != QBluetoothUuid(QBluetoothUuid::CharacteristicType::HeartRateMeasurement))
return;
auto data = reinterpret_cast<const quint8 *>(value.constData());
@@ -251,21 +212,18 @@ void DeviceHandler::updateHeartRateValue(const QLowEnergyCharacteristic &c, cons
}
//! [Reading value]
-#ifdef SIMULATOR
void DeviceHandler::updateDemoHR()
{
int randomValue = 0;
- if (m_currentValue < 30) { // Initial value
+ if (m_currentValue < 30) // Initial value
randomValue = 55 + QRandomGenerator::global()->bounded(30);
- } else if (!m_measuring) { // Value when relax
+ else if (!m_measuring) // Value when relax
randomValue = qBound(55, m_currentValue - 2 + QRandomGenerator::global()->bounded(5), 75);
- } else { // Measuring
+ else // Measuring
randomValue = m_currentValue + QRandomGenerator::global()->bounded(10) - 2;
- }
addMeasurement(randomValue);
}
-#endif
void DeviceHandler::confirmedDescriptorWrite(const QLowEnergyDescriptor &d, const QByteArray &value)
{
@@ -301,12 +259,11 @@ bool DeviceHandler::measuring() const
bool DeviceHandler::alive() const
{
-#ifdef SIMULATOR
- return true;
-#endif
+ if (simulator)
+ return true;
if (m_service)
- return m_service->state() == QLowEnergyService::ServiceDiscovered;
+ return m_service->state() == QLowEnergyService::RemoteServiceDiscovered;
return false;
}
@@ -355,7 +312,8 @@ void DeviceHandler::addMeasurement(int value)
m_max = qMax(value, m_max);
m_sum += value;
m_avg = (double)m_sum / m_measurements.size();
- m_calories = ((-55.0969 + (0.6309 * m_avg) + (0.1988 * 94) + (0.2017 * 24)) / 4.184) * 60 * time()/3600;
+ m_calories = ((-55.0969 + (0.6309 * m_avg) + (0.1988 * 94) + (0.2017 * 24)) / 4.184)
+ * 60 * time() / 3600;
}
emit statsChanged();
diff --git a/examples/bluetooth/heartrate-game/devicehandler.h b/examples/bluetooth/heartrate-game/devicehandler.h
index 4fa2782b..a010d396 100644
--- a/examples/bluetooth/heartrate-game/devicehandler.h
+++ b/examples/bluetooth/heartrate-game/devicehandler.h
@@ -1,64 +1,19 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef DEVICEHANDLER_H
#define DEVICEHANDLER_H
#include "bluetoothbaseclass.h"
+#include <QLowEnergyController>
+#include <QLowEnergyService>
+
#include <QDateTime>
+#include <QList>
#include <QTimer>
-#include <QVector>
-#include <QLowEnergyController>
-#include <QLowEnergyService>
+#include <QQmlEngine>
class DeviceInfo;
@@ -76,6 +31,8 @@ class DeviceHandler : public BluetoothBaseClass
Q_PROPERTY(float calories READ calories NOTIFY statsChanged)
Q_PROPERTY(AddressType addressType READ addressType WRITE setAddressType)
+ QML_ELEMENT
+
public:
enum class AddressType {
PublicAddress,
@@ -120,11 +77,10 @@ private:
void updateHeartRateValue(const QLowEnergyCharacteristic &c,
const QByteArray &value);
void confirmedDescriptorWrite(const QLowEnergyDescriptor &d,
- const QByteArray &value);
+ const QByteArray &value);
-#ifdef SIMULATOR
void updateDemoHR();
-#endif
+
private:
void addMeasurement(int value);
@@ -133,21 +89,19 @@ private:
QLowEnergyDescriptor m_notificationDesc;
DeviceInfo *m_currentDevice = nullptr;
- bool m_foundHeartRateService;
- bool m_measuring;
- int m_currentValue, m_min, m_max, m_sum;
- float m_avg, m_calories;
+ bool m_foundHeartRateService = false;
+ bool m_measuring = false;
+ int m_currentValue = 0, m_min = 0, m_max = 0, m_sum = 0;
+ float m_avg = 0, m_calories = 0;
// Statistics
QDateTime m_start;
QDateTime m_stop;
- QVector<int> m_measurements;
+ QList<int> m_measurements;
QLowEnergyController::RemoteAddressType m_addressType = QLowEnergyController::PublicAddress;
-#ifdef SIMULATOR
QTimer m_demoTimer;
-#endif
};
#endif // DEVICEHANDLER_H
diff --git a/examples/bluetooth/heartrate-game/deviceinfo.cpp b/examples/bluetooth/heartrate-game/deviceinfo.cpp
index 4ed7f1b1..9bfff540 100644
--- a/examples/bluetooth/heartrate-game/deviceinfo.cpp
+++ b/examples/bluetooth/heartrate-game/deviceinfo.cpp
@@ -1,58 +1,14 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-#include "heartrate-global.h"
#include "deviceinfo.h"
+#include "heartrate-global.h"
+
#include <QBluetoothAddress>
#include <QBluetoothUuid>
+using namespace Qt::StringLiterals;
+
DeviceInfo::DeviceInfo(const QBluetoothDeviceInfo &info):
m_device(info)
{
@@ -65,18 +21,16 @@ QBluetoothDeviceInfo DeviceInfo::getDevice() const
QString DeviceInfo::getName() const
{
-#ifdef SIMULATOR
- return "Demo device";
-#else
+ if (simulator)
+ return u"Demo BT Device"_s;
return m_device.name();
-#endif
}
QString DeviceInfo::getAddress() const
{
-#ifdef SIMULATOR
- return "00:11:22:33:44:55";
-#elif defined Q_OS_DARWIN
+ if (simulator)
+ return u"00:11:22:33:44:55"_s;
+#ifdef Q_OS_DARWIN
// workaround for Core Bluetooth:
return m_device.deviceUuid().toString();
#else
diff --git a/examples/bluetooth/heartrate-game/deviceinfo.h b/examples/bluetooth/heartrate-game/deviceinfo.h
index f8fc3a19..19dd7afb 100644
--- a/examples/bluetooth/heartrate-game/deviceinfo.h
+++ b/examples/bluetooth/heartrate-game/deviceinfo.h
@@ -1,63 +1,18 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef DEVICEINFO_H
#define DEVICEINFO_H
-#include <QString>
-#include <QObject>
#include <QBluetoothDeviceInfo>
+#include <QObject>
+#include <QString>
+
class DeviceInfo: public QObject
{
Q_OBJECT
+
Q_PROPERTY(QString deviceName READ getName NOTIFY deviceChanged)
Q_PROPERTY(QString deviceAddress READ getAddress NOTIFY deviceChanged)
diff --git a/examples/bluetooth/heartrate-game/doc/images/heartgame-result.png b/examples/bluetooth/heartrate-game/doc/images/heartgame-result.png
deleted file mode 100644
index 2dad1b30..00000000
--- a/examples/bluetooth/heartrate-game/doc/images/heartgame-result.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/heartrate-game/doc/images/heartgame-result.webp b/examples/bluetooth/heartrate-game/doc/images/heartgame-result.webp
new file mode 100644
index 00000000..58815ac0
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/doc/images/heartgame-result.webp
Binary files differ
diff --git a/examples/bluetooth/heartrate-game/doc/images/heartgame-running.png b/examples/bluetooth/heartrate-game/doc/images/heartgame-running.png
deleted file mode 100644
index 05485f0e..00000000
--- a/examples/bluetooth/heartrate-game/doc/images/heartgame-running.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/heartrate-game/doc/images/heartgame-running.webp b/examples/bluetooth/heartrate-game/doc/images/heartgame-running.webp
new file mode 100644
index 00000000..1de7af6d
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/doc/images/heartgame-running.webp
Binary files differ
diff --git a/examples/bluetooth/heartrate-game/doc/images/heartgame-search.png b/examples/bluetooth/heartrate-game/doc/images/heartgame-search.png
deleted file mode 100644
index 4b0b0497..00000000
--- a/examples/bluetooth/heartrate-game/doc/images/heartgame-search.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/heartrate-game/doc/images/heartgame-search.webp b/examples/bluetooth/heartrate-game/doc/images/heartgame-search.webp
new file mode 100644
index 00000000..727486d0
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/doc/images/heartgame-search.webp
Binary files differ
diff --git a/examples/bluetooth/heartrate-game/doc/images/heartgame-start.png b/examples/bluetooth/heartrate-game/doc/images/heartgame-start.png
deleted file mode 100644
index 21cc641f..00000000
--- a/examples/bluetooth/heartrate-game/doc/images/heartgame-start.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/heartrate-game/doc/images/heartgame-start.webp b/examples/bluetooth/heartrate-game/doc/images/heartgame-start.webp
new file mode 100644
index 00000000..9a49e4a1
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/doc/images/heartgame-start.webp
Binary files differ
diff --git a/examples/bluetooth/heartrate-game/doc/src/heartrate-game.qdoc b/examples/bluetooth/heartrate-game/doc/src/heartrate-game.qdoc
index f0d4c365..891ffc69 100644
--- a/examples/bluetooth/heartrate-game/doc/src/heartrate-game.qdoc
+++ b/examples/bluetooth/heartrate-game/doc/src/heartrate-game.qdoc
@@ -1,43 +1,21 @@
-/****************************************************************************
-**
-** 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
/*!
\example heartrate-game
\title Bluetooth Low Energy Heart Rate Game
+ \examplecategory {Connectivity}
+ \meta tags {bluetooth, ble, quick}
\brief A game demonstrating the interaction with a Bluetooth Low Energy Heart Rate
device/service.
The Bluetooth Low Energy Heart Rate Game shows how to develop a Bluetooth Low Energy
- application using the Qt Bluetooth API. The application covers the scanning for
+ application using the \l{QtBluetooth}{Qt Bluetooth API}. The application covers the scanning for
Bluetooth Low Energy devices, connecting to a Heart Rate service on the device, writing
characteristics and descriptors, and receiving updates from the device once the heart rate
has changed.
- \image heartgame-start.png
+ \image heartgame-start.webp
The example introduces the following Qt classes:
@@ -52,17 +30,30 @@
service is required for this application to work. An alternative might be a programmable
Bluetooth Low Energy device which might simulate the service. You can also use the
\l {heartrate-server} {Heart Rate server} example for that purpose.
- If no such device can be found, the example uses a demo mode which creates and displays
- random values.
+ If no such device is available, a demo mode is available which creates and displays
+ random values. This demo mode is enabled by passing \c{--simulator} on the
+ command line.
The goal of the game is to increase the measured heart rate as much as possible.
+ A detailed explanation of the APIs used in this example is given in the
+ \l {Using Qt Bluetooth Low Energy API} section of the \l{Qt Bluetooth} module
+ documentation.
+
The \l {lowenergyscanner}{Bluetooth Low Energy Scanner} example might be more suitable
if a heart rate device is not available. The scanner example works with any type of Bluetooth
Low Energy peripheral device.
\include examples-run.qdocinc
+ \section1 Checking Bluetooth Permissions
+
+ Before the application can start using Bluetooth, we have to check that
+ appropriate permissions were granted:
+
+ \snippet heartrate-game/devicefinder.cpp permissions
+
+
\section1 Visual Tour
The application searches for all Bluetooth Low Energy peripheral devices in the vicinity.
@@ -70,17 +61,17 @@
presented in a list. Note that all found Bluetooth Low Energy devices are listed even
if they do not offer a Heart Rate service.
- \image heartgame-search.png
+ \image heartgame-search.webp
After the user has selected a target device, the example connects to its Heart Rate service
if one is available. It automatically enables notification updates for the Heart Rate value
and presents the current value on the screen.
- \image heartgame-running.png
+ \image heartgame-running.webp
- Once the monitoring process is canceled, a small graph presents a summary of the received
- values.
+ Once the monitoring process is finished, a small summary of the received
+ values is presented.
- \image heartgame-result.png
+ \image heartgame-result.webp
*/
diff --git a/examples/bluetooth/heartrate-game/heartrate-game.pro b/examples/bluetooth/heartrate-game/heartrate-game.pro
index fcec0bd2..7cd5dcc5 100644
--- a/examples/bluetooth/heartrate-game/heartrate-game.pro
+++ b/examples/bluetooth/heartrate-game/heartrate-game.pro
@@ -2,7 +2,10 @@ TEMPLATE = app
TARGET = heartrate-game
QT += qml quick bluetooth
-CONFIG += c++11
+
+CONFIG += qmltypes
+QML_IMPORT_NAME = HeartRateGame
+QML_IMPORT_MAJOR_VERSION = 1
HEADERS += \
connectionhandler.h \
@@ -19,11 +22,36 @@ SOURCES += main.cpp \
devicehandler.cpp \
bluetoothbaseclass.cpp
-RESOURCES += qml.qrc \
- images.qrc
+qml_resources.files = \
+ qmldir \
+ App.qml \
+ BluetoothAlarmDialog.qml \
+ BottomLine.qml \
+ Connect.qml \
+ GameButton.qml \
+ GamePage.qml \
+ GameSettings.qml \
+ Measure.qml \
+ SplashScreen.qml \
+ Stats.qml \
+ StatsLabel.qml \
+ TitleBar.qml \
+ Main.qml \
+ images/alert.svg \
+ images/bluetooth.svg \
+ images/bt_off_to_on.png \
+ images/clock.svg \
+ images/heart.png \
+ images/logo.png \
+ images/progress.svg \
+ images/search.svg
+
+qml_resources.prefix = /qt/qml/HeartRateGame
+
+RESOURCES = qml_resources
-# Additional import path used to resolve QML modules in Qt Creator's code model
-QML_IMPORT_PATH =
+ios: QMAKE_INFO_PLIST = ../shared/Info.qmake.ios.plist
+macos: QMAKE_INFO_PLIST = ../shared/Info.qmake.macos.plist
target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/heartrate-game
INSTALLS += target
diff --git a/examples/bluetooth/heartrate-game/heartrate-global.h b/examples/bluetooth/heartrate-game/heartrate-global.h
index cc47bbb4..a967e64e 100644
--- a/examples/bluetooth/heartrate-game/heartrate-global.h
+++ b/examples/bluetooth/heartrate-game/heartrate-global.h
@@ -1,61 +1,9 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef HEARTRATEGLOBAL_H
#define HEARTRATEGLOBAL_H
-//#define USE_SIMULATOR
-
-#if defined(Q_OS_WIN32) || defined(USE_SIMULATOR)
-#define SIMULATOR
-#endif
-
+extern bool simulator;
#endif // HEARTRATEGLOBAL_H
diff --git a/examples/bluetooth/heartrate-game/images.qrc b/examples/bluetooth/heartrate-game/images.qrc
deleted file mode 100644
index 38058de0..00000000
--- a/examples/bluetooth/heartrate-game/images.qrc
+++ /dev/null
@@ -1,7 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>qml/images/logo.png</file>
- <file>qml/images/bt_off_to_on.png</file>
- <file>qml/images/heart.png</file>
- </qresource>
-</RCC>
diff --git a/examples/bluetooth/heartrate-game/images/alert.svg b/examples/bluetooth/heartrate-game/images/alert.svg
new file mode 100644
index 00000000..c48c10e6
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/images/alert.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12 4C16.4183 4 20 7.58172 20 12C20 16.4183 16.4183 20 12 20C7.58172 20 4 16.4183 4 12C4 7.58172 7.58172 4 12 4ZM12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2Z" fill="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12 13C11.4477 13 11 12.5523 11 12V8C11 7.44772 11.4477 7 12 7C12.5523 7 13 7.44772 13 8V12C13 12.5523 12.5523 13 12 13ZM12 15C12.5523 15 13 15.4477 13 16C13 16.5523 12.5523 17 12 17C11.4477 17 11 16.5523 11 16C11 15.4477 11.4477 15 12 15Z" fill="white"/>
+</svg>
diff --git a/examples/bluetooth/heartrate-game/images/bluetooth.svg b/examples/bluetooth/heartrate-game/images/bluetooth.svg
new file mode 100644
index 00000000..6d01b28f
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/images/bluetooth.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M11.1869 2.24413C11.4926 2.11749 11.8445 2.18749 12.0785 2.42149L16.5785 6.92149C16.8981 7.24101 16.8981 7.75905 16.5785 8.07857L12.6571 12L16.5785 15.9215C16.8981 16.241 16.8981 16.7591 16.5785 17.0786L12.0785 21.5786C11.8445 21.8126 11.4926 21.8826 11.1869 21.7559C10.8812 21.6293 10.6818 21.331 10.6818 21V13.9753L7.57855 17.0786C7.25903 17.3981 6.74098 17.3981 6.42146 17.0786C6.10194 16.7591 6.10194 16.241 6.42146 15.9215L10.3429 12L6.42146 8.07857C6.10194 7.75905 6.10194 7.24101 6.42146 6.92149C6.74098 6.60197 7.25903 6.60197 7.57855 6.92149L10.6818 10.0248V3.00003C10.6818 2.66911 10.8812 2.37077 11.1869 2.24413ZM12.3182 13.9753L14.8429 16.5L12.3182 19.0248V13.9753ZM12.3182 10.0248V4.9753L14.8429 7.50003L12.3182 10.0248Z" fill="#80EBB6"/>
+</svg>
diff --git a/examples/bluetooth/heartrate-game/qml/images/bt_off_to_on.png b/examples/bluetooth/heartrate-game/images/bt_off_to_on.png
index 5ea1f3f0..5ea1f3f0 100644
--- a/examples/bluetooth/heartrate-game/qml/images/bt_off_to_on.png
+++ b/examples/bluetooth/heartrate-game/images/bt_off_to_on.png
Binary files differ
diff --git a/examples/bluetooth/heartrate-game/images/clock.svg b/examples/bluetooth/heartrate-game/images/clock.svg
new file mode 100644
index 00000000..655996ba
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/images/clock.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M8 20H16V17C16 15.9 15.6083 14.9583 14.825 14.175C14.0417 13.3917 13.1 13 12 13C10.9 13 9.95833 13.3917 9.175 14.175C8.39167 14.9583 8 15.9 8 17V20ZM12 11C13.1 11 14.0417 10.6083 14.825 9.825C15.6083 9.04167 16 8.1 16 7V4H8V7C8 8.1 8.39167 9.04167 9.175 9.825C9.95833 10.6083 10.9 11 12 11ZM5 22C4.44772 22 4 21.5523 4 21C4 20.4477 4.44772 20 5 20H6V17C6 15.9833 6.2375 15.0292 6.7125 14.1375C7.1875 13.2458 7.85 12.5333 8.7 12C7.85 11.4667 7.1875 10.7542 6.7125 9.8625C6.2375 8.97083 6 8.01667 6 7V4H5C4.44772 4 4 3.55228 4 3C4 2.44772 4.44772 2 5 2H19C19.5523 2 20 2.44772 20 3C20 3.55228 19.5523 4 19 4H18V7C18 8.01667 17.7625 8.97083 17.2875 9.8625C16.8125 10.7542 16.15 11.4667 15.3 12C16.15 12.5333 16.8125 13.2458 17.2875 14.1375C17.7625 15.0292 18 15.9833 18 17V20H19C19.5523 20 20 20.4477 20 21C20 21.5523 19.5523 22 19 22H5Z" fill="#80EBB6"/>
+<path d="M17 22H7L7 18C7 15.2386 9.23858 13 12 13C14.7614 13 17 15.2386 17 18V22Z" fill="#80EBB6"/>
+</svg>
diff --git a/examples/bluetooth/heartrate-game/images/heart.png b/examples/bluetooth/heartrate-game/images/heart.png
new file mode 100644
index 00000000..4ba0f822
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/images/heart.png
Binary files differ
diff --git a/examples/bluetooth/heartrate-game/qml/images/logo.png b/examples/bluetooth/heartrate-game/images/logo.png
index ea0af7e0..ea0af7e0 100644
--- a/examples/bluetooth/heartrate-game/qml/images/logo.png
+++ b/examples/bluetooth/heartrate-game/images/logo.png
Binary files differ
diff --git a/examples/bluetooth/heartrate-game/images/progress.svg b/examples/bluetooth/heartrate-game/images/progress.svg
new file mode 100644
index 00000000..449fe5e7
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/images/progress.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19 11C19 11.5523 19.4477 12 20 12C20.5523 12 21 11.5523 21 11V10.8478C21 8.11075 19.7088 5.53404 17.5163 3.89561C17.0739 3.56501 16.4472 3.65565 16.1166 4.09805C15.786 4.54046 15.8767 5.1671 16.3191 5.4977C18.0064 6.75857 19 8.74149 19 10.8478V11ZM4 12C4.55228 12 5 11.5523 5 11V10.8478C5 8.74149 5.99363 6.75857 7.68091 5.4977C8.12331 5.1671 8.21395 4.54046 7.88335 4.09805C7.55275 3.65565 6.92611 3.56501 6.4837 3.89561C4.29117 5.53404 3 8.11075 3 10.8478V11C3 11.5523 3.44772 12 4 12ZM7.10555 19.5528C7.35253 19.0588 7.95321 18.8586 8.44719 19.1055C10.6837 20.2238 13.3162 20.2238 15.5528 19.1056C16.0467 18.8586 16.6474 19.0588 16.8944 19.5528C17.1414 20.0468 16.9412 20.6474 16.4472 20.8944C13.6476 22.2942 10.3523 22.2942 7.55276 20.8944C7.05878 20.6474 6.85856 20.0467 7.10555 19.5528Z" fill="#80EBB6"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M13 5C13 5.55228 12.5523 6 12 6C11.4477 6 11 5.55228 11 5C11 4.44772 11.4477 4 12 4C12.5523 4 13 4.44772 13 5ZM15 5C15 6.65685 13.6569 8 12 8C10.3431 8 9 6.65685 9 5C9 3.34315 10.3431 2 12 2C13.6569 2 15 3.34315 15 5ZM5 17C5.55228 17 6 16.5523 6 16C6 15.4477 5.55228 15 5 15C4.44772 15 4 15.4477 4 16C4 16.5523 4.44772 17 5 17ZM5 19C6.65685 19 8 17.6569 8 16C8 14.3431 6.65685 13 5 13C3.34315 13 2 14.3431 2 16C2 17.6569 3.34315 19 5 19ZM19 17C19.5523 17 20 16.5523 20 16C20 15.4477 19.5523 15 19 15C18.4477 15 18 15.4477 18 16C18 16.5523 18.4477 17 19 17ZM19 19C20.6569 19 22 17.6569 22 16C22 14.3431 20.6569 13 19 13C17.3431 13 16 14.3431 16 16C16 17.6569 17.3431 19 19 19Z" fill="#80EBB6"/>
+</svg>
diff --git a/examples/bluetooth/heartrate-game/images/search.svg b/examples/bluetooth/heartrate-game/images/search.svg
new file mode 100644
index 00000000..9af5fe4d
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/images/search.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M14.2929 14.2929C14.6834 13.9024 15.3166 13.9024 15.7071 14.2929L21.7071 20.2929C22.0976 20.6834 22.0976 21.3166 21.7071 21.7071C21.3166 22.0976 20.6834 22.0976 20.2929 21.7071L14.2929 15.7071C13.9024 15.3166 13.9024 14.6834 14.2929 14.2929Z" fill="#80EBB6"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M10 4C6.68629 4 4 6.68629 4 10C4 13.3137 6.68629 16 10 16C13.3137 16 16 13.3137 16 10C16 6.68629 13.3137 4 10 4ZM2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10Z" fill="#80EBB6"/>
+</svg>
diff --git a/examples/bluetooth/heartrate-game/main.cpp b/examples/bluetooth/heartrate-game/main.cpp
index 05557c05..47192114 100644
--- a/examples/bluetooth/heartrate-game/main.cpp
+++ b/examples/bluetooth/heartrate-game/main.cpp
@@ -1,80 +1,56 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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$
-**
-****************************************************************************/
-
-#include <QGuiApplication>
-#include <QLoggingCategory>
-#include <QQmlApplicationEngine>
-#include <QQmlContext>
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "connectionhandler.h"
#include "devicefinder.h"
#include "devicehandler.h"
+#include "heartrate-global.h"
+
+#include <QCommandLineOption>
+#include <QCommandLineParser>
+#include <QLoggingCategory>
+
+#include <QGuiApplication>
+
+#include <QQmlApplicationEngine>
+
+using namespace Qt::StringLiterals;
+
+bool simulator = false;
int main(int argc, char *argv[])
{
- QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
- QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
+ QCommandLineParser parser;
+ parser.setApplicationDescription(u"Bluetooth Low Energy Heart Rate Game"_s);
+ parser.addHelpOption();
+ parser.addVersionOption();
+ QCommandLineOption simulatorOption(u"simulator"_s, u"Simulator"_s);
+ parser.addOption(simulatorOption);
+
+ QCommandLineOption verboseOption(u"verbose"_s, u"Verbose mode"_s);
+ parser.addOption(verboseOption);
+ parser.process(app);
+
+ if (parser.isSet(verboseOption))
+ QLoggingCategory::setFilterRules(u"qt.bluetooth* = true"_s);
+ simulator = parser.isSet(simulatorOption);
+
ConnectionHandler connectionHandler;
DeviceHandler deviceHandler;
DeviceFinder deviceFinder(&deviceHandler);
- qmlRegisterUncreatableType<DeviceHandler>("Shared", 1, 0, "AddressType", "Enum is not a type");
-
QQmlApplicationEngine engine;
- engine.rootContext()->setContextProperty("connectionHandler", &connectionHandler);
- engine.rootContext()->setContextProperty("deviceFinder", &deviceFinder);
- engine.rootContext()->setContextProperty("deviceHandler", &deviceHandler);
-
- engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
+ engine.setInitialProperties({
+ {u"connectionHandler"_s, QVariant::fromValue(&connectionHandler)},
+ {u"deviceFinder"_s, QVariant::fromValue(&deviceFinder)},
+ {u"deviceHandler"_s, QVariant::fromValue(&deviceHandler)}
+ });
+
+ QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &app,
+ []() { QCoreApplication::exit(1); }, Qt::QueuedConnection);
+ engine.loadFromModule("HeartRateGame", "Main");
return app.exec();
}
diff --git a/examples/bluetooth/heartrate-game/qml.qrc b/examples/bluetooth/heartrate-game/qml.qrc
deleted file mode 100644
index bab96355..00000000
--- a/examples/bluetooth/heartrate-game/qml.qrc
+++ /dev/null
@@ -1,18 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>qml/BluetoothAlarmDialog.qml</file>
- <file>qml/main.qml</file>
- <file>qml/SplashScreen.qml</file>
- <file>qml/GameSettings.qml</file>
- <file>qml/App.qml</file>
- <file>qml/TitleBar.qml</file>
- <file>qml/Connect.qml</file>
- <file>qml/Measure.qml</file>
- <file>qml/Stats.qml</file>
- <file>qml/GameButton.qml</file>
- <file>qml/GamePage.qml</file>
- <file>qml/BottomLine.qml</file>
- <file>qml/StatsLabel.qml</file>
- <file>qml/qmldir</file>
- </qresource>
-</RCC>
diff --git a/examples/bluetooth/heartrate-game/qml/App.qml b/examples/bluetooth/heartrate-game/qml/App.qml
deleted file mode 100644
index b61a7374..00000000
--- a/examples/bluetooth/heartrate-game/qml/App.qml
+++ /dev/null
@@ -1,130 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.5
-
-Item {
- id: app
- anchors.fill: parent
- opacity: 0.0
-
- Behavior on opacity { NumberAnimation { duration: 500 } }
-
- property var lastPages: []
- property int __currentIndex: 0
-
- function init()
- {
- opacity = 1.0
- showPage("Connect.qml")
- }
-
- function prevPage()
- {
- lastPages.pop()
- pageLoader.setSource(lastPages[lastPages.length-1])
- __currentIndex = lastPages.length-1;
- }
-
- function showPage(name)
- {
- lastPages.push(name)
- pageLoader.setSource(name)
- __currentIndex = lastPages.length-1;
- }
-
- TitleBar {
- id: titleBar
- currentIndex: __currentIndex
-
- onTitleClicked: {
- if (index < __currentIndex)
- pageLoader.item.close()
- }
- }
-
- Loader {
- id: pageLoader
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.top: titleBar.bottom
- anchors.bottom: parent.bottom
-
- onStatusChanged: {
- if (status === Loader.Ready)
- {
- pageLoader.item.init();
- pageLoader.item.forceActiveFocus()
- }
- }
- }
-
- Keys.onReleased: {
- switch (event.key) {
- case Qt.Key_Escape:
- case Qt.Key_Back: {
- if (__currentIndex > 0) {
- pageLoader.item.close()
- event.accepted = true
- } else {
- Qt.quit()
- }
- break;
- }
- default: break;
- }
- }
-
- BluetoothAlarmDialog {
- id: btAlarmDialog
- anchors.fill: parent
- visible: !connectionHandler.alive
- }
-}
diff --git a/examples/bluetooth/heartrate-game/qml/BluetoothAlarmDialog.qml b/examples/bluetooth/heartrate-game/qml/BluetoothAlarmDialog.qml
deleted file mode 100644
index df55c300..00000000
--- a/examples/bluetooth/heartrate-game/qml/BluetoothAlarmDialog.qml
+++ /dev/null
@@ -1,122 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.5
-
-Item {
- id: root
- anchors.fill: parent
-
- Rectangle {
- anchors.fill: parent
- color: "black"
- opacity: 0.9
- }
-
- MouseArea {
- id: eventEater
- }
-
- Rectangle {
- id: dialogFrame
-
- anchors.centerIn: parent
- width: parent.width * 0.8
- height: parent.height * 0.6
- border.color: "#454545"
- color: GameSettings.backgroundColor
- radius: width * 0.05
-
- Item {
- id: dialogContainer
- anchors.fill: parent
- anchors.margins: parent.width*0.05
-
- Image {
- id: offOnImage
- anchors.left: quitButton.left
- anchors.right: quitButton.right
- anchors.top: parent.top
- height: GameSettings.heightForWidth(width, sourceSize)
- source: "images/bt_off_to_on.png"
- }
-
- Text {
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.top: offOnImage.bottom
- anchors.bottom: quitButton.top
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- wrapMode: Text.WordWrap
- font.pixelSize: GameSettings.mediumFontSize
- color: GameSettings.textColor
- text: qsTr("This application cannot be used without Bluetooth. Please switch Bluetooth ON to continue.")
- }
-
- GameButton {
- id: quitButton
- anchors.bottom: parent.bottom
- anchors.horizontalCenter: parent.horizontalCenter
- width: dialogContainer.width * 0.6
- height: GameSettings.buttonHeight
- onClicked: Qt.quit()
-
- Text {
- anchors.centerIn: parent
- color: GameSettings.textColor
- font.pixelSize: GameSettings.bigFontSize
- text: qsTr("Quit")
- }
- }
- }
- }
-}
-
diff --git a/examples/bluetooth/heartrate-game/qml/BottomLine.qml b/examples/bluetooth/heartrate-game/qml/BottomLine.qml
deleted file mode 100644
index 6e99474a..00000000
--- a/examples/bluetooth/heartrate-game/qml/BottomLine.qml
+++ /dev/null
@@ -1,59 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.5
-
-Rectangle {
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.bottom: parent.bottom
- width: parent.width * 0.85
- height: parent.height * 0.05
- radius: height*0.5
-}
diff --git a/examples/bluetooth/heartrate-game/qml/Connect.qml b/examples/bluetooth/heartrate-game/qml/Connect.qml
deleted file mode 100644
index 519fe302..00000000
--- a/examples/bluetooth/heartrate-game/qml/Connect.qml
+++ /dev/null
@@ -1,188 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.5
-import Shared 1.0
-
-GamePage {
-
- errorMessage: deviceFinder.error
- infoMessage: deviceFinder.info
-
- Rectangle {
- id: viewContainer
- anchors.top: parent.top
- anchors.bottom:
- // only BlueZ platform has address type selection
- connectionHandler.requiresAddressType ? addressTypeButton.top : searchButton.top
- anchors.topMargin: GameSettings.fieldMargin + messageHeight
- anchors.bottomMargin: GameSettings.fieldMargin
- anchors.horizontalCenter: parent.horizontalCenter
- width: parent.width - GameSettings.fieldMargin*2
- color: GameSettings.viewColor
- radius: GameSettings.buttonRadius
-
-
- Text {
- id: title
- width: parent.width
- height: GameSettings.fieldHeight
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- color: GameSettings.textColor
- font.pixelSize: GameSettings.mediumFontSize
- text: qsTr("FOUND DEVICES")
-
- BottomLine {
- height: 1;
- width: parent.width
- color: "#898989"
- }
- }
-
-
- ListView {
- id: devices
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- anchors.top: title.bottom
- model: deviceFinder.devices
- clip: true
-
- delegate: Rectangle {
- id: box
- height:GameSettings.fieldHeight * 1.2
- width: parent.width
- color: index % 2 === 0 ? GameSettings.delegate1Color : GameSettings.delegate2Color
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- deviceFinder.connectToService(modelData.deviceAddress);
- app.showPage("Measure.qml")
- }
- }
-
- Text {
- id: device
- font.pixelSize: GameSettings.smallFontSize
- text: modelData.deviceName
- anchors.top: parent.top
- anchors.topMargin: parent.height * 0.1
- anchors.leftMargin: parent.height * 0.1
- anchors.left: parent.left
- color: GameSettings.textColor
- }
-
- Text {
- id: deviceAddress
- font.pixelSize: GameSettings.smallFontSize
- text: modelData.deviceAddress
- anchors.bottom: parent.bottom
- anchors.bottomMargin: parent.height * 0.1
- anchors.rightMargin: parent.height * 0.1
- anchors.right: parent.right
- color: Qt.darker(GameSettings.textColor)
- }
- }
- }
- }
-
- GameButton {
- id: addressTypeButton
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.bottom: searchButton.top
- anchors.bottomMargin: GameSettings.fieldMargin*0.5
- width: viewContainer.width
- height: GameSettings.fieldHeight
- visible: connectionHandler.requiresAddressType // only required on BlueZ
- state: "public"
- onClicked: state == "public" ? state = "random" : state = "public"
-
- states: [
- State {
- name: "public"
- PropertyChanges { target: addressTypeText; text: qsTr("Public Address") }
- PropertyChanges { target: deviceHandler; addressType: AddressType.PublicAddress }
- },
- State {
- name: "random"
- PropertyChanges { target: addressTypeText; text: qsTr("Random Address") }
- PropertyChanges { target: deviceHandler; addressType: AddressType.RandomAddress }
- }
- ]
-
- Text {
- id: addressTypeText
- anchors.centerIn: parent
- font.pixelSize: GameSettings.tinyFontSize
- color: GameSettings.textColor
- }
- }
-
- GameButton {
- id: searchButton
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.bottom: parent.bottom
- anchors.bottomMargin: GameSettings.fieldMargin
- width: viewContainer.width
- height: GameSettings.fieldHeight
- enabled: !deviceFinder.scanning
- onClicked: deviceFinder.startSearch()
-
- Text {
- anchors.centerIn: parent
- font.pixelSize: GameSettings.tinyFontSize
- text: qsTr("START SEARCH")
- color: searchButton.enabled ? GameSettings.textColor : GameSettings.disabledTextColor
- }
- }
-}
diff --git a/examples/bluetooth/heartrate-game/qml/GameButton.qml b/examples/bluetooth/heartrate-game/qml/GameButton.qml
deleted file mode 100644
index eabd8dcd..00000000
--- a/examples/bluetooth/heartrate-game/qml/GameButton.qml
+++ /dev/null
@@ -1,88 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.5
-import "."
-
-Rectangle {
- id: button
- color: baseColor
- onEnabledChanged: checkColor()
- radius: GameSettings.buttonRadius
-
- property color baseColor: GameSettings.buttonColor
- property color pressedColor: GameSettings.buttonPressedColor
- property color disabledColor: GameSettings.disabledButtonColor
-
- signal clicked()
-
- function checkColor()
- {
- if (!button.enabled) {
- button.color = disabledColor
- } else {
- if (mouseArea.containsPress)
- button.color = pressedColor
- else
- button.color = baseColor
- }
- }
-
- MouseArea {
- id: mouseArea
- anchors.fill: parent
- onPressed: checkColor()
- onReleased: checkColor()
- onClicked: {
- checkColor()
- button.clicked()
- }
- }
-}
diff --git a/examples/bluetooth/heartrate-game/qml/GamePage.qml b/examples/bluetooth/heartrate-game/qml/GamePage.qml
deleted file mode 100644
index 5e432e58..00000000
--- a/examples/bluetooth/heartrate-game/qml/GamePage.qml
+++ /dev/null
@@ -1,93 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.5
-import "."
-
-Item {
- anchors.fill: parent
-
- property string errorMessage: ""
- property string infoMessage: ""
- property real messageHeight: msg.height
- property bool hasError: errorMessage != ""
- property bool hasInfo: infoMessage != ""
-
- function init()
- {
- }
-
- function close()
- {
- app.prevPage()
- }
-
- Rectangle {
- id: msg
- anchors.top: parent.top
- anchors.left: parent.left
- anchors.right: parent.right
- height: GameSettings.fieldHeight
- color: hasError ? GameSettings.errorColor : GameSettings.infoColor
- visible: hasError || hasInfo
-
- Text {
- id: error
- anchors.fill: parent
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- minimumPixelSize: 5
- font.pixelSize: GameSettings.smallFontSize
- fontSizeMode: Text.Fit
- color: GameSettings.textColor
- text: hasError ? errorMessage : infoMessage
- }
- }
-}
diff --git a/examples/bluetooth/heartrate-game/qml/GameSettings.qml b/examples/bluetooth/heartrate-game/qml/GameSettings.qml
deleted file mode 100644
index e9edde90..00000000
--- a/examples/bluetooth/heartrate-game/qml/GameSettings.qml
+++ /dev/null
@@ -1,101 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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$
-**
-****************************************************************************/
-
-pragma Singleton
-import QtQuick 2.5
-
-Item {
- property int wHeight
- property int wWidth
-
- // Colors
- readonly property color backgroundColor: "#2d3037"
- readonly property color buttonColor: "#202227"
- readonly property color buttonPressedColor: "#6ccaf2"
- readonly property color disabledButtonColor: "#555555"
- readonly property color viewColor: "#202227"
- readonly property color delegate1Color: Qt.darker(viewColor, 1.2)
- readonly property color delegate2Color: Qt.lighter(viewColor, 1.2)
- readonly property color textColor: "#ffffff"
- readonly property color textDarkColor: "#232323"
- readonly property color disabledTextColor: "#777777"
- readonly property color sliderColor: "#6ccaf2"
- readonly property color errorColor: "#ba3f62"
- readonly property color infoColor: "#3fba62"
-
- // Font sizes
- property real microFontSize: hugeFontSize * 0.2
- property real tinyFontSize: hugeFontSize * 0.4
- property real smallTinyFontSize: hugeFontSize * 0.5
- property real smallFontSize: hugeFontSize * 0.6
- property real mediumFontSize: hugeFontSize * 0.7
- property real bigFontSize: hugeFontSize * 0.8
- property real largeFontSize: hugeFontSize * 0.9
- property real hugeFontSize: (wWidth + wHeight) * 0.03
- property real giganticFontSize: (wWidth + wHeight) * 0.04
-
- // Some other values
- property real fieldHeight: wHeight * 0.08
- property real fieldMargin: fieldHeight * 0.5
- property real buttonHeight: wHeight * 0.08
- property real buttonRadius: buttonHeight * 0.1
-
- // Some help functions
- function widthForHeight(h, ss)
- {
- return h/ss.height * ss.width;
- }
-
- function heightForWidth(w, ss)
- {
- return w/ss.width * ss.height;
- }
-
-}
diff --git a/examples/bluetooth/heartrate-game/qml/Measure.qml b/examples/bluetooth/heartrate-game/qml/Measure.qml
deleted file mode 100644
index 07056e6e..00000000
--- a/examples/bluetooth/heartrate-game/qml/Measure.qml
+++ /dev/null
@@ -1,244 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.5
-
-GamePage {
- id: measurePage
-
- errorMessage: deviceHandler.error
- infoMessage: deviceHandler.info
-
- property real __timeCounter: 0;
- property real __maxTimeCount: 60
- property string relaxText: qsTr("Relax!\nWhen you are ready, press Start. You have %1s time to increase heartrate so much as possible.\nGood luck!").arg(__maxTimeCount)
-
- function close()
- {
- deviceHandler.stopMeasurement();
- deviceHandler.disconnectService();
- app.prevPage();
- }
-
- function start()
- {
- if (!deviceHandler.measuring) {
- __timeCounter = 0;
- deviceHandler.startMeasurement()
- }
- }
-
- function stop()
- {
- if (deviceHandler.measuring) {
- deviceHandler.stopMeasurement()
- }
-
- app.showPage("Stats.qml")
- }
-
- Timer {
- id: measureTimer
- interval: 1000
- running: deviceHandler.measuring
- repeat: true
- onTriggered: {
- __timeCounter++;
- if (__timeCounter >= __maxTimeCount)
- measurePage.stop()
- }
- }
-
- Column {
- anchors.centerIn: parent
- spacing: GameSettings.fieldHeight * 0.5
-
- Rectangle {
- id: circle
- anchors.horizontalCenter: parent.horizontalCenter
- width: Math.min(measurePage.width, measurePage.height-GameSettings.fieldHeight*4) - 2*GameSettings.fieldMargin
- height: width
- radius: width*0.5
- color: GameSettings.viewColor
-
- Text {
- id: hintText
- anchors.centerIn: parent
- anchors.verticalCenterOffset: -parent.height*0.1
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- width: parent.width * 0.8
- height: parent.height * 0.6
- wrapMode: Text.WordWrap
- text: measurePage.relaxText
- visible: !deviceHandler.measuring
- color: GameSettings.textColor
- fontSizeMode: Text.Fit
- minimumPixelSize: 10
- font.pixelSize: GameSettings.mediumFontSize
- }
-
- Text {
- id: text
- anchors.centerIn: parent
- anchors.verticalCenterOffset: -parent.height*0.15
- font.pixelSize: parent.width * 0.45
- text: deviceHandler.hr
- visible: deviceHandler.measuring
- color: GameSettings.textColor
- }
-
- Item {
- id: minMaxContainer
- anchors.horizontalCenter: parent.horizontalCenter
- width: parent.width*0.7
- height: parent.height * 0.15
- anchors.bottom: parent.bottom
- anchors.bottomMargin: parent.height*0.16
- visible: deviceHandler.measuring
-
- Text {
- anchors.left: parent.left
- anchors.verticalCenter: parent.verticalCenter
- text: deviceHandler.minHR
- color: GameSettings.textColor
- font.pixelSize: GameSettings.hugeFontSize
-
- Text {
- anchors.left: parent.left
- anchors.bottom: parent.top
- font.pixelSize: parent.font.pixelSize*0.8
- color: parent.color
- text: "MIN"
- }
- }
-
- Text {
- anchors.right: parent.right
- anchors.verticalCenter: parent.verticalCenter
- text: deviceHandler.maxHR
- color: GameSettings.textColor
- font.pixelSize: GameSettings.hugeFontSize
-
- Text {
- anchors.right: parent.right
- anchors.bottom: parent.top
- font.pixelSize: parent.font.pixelSize*0.8
- color: parent.color
- text: "MAX"
- }
- }
- }
-
- Image {
- id: heart
- anchors.horizontalCenter: minMaxContainer.horizontalCenter
- anchors.verticalCenter: minMaxContainer.bottom
- width: parent.width * 0.2
- height: width
- source: "images/heart.png"
- smooth: true
- antialiasing: true
-
- SequentialAnimation{
- id: heartAnim
- running: deviceHandler.alive
- loops: Animation.Infinite
- alwaysRunToEnd: true
- PropertyAnimation { target: heart; property: "scale"; to: 1.2; duration: 500; easing.type: Easing.InQuad }
- PropertyAnimation { target: heart; property: "scale"; to: 1.0; duration: 500; easing.type: Easing.OutQuad }
- }
- }
- }
-
- Rectangle {
- id: timeSlider
- color: GameSettings.viewColor
- anchors.horizontalCenter: parent.horizontalCenter
- width: circle.width
- height: GameSettings.fieldHeight
- radius: GameSettings.buttonRadius
-
- Rectangle {
- height: parent.height
- radius: parent.radius
- color: GameSettings.sliderColor
- width: Math.min(1.0,__timeCounter / __maxTimeCount) * parent.width
- }
-
- Text {
- anchors.centerIn: parent
- color: "gray"
- text: (__maxTimeCount - __timeCounter).toFixed(0) + " s"
- font.pixelSize: GameSettings.bigFontSize
- }
- }
- }
-
- GameButton {
- id: startButton
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.bottom: parent.bottom
- anchors.bottomMargin: GameSettings.fieldMargin
- width: circle.width
- height: GameSettings.fieldHeight
- enabled: !deviceHandler.measuring
- radius: GameSettings.buttonRadius
-
- onClicked: start()
-
- Text {
- anchors.centerIn: parent
- font.pixelSize: GameSettings.tinyFontSize
- text: qsTr("START")
- color: startButton.enabled ? GameSettings.textColor : GameSettings.disabledTextColor
- }
- }
-}
diff --git a/examples/bluetooth/heartrate-game/qml/SplashScreen.qml b/examples/bluetooth/heartrate-game/qml/SplashScreen.qml
deleted file mode 100644
index 59870188..00000000
--- a/examples/bluetooth/heartrate-game/qml/SplashScreen.qml
+++ /dev/null
@@ -1,90 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.5
-import "."
-
-Item {
- id: root
- anchors.fill: parent
-
- property bool appIsReady: false
- property bool splashIsReady: false
-
- property bool ready: appIsReady && splashIsReady
- onReadyChanged: if (ready) readyToGo();
-
- signal readyToGo()
-
- function appReady()
- {
- appIsReady = true
- }
-
- function errorInLoadingApp()
- {
- Qt.quit()
- }
-
- Image {
- anchors.centerIn: parent
- width: Math.min(parent.height, parent.width)*0.6
- height: GameSettings.heightForWidth(width, sourceSize)
- source: "images/logo.png"
- }
-
- Timer {
- id: splashTimer
- interval: 1000
- onTriggered: splashIsReady = true
- }
-
- Component.onCompleted: splashTimer.start()
-}
diff --git a/examples/bluetooth/heartrate-game/qml/Stats.qml b/examples/bluetooth/heartrate-game/qml/Stats.qml
deleted file mode 100644
index 5d45fc8c..00000000
--- a/examples/bluetooth/heartrate-game/qml/Stats.qml
+++ /dev/null
@@ -1,99 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.5
-
-GamePage {
-
- Column {
- anchors.centerIn: parent
- width: parent.width
-
- Text {
- anchors.horizontalCenter: parent.horizontalCenter
- font.pixelSize: GameSettings.hugeFontSize
- color: GameSettings.textColor
- text: qsTr("RESULT")
- }
-
- Text {
- anchors.horizontalCenter: parent.horizontalCenter
- font.pixelSize: GameSettings.giganticFontSize*3
- color: GameSettings.textColor
- text: (deviceHandler.maxHR - deviceHandler.minHR).toFixed(0)
- }
-
- Item {
- height: GameSettings.fieldHeight
- width: 1
- }
-
- StatsLabel {
- title: qsTr("MIN")
- value: deviceHandler.minHR.toFixed(0)
- }
-
- StatsLabel {
- title: qsTr("MAX")
- value: deviceHandler.maxHR.toFixed(0)
- }
-
- StatsLabel {
- title: qsTr("AVG")
- value: deviceHandler.average.toFixed(1)
- }
-
-
- StatsLabel {
- title: qsTr("CALORIES")
- value: deviceHandler.calories.toFixed(3)
- }
- }
-}
diff --git a/examples/bluetooth/heartrate-game/qml/StatsLabel.qml b/examples/bluetooth/heartrate-game/qml/StatsLabel.qml
deleted file mode 100644
index ff5e0fbb..00000000
--- a/examples/bluetooth/heartrate-game/qml/StatsLabel.qml
+++ /dev/null
@@ -1,82 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.5
-import "."
-
-Item {
- height: GameSettings.fieldHeight
- width: parent.width
-
- property alias title: leftText.text
- property alias value: rightText.text
-
- Text {
- id: leftText
- anchors.left: parent.left
- height: parent.height
- width: parent.width * 0.45
- horizontalAlignment: Text.AlignRight
- verticalAlignment: Text.AlignVCenter
- font.pixelSize: GameSettings.mediumFontSize
- color: GameSettings.textColor
- }
-
- Text {
- id: rightText
- anchors.right: parent.right
- height: parent.height
- width: parent.width * 0.45
- horizontalAlignment: Text.AlignLeft
- verticalAlignment: Text.AlignVCenter
- font.pixelSize: GameSettings.mediumFontSize
- color: GameSettings.textColor
- }
-}
diff --git a/examples/bluetooth/heartrate-game/qml/TitleBar.qml b/examples/bluetooth/heartrate-game/qml/TitleBar.qml
deleted file mode 100644
index 3a3e2c42..00000000
--- a/examples/bluetooth/heartrate-game/qml/TitleBar.qml
+++ /dev/null
@@ -1,97 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.5
-
-Rectangle {
- id: titleBar
- anchors.top: parent.top
- anchors.left: parent.left
- anchors.right: parent.right
- height: GameSettings.fieldHeight
- color: GameSettings.viewColor
-
- property var __titles: ["CONNECT", "MEASURE", "STATS"]
- property int currentIndex: 0
-
- signal titleClicked(int index)
-
- Repeater {
- model: 3
- Text {
- width: titleBar.width / 3
- height: titleBar.height
- x: index * width
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- text: __titles[index]
- font.pixelSize: GameSettings.tinyFontSize
- color: titleBar.currentIndex === index ? GameSettings.textColor : GameSettings.disabledTextColor
-
- MouseArea {
- anchors.fill: parent
- onClicked: titleClicked(index)
- }
- }
- }
-
-
- Item {
- anchors.bottom: parent.bottom
- width: parent.width / 3
- height: parent.height
- x: currentIndex * width
-
- BottomLine{}
-
- Behavior on x { NumberAnimation { duration: 200 } }
- }
-
-}
diff --git a/examples/bluetooth/heartrate-game/qml/images/heart.png b/examples/bluetooth/heartrate-game/qml/images/heart.png
deleted file mode 100644
index f2b3c0a3..00000000
--- a/examples/bluetooth/heartrate-game/qml/images/heart.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/heartrate-game/qml/main.qml b/examples/bluetooth/heartrate-game/qml/main.qml
deleted file mode 100644
index 0dfeef44..00000000
--- a/examples/bluetooth/heartrate-game/qml/main.qml
+++ /dev/null
@@ -1,105 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.7
-import QtQuick.Window 2.2
-import "."
-
-Window {
- id: wroot
- visible: true
- width: 720 * .7
- height: 1240 * .7
- title: qsTr("HeartRateGame")
- color: GameSettings.backgroundColor
-
- Component.onCompleted: {
- GameSettings.wWidth = Qt.binding(function() {return width})
- GameSettings.wHeight = Qt.binding(function() {return height})
- }
-
- Loader {
- id: splashLoader
- anchors.fill: parent
- source: "SplashScreen.qml"
- asynchronous: false
- visible: true
-
- onStatusChanged: {
- if (status === Loader.Ready) {
- appLoader.setSource("App.qml");
- }
- }
- }
-
- Connections {
- target: splashLoader.item
- onReadyToGo: {
- appLoader.visible = true
- appLoader.item.init()
- splashLoader.visible = false
- splashLoader.setSource("")
- appLoader.item.forceActiveFocus();
- }
- }
-
- Loader {
- id: appLoader
- anchors.fill: parent
- visible: false
- asynchronous: true
- onStatusChanged: {
- if (status === Loader.Ready)
- splashLoader.item.appReady()
- if (status === Loader.Error)
- splashLoader.item.errorInLoadingApp();
- }
- }
-}
diff --git a/examples/bluetooth/heartrate-game/qml/qmldir b/examples/bluetooth/heartrate-game/qml/qmldir
deleted file mode 100644
index 5e0d2b54..00000000
--- a/examples/bluetooth/heartrate-game/qml/qmldir
+++ /dev/null
@@ -1 +0,0 @@
-singleton GameSettings 1.0 GameSettings.qml
diff --git a/examples/bluetooth/heartrate-game/qmldir b/examples/bluetooth/heartrate-game/qmldir
new file mode 100644
index 00000000..161e6bab
--- /dev/null
+++ b/examples/bluetooth/heartrate-game/qmldir
@@ -0,0 +1,15 @@
+module HeartRateGame
+prefer :/qt/qml/HeartRateGame/
+App 1.0 App.qml
+BluetoothAlarmDialog 1.0 BluetoothAlarmDialog.qml
+BottomLine 1.0 BottomLine.qml
+Connect 1.0 Connect.qml
+GameButton 1.0 GameButton.qml
+GamePage 1.0 GamePage.qml
+singleton GameSettings 1.0 GameSettings.qml
+Measure 1.0 Measure.qml
+SplashScreen 1.0 SplashScreen.qml
+Stats 1.0 Stats.qml
+StatsLabel 1.0 StatsLabel.qml
+TitleBar 1.0 TitleBar.qml
+Main 1.0 Main.qml
diff --git a/examples/bluetooth/heartrate-server/CMakeLists.txt b/examples/bluetooth/heartrate-server/CMakeLists.txt
new file mode 100644
index 00000000..505e967c
--- /dev/null
+++ b/examples/bluetooth/heartrate-server/CMakeLists.txt
@@ -0,0 +1,58 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(heartrate-server LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/bluetooth/heartrate-server")
+
+find_package(Qt6 REQUIRED COMPONENTS Bluetooth Core)
+
+qt_standard_project_setup()
+
+if(ANDROID OR APPLE)
+ find_package(Qt6 REQUIRED COMPONENTS Gui)
+endif()
+
+qt_add_executable(heartrate-server
+ main.cpp
+)
+
+set_target_properties(heartrate-server PROPERTIES
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(heartrate-server PRIVATE
+ Qt6::Bluetooth
+ Qt6::Core
+)
+
+if(ANDROID OR APPLE)
+ target_link_libraries(heartrate-server PRIVATE
+ Qt6::Gui
+ )
+endif()
+
+if (APPLE)
+ # Using absolute path for shared plist files is a Ninja bug workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../shared ABSOLUTE)
+ if (IOS)
+ set_target_properties(heartrate-server PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.cmake.ios.plist"
+ )
+ else()
+ set_target_properties(heartrate-server PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.cmake.macos.plist"
+ )
+ endif()
+endif()
+
+install(TARGETS heartrate-server
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/bluetooth/heartrate-server/doc/src/heartrate-server.qdoc b/examples/bluetooth/heartrate-server/doc/src/heartrate-server.qdoc
index 7e0c29e8..30725aed 100644
--- a/examples/bluetooth/heartrate-server/doc/src/heartrate-server.qdoc
+++ b/examples/bluetooth/heartrate-server/doc/src/heartrate-server.qdoc
@@ -1,39 +1,18 @@
-/****************************************************************************
-**
-** 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
/*!
\example heartrate-server
- \title Bluetooth Low Energy Heart Rate Server Example
+ \title Bluetooth Low Energy Heart Rate Server
+ \examplecategory {Connectivity}
+ \meta tags {bluetooth, ble}
+
\brief An example demonstrating how to set up and advertise a GATT service. The example
- demonstrates the use of the Qt Bluetooth Low Energy classes related to peripheral (slave)
+ demonstrates the use of the \l{Qt Bluetooth} Low Energy classes related to peripheral (slave)
functionality.
The Bluetooth Low Energy Heart Rate Server is a command-line application that shows how to
- develop a Bluetooth GATT server using the Qt Bluetooth API.
+ develop a Bluetooth GATT server using the \l{QtBluetooth}{Qt Bluetooth API}.
The application covers setting up a service, advertising it and notifying clients about changes
to characteristic values.
@@ -54,14 +33,28 @@
To visualize what it is doing, you can use the \l {heartrate-game}{Heart Rate Game}
example, which is basically the client-side counterpart to this application.
- \note On Linux, advertising requires privileged access, so you need to run
- the example as root, for instance via \c sudo.
+ \section1 Checking Bluetooth Permission
+ Before the application can create a service and start advertising, we have to check
+ if the application has a permission to use Bluetooth.
+ \snippet heartrate-server/main.cpp Check Bluetooth Permission
+
+ \section1 Request Bluetooth Permission
+ If the Bluetooth authorization status is undetermined, we have to request a permission
+ to use Bluetooth.
+ \snippet heartrate-server/main.cpp Request Bluetooth Permission
\section1 Setting up Advertising Data and Parameters
- Two classes are used to configure the advertising process: \l QLowEnergyAdvertisingData to
- specify which information is to be broadcast, and \l QLowEnergyAdvertisingParameters for
- specific aspects such as setting the advertising interval or controlling which devices are
- allowed to connect. In our example, we simply use the default parameters.
+
+ Two classes are used to configure the advertising process:
+ \list
+ \li \l QLowEnergyAdvertisingData specifies which information is to be
+ broadcasted
+ \li \l QLowEnergyAdvertisingParameters is used for specific aspects such
+ as setting the advertising interval or controlling which devices are
+ allowed to connect.
+ \endlist
+
+ In our example, we simply use the default parameters.
The information contained in the \l QLowEnergyAdvertisingData will be visible to other devices
that are currently scanning. They can use it to decide whether they want to establish a connection
@@ -74,13 +67,16 @@
\snippet heartrate-server/main.cpp Advertising Data
\section1 Setting up Service Data
- Next we configure the kind of service we want to offer. We use the \c {Heart Rate} service as
- defined in the Bluetooth specification in its minimal form, that is, consisting only of the
- \c {Heart Rate Measurement} characteristic. This characteristic must support the \c Notify
- property (and no others), and it needs to have a \c {Client Characteristic Configuration}
- descriptor, which enables clients to register to get notified about changes to characteristic
- values. We set the initial heart rate value to zero, as it cannot be read anyway (the only
- way the client can get at the value is via notifications).
+ Next we configure the kind of service we want to offer. We use the
+ \l {QBluetoothUuid::ServiceClassUuid}{Heart Rate} service as defined in the
+ Bluetooth specification in its minimal form, that is, consisting only of the
+ \l {QBluetoothUuid::CharacteristicType}{Heart Rate Measurement} characteristic.
+ This characteristic must support the \l {QLowEnergyCharacteristic::}{Notify}
+ property (and no others), and it needs to have a \l {QBluetoothUuid::DescriptorType}
+ {Client Characteristic Configuration} descriptor, which enables clients to
+ register to get notified about changes to characteristic values. We set the
+ initial heart rate value to zero, as it cannot be read anyway (the only way
+ the client can get the value is via notifications).
\snippet heartrate-server/main.cpp Service Data
\section1 Advertising and Listening for Incoming Connections
diff --git a/examples/bluetooth/heartrate-server/heartrate-server.pro b/examples/bluetooth/heartrate-server/heartrate-server.pro
index edd011b9..56869fd7 100644
--- a/examples/bluetooth/heartrate-server/heartrate-server.pro
+++ b/examples/bluetooth/heartrate-server/heartrate-server.pro
@@ -2,9 +2,14 @@ TEMPLATE = app
TARGET = heartrate-server
QT = core bluetooth
-CONFIG += c++11
+android|darwin: QT += gui
+
+CONFIG += console
SOURCES += main.cpp
+ios: QMAKE_INFO_PLIST = ../shared/Info.qmake.ios.plist
+macos: QMAKE_INFO_PLIST = ../shared/Info.qmake.macos.plist
+
target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/heartrate-server
INSTALLS += target
diff --git a/examples/bluetooth/heartrate-server/main.cpp b/examples/bluetooth/heartrate-server/main.cpp
index ea01d07d..90b4461c 100644
--- a/examples/bluetooth/heartrate-server/main.cpp
+++ b/examples/bluetooth/heartrate-server/main.cpp
@@ -1,101 +1,108 @@
-/***************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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$
-**
-****************************************************************************/
-
-#include <QtBluetooth/qlowenergyadvertisingdata.h>
-#include <QtBluetooth/qlowenergyadvertisingparameters.h>
-#include <QtBluetooth/qlowenergycharacteristic.h>
-#include <QtBluetooth/qlowenergycharacteristicdata.h>
-#include <QtBluetooth/qlowenergydescriptordata.h>
-#include <QtBluetooth/qlowenergycontroller.h>
-#include <QtBluetooth/qlowenergyservice.h>
-#include <QtBluetooth/qlowenergyservicedata.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qscopedpointer.h>
-#include <QtCore/qtimer.h>
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QLowEnergyAdvertisingData>
+#include <QLowEnergyAdvertisingParameters>
+#include <QLowEnergyCharacteristic>
+#include <QLowEnergyCharacteristicData>
+#include <QLowEnergyDescriptorData>
+#include <QLowEnergyController>
+#include <QLowEnergyService>
+#include <QLowEnergyServiceData>
+
+#include <QByteArray>
+
+#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN)
+#include <QGuiApplication>
+#else
+#include <QCoreApplication>
+#endif
+
+#include <QList>
+#include <QLoggingCategory>
+#include <QTimer>
+
+#if QT_CONFIG(permissions)
+#include <QPermissions>
+#endif
+
+#include <memory>
int main(int argc, char *argv[])
{
- //QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
+ // QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
+#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN)
+ QGuiApplication app(argc, argv);
+#else
QCoreApplication app(argc, argv);
+#endif
+#if QT_CONFIG(permissions)
+ //! [Check Bluetooth Permission]
+ auto permissionStatus = app.checkPermission(QBluetoothPermission{});
+ //! [Check Bluetooth Permission]
+
+ //! [Request Bluetooth Permission]
+ if (permissionStatus == Qt::PermissionStatus::Undetermined) {
+ qInfo("Requesting Bluetooth permission ...");
+ app.requestPermission(QBluetoothPermission{}, [&permissionStatus](const QPermission &permission){
+ qApp->exit();
+ permissionStatus = permission.status();
+ });
+ // Now, wait for permission request to resolve.
+ app.exec();
+ }
+ //! [Request Bluetooth Permission]
+
+ if (permissionStatus == Qt::PermissionStatus::Denied) {
+ // Either explicitly denied by a user, or Bluetooth is off.
+ qWarning("This application cannot use Bluetooth, the permission was denied");
+ return -1;
+ }
+
+#endif
//! [Advertising Data]
QLowEnergyAdvertisingData advertisingData;
advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral);
advertisingData.setIncludePowerLevel(true);
advertisingData.setLocalName("HeartRateServer");
- advertisingData.setServices(QList<QBluetoothUuid>() << QBluetoothUuid::HeartRate);
+ advertisingData.setServices(QList<QBluetoothUuid>() << QBluetoothUuid::ServiceClassUuid::HeartRate);
//! [Advertising Data]
//! [Service Data]
QLowEnergyCharacteristicData charData;
- charData.setUuid(QBluetoothUuid::HeartRateMeasurement);
+ charData.setUuid(QBluetoothUuid::CharacteristicType::HeartRateMeasurement);
charData.setValue(QByteArray(2, 0));
charData.setProperties(QLowEnergyCharacteristic::Notify);
- const QLowEnergyDescriptorData clientConfig(QBluetoothUuid::ClientCharacteristicConfiguration,
+ const QLowEnergyDescriptorData clientConfig(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration,
QByteArray(2, 0));
charData.addDescriptor(clientConfig);
QLowEnergyServiceData serviceData;
serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
- serviceData.setUuid(QBluetoothUuid::HeartRate);
+ serviceData.setUuid(QBluetoothUuid::ServiceClassUuid::HeartRate);
serviceData.addCharacteristic(charData);
//! [Service Data]
//! [Start Advertising]
- const QScopedPointer<QLowEnergyController> leController(QLowEnergyController::createPeripheral());
- QScopedPointer<QLowEnergyService> service(leController->addService(serviceData));
+ bool errorOccurred = false;
+ const std::unique_ptr<QLowEnergyController> leController(QLowEnergyController::createPeripheral());
+ auto errorHandler = [&leController, &errorOccurred](QLowEnergyController::Error errorCode) {
+ qWarning().noquote().nospace() << errorCode << " occurred: "
+ << leController->errorString();
+ if (errorCode != QLowEnergyController::RemoteHostClosedError) {
+ qWarning("Heartrate-server quitting due to the error.");
+ errorOccurred = true;
+ QCoreApplication::quit();
+ }
+ };
+ QObject::connect(leController.get(), &QLowEnergyController::errorOccurred, errorHandler);
+
+ std::unique_ptr<QLowEnergyService> service(leController->addService(serviceData));
leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData,
advertisingData);
+ if (errorOccurred)
+ return -1;
//! [Start Advertising]
//! [Provide Heartbeat]
@@ -107,7 +114,7 @@ int main(int argc, char *argv[])
value.append(char(0)); // Flags that specify the format of the value.
value.append(char(currentHeartRate)); // Actual value.
QLowEnergyCharacteristic characteristic
- = service->characteristic(QBluetoothUuid::HeartRateMeasurement);
+ = service->characteristic(QBluetoothUuid::CharacteristicType::HeartRateMeasurement);
Q_ASSERT(characteristic.isValid());
service->writeCharacteristic(characteristic, value); // Potentially causes notification.
if (currentHeartRate == 60)
@@ -123,14 +130,15 @@ int main(int argc, char *argv[])
heartbeatTimer.start(1000);
//! [Provide Heartbeat]
- auto reconnect = [&leController, advertisingData, &service, serviceData]()
- {
+ auto reconnect = [&leController, advertisingData, &service, serviceData]() {
service.reset(leController->addService(serviceData));
- if (!service.isNull())
+ if (service) {
leController->startAdvertising(QLowEnergyAdvertisingParameters(),
advertisingData, advertisingData);
+ }
};
- QObject::connect(leController.data(), &QLowEnergyController::disconnected, reconnect);
+ QObject::connect(leController.get(), &QLowEnergyController::disconnected, reconnect);
- return app.exec();
+ const int retval = QCoreApplication::exec();
+ return errorOccurred ? -1 : retval;
}
diff --git a/examples/bluetooth/lowenergyscanner/CMakeLists.txt b/examples/bluetooth/lowenergyscanner/CMakeLists.txt
new file mode 100644
index 00000000..bb7d8fa3
--- /dev/null
+++ b/examples/bluetooth/lowenergyscanner/CMakeLists.txt
@@ -0,0 +1,72 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(lowenergyscanner LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/bluetooth/lowenergyscanner")
+
+find_package(Qt6 REQUIRED COMPONENTS Bluetooth Core Gui Quick)
+
+qt_standard_project_setup(REQUIRES 6.5)
+
+qt_add_executable(lowenergyscanner
+ main.cpp
+)
+
+set_target_properties(lowenergyscanner PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(lowenergyscanner PUBLIC
+ Qt6::Bluetooth
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Quick
+)
+
+if (APPLE)
+ # Using absolute path for shared plist files is a Ninja bug workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../shared ABSOLUTE)
+ if (IOS)
+ set_target_properties(lowenergyscanner PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.cmake.ios.plist"
+ )
+ else()
+ set_target_properties(lowenergyscanner PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.cmake.macos.plist"
+ )
+ endif()
+endif()
+
+qt_add_qml_module(lowenergyscanner
+ URI Scanner
+ VERSION 1.0
+ SOURCES
+ characteristicinfo.cpp characteristicinfo.h
+ device.cpp device.h
+ deviceinfo.cpp deviceinfo.h
+ serviceinfo.cpp serviceinfo.h
+ QML_FILES
+ Characteristics.qml
+ Devices.qml
+ Dialog.qml
+ Header.qml
+ Label.qml
+ Main.qml
+ Menu.qml
+ Services.qml
+ RESOURCES
+ assets/busy_dark.png
+)
+
+install(TARGETS lowenergyscanner
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/bluetooth/lowenergyscanner/Characteristics.qml b/examples/bluetooth/lowenergyscanner/Characteristics.qml
new file mode 100644
index 00000000..5d140bd1
--- /dev/null
+++ b/examples/bluetooth/lowenergyscanner/Characteristics.qml
@@ -0,0 +1,121 @@
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+import QtQuick
+
+Rectangle {
+ id: characteristicsPage
+
+ signal showServices
+ signal showDevices
+
+ width: 300
+ height: 600
+
+ Header {
+ id: header
+ anchors.top: parent.top
+ headerText: "Characteristics list"
+ }
+
+ Dialog {
+ id: info
+ anchors.centerIn: parent
+ visible: true
+ dialogText: "Scanning for characteristics..."
+ }
+
+ Connections {
+ target: Device
+ function onCharacteristicsUpdated() {
+ menu.menuText = "Back"
+ if (characteristicview.count === 0) {
+ info.dialogText = "No characteristic found"
+ info.busyImage = false
+ } else {
+ info.visible = false
+ info.busyImage = true
+ }
+ }
+
+ function onDisconnected() {
+ characteristicsPage.showDevices()
+ }
+ }
+
+ ListView {
+ id: characteristicview
+ width: parent.width
+ clip: true
+
+ anchors.top: header.bottom
+ anchors.bottom: menu.top
+ model: Device.characteristicList
+
+ delegate: Rectangle {
+ required property var modelData
+ id: box
+ height: 300
+ width: characteristicview.width
+ color: "lightsteelblue"
+ border.width: 2
+ border.color: "black"
+ radius: 5
+
+ Label {
+ id: characteristicName
+ textContent: box.modelData.characteristicName
+ anchors.top: parent.top
+ anchors.topMargin: 5
+ }
+
+ Label {
+ id: characteristicUuid
+ font.pointSize: characteristicName.font.pointSize * 0.7
+ textContent: box.modelData.characteristicUuid
+ anchors.top: characteristicName.bottom
+ anchors.topMargin: 5
+ }
+
+ Label {
+ id: characteristicValue
+ font.pointSize: characteristicName.font.pointSize * 0.7
+ textContent: ("Value: " + box.modelData.characteristicValue)
+ anchors.bottom: characteristicHandle.top
+ horizontalAlignment: Text.AlignHCenter
+ anchors.topMargin: 5
+ }
+
+ Label {
+ id: characteristicHandle
+ font.pointSize: characteristicName.font.pointSize * 0.7
+ textContent: ("Handlers: " + box.modelData.characteristicHandle)
+ anchors.bottom: characteristicPermission.top
+ anchors.topMargin: 5
+ }
+
+ Label {
+ id: characteristicPermission
+ font.pointSize: characteristicName.font.pointSize * 0.7
+ textContent: box.modelData.characteristicPermission
+ anchors.bottom: parent.bottom
+ anchors.topMargin: 5
+ anchors.bottomMargin: 5
+ }
+ }
+ }
+
+ Menu {
+ id: menu
+ anchors.bottom: parent.bottom
+ menuWidth: parent.width
+ menuText: Device.update
+ menuHeight: (parent.height / 6)
+ onButtonClick: {
+ characteristicsPage.showServices()
+ Device.update = "Back"
+ }
+ }
+}
diff --git a/examples/bluetooth/lowenergyscanner/Devices.qml b/examples/bluetooth/lowenergyscanner/Devices.qml
new file mode 100644
index 00000000..b41c259d
--- /dev/null
+++ b/examples/bluetooth/lowenergyscanner/Devices.qml
@@ -0,0 +1,144 @@
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+import QtCore
+import QtQuick
+
+Rectangle {
+ id: devicesPage
+
+ property bool deviceState: Device.state
+ signal showServices
+
+ width: 300
+ height: 600
+
+ function toggleDiscovery() {
+ if (!Device.state) {
+ Device.startDeviceDiscovery()
+ // if startDeviceDiscovery() failed Device.state is not set
+ if (Device.state) {
+ info.dialogText = "Searching..."
+ info.visible = true
+ }
+ } else {
+ Device.stopDeviceDiscovery()
+ }
+ }
+
+ onDeviceStateChanged: {
+ if (!Device.state)
+ info.visible = false
+ }
+
+ Header {
+ id: header
+ anchors.top: parent.top
+ headerText: {
+ if (Device.state)
+ return "Discovering"
+
+ if (Device.devicesList.length > 0)
+ return "Select a device"
+
+ return "Start Discovery"
+ }
+ }
+
+ Dialog {
+ id: info
+ anchors.centerIn: parent
+ visible: false
+ }
+
+ ListView {
+ id: theListView
+ width: parent.width
+ clip: true
+
+ anchors.top: header.bottom
+ anchors.bottom: connectToggle.top
+ model: Device.devicesList
+
+ delegate: Rectangle {
+ required property var modelData
+ id: box
+ height: 100
+ width: theListView.width
+ color: "lightsteelblue"
+ border.width: 2
+ border.color: "black"
+ radius: 5
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ Device.scanServices(box.modelData.deviceAddress)
+ showServices()
+ }
+ }
+
+ Label {
+ id: deviceName
+ textContent: box.modelData.deviceName
+ anchors.top: parent.top
+ anchors.topMargin: 5
+ }
+
+ Label {
+ id: deviceAddress
+ textContent: box.modelData.deviceAddress
+ font.pointSize: deviceName.font.pointSize * 0.7
+ anchors.bottom: box.bottom
+ anchors.bottomMargin: 5
+ }
+ }
+ }
+
+ Menu {
+ id: connectToggle
+
+ menuWidth: parent.width
+ anchors.bottom: menu.top
+ menuText: {
+ visible = Device.devicesList.length > 0
+ if (Device.useRandomAddress)
+ return "Address type: Random"
+ else
+ return "Address type: Public"
+ }
+
+ onButtonClick: Device.useRandomAddress = !Device.useRandomAddress
+ }
+
+ //! [permission-object]
+ BluetoothPermission {
+ id: permission
+ communicationModes: BluetoothPermission.Access
+ onStatusChanged: {
+ if (permission.status === Qt.PermissionStatus.Denied)
+ Device.update = "Bluetooth permission required"
+ else if (permission.status === Qt.PermissionStatus.Granted)
+ devicesPage.toggleDiscovery()
+ }
+ }
+ //! [permission-object]
+
+ Menu {
+ id: menu
+ anchors.bottom: parent.bottom
+ menuWidth: parent.width
+ menuHeight: (parent.height / 6)
+ menuText: Device.update
+ //! [permission-request]
+ onButtonClick: {
+ if (permission.status === Qt.PermissionStatus.Undetermined)
+ permission.request()
+ else if (permission.status === Qt.PermissionStatus.Granted)
+ devicesPage.toggleDiscovery()
+ }
+ //! [permission-request]
+ }
+}
diff --git a/examples/bluetooth/lowenergyscanner/Dialog.qml b/examples/bluetooth/lowenergyscanner/Dialog.qml
new file mode 100644
index 00000000..75e82642
--- /dev/null
+++ b/examples/bluetooth/lowenergyscanner/Dialog.qml
@@ -0,0 +1,48 @@
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+Rectangle {
+ id: dialog
+ width: parent.width / 3 * 2
+ height: dialogTextId.height + background.height + 20
+ z: 50
+ property string dialogText: ""
+ property bool busyImage: true
+ border.width: 1
+ border.color: "#363636"
+ radius: 10
+
+ Text {
+ id: dialogTextId
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ anchors.topMargin: 10
+
+ elide: Text.ElideMiddle
+ text: dialog.dialogText
+ color: "#363636"
+ wrapMode: Text.Wrap
+ }
+
+ Image {
+ id: background
+
+ width: 20
+ height: 20
+ anchors.top: dialogTextId.bottom
+ anchors.horizontalCenter: dialogTextId.horizontalCenter
+ visible: parent.busyImage
+ source: "assets/busy_dark.png"
+ fillMode: Image.PreserveAspectFit
+ NumberAnimation on rotation {
+ duration: 3000
+ from: 0
+ to: 360
+ loops: Animation.Infinite
+ }
+ }
+}
diff --git a/examples/bluetooth/lowenergyscanner/Header.qml b/examples/bluetooth/lowenergyscanner/Header.qml
new file mode 100644
index 00000000..c95385dd
--- /dev/null
+++ b/examples/bluetooth/lowenergyscanner/Header.qml
@@ -0,0 +1,25 @@
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+Rectangle {
+ id: header
+ width: parent.width
+ height: 70
+ border.width: 1
+ border.color: "#363636"
+ radius: 5
+ property string headerText: ""
+
+ Text {
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ anchors.fill: parent
+ text: header.headerText
+ font.bold: true
+ font.pointSize: 20
+ elide: Text.ElideMiddle
+ color: "#363636"
+ }
+}
diff --git a/examples/bluetooth/lowenergyscanner/Label.qml b/examples/bluetooth/lowenergyscanner/Label.qml
new file mode 100644
index 00000000..e3115674
--- /dev/null
+++ b/examples/bluetooth/lowenergyscanner/Label.qml
@@ -0,0 +1,16 @@
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+Text {
+ property string textContent: ""
+ font.pointSize: 20
+ anchors.horizontalCenter: parent.horizontalCenter
+ color: "#363636"
+ horizontalAlignment: Text.AlignHCenter
+ elide: Text.ElideMiddle
+ width: parent.width
+ wrapMode: Text.Wrap
+ text: textContent
+}
diff --git a/examples/bluetooth/lowenergyscanner/Main.qml b/examples/bluetooth/lowenergyscanner/Main.qml
new file mode 100644
index 00000000..88600bac
--- /dev/null
+++ b/examples/bluetooth/lowenergyscanner/Main.qml
@@ -0,0 +1,31 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Layouts
+
+Window {
+ id: main
+
+ width: 300
+ height: 600
+ visible: true
+
+ StackLayout {
+ id: pagesLayout
+ anchors.fill: parent
+ currentIndex: 0
+
+ Devices {
+ onShowServices: pagesLayout.currentIndex = 1
+ }
+ Services {
+ onShowDevices: pagesLayout.currentIndex = 0
+ onShowCharacteristics: pagesLayout.currentIndex = 2
+ }
+ Characteristics {
+ onShowDevices: pagesLayout.currentIndex = 0
+ onShowServices: pagesLayout.currentIndex = 1
+ }
+ }
+}
diff --git a/examples/bluetooth/lowenergyscanner/Menu.qml b/examples/bluetooth/lowenergyscanner/Menu.qml
new file mode 100644
index 00000000..ef69c895
--- /dev/null
+++ b/examples/bluetooth/lowenergyscanner/Menu.qml
@@ -0,0 +1,55 @@
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+Rectangle {
+ id: menu
+
+ property real menuWidth: 100
+ property real menuHeight: 50
+ property string menuText: "Search"
+ signal buttonClick
+
+ height: menuHeight
+ width: menuWidth
+
+ Rectangle {
+ id: search
+ width: parent.width
+ height: parent.height
+ anchors.centerIn: parent
+ color: "#363636"
+ border.width: 1
+ border.color: "#E3E3E3"
+ radius: 5
+ Text {
+ id: searchText
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ anchors.fill: parent
+ text: menu.menuText
+ elide: Text.ElideMiddle
+ color: "#E3E3E3"
+ wrapMode: Text.WordWrap
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onPressed: {
+ search.width = search.width - 7
+ search.height = search.height - 5
+ }
+
+ onReleased: {
+ search.width = search.width + 7
+ search.height = search.height + 5
+ }
+
+ onClicked: {
+ menu.buttonClick()
+ }
+ }
+ }
+}
diff --git a/examples/bluetooth/lowenergyscanner/Services.qml b/examples/bluetooth/lowenergyscanner/Services.qml
new file mode 100644
index 00000000..4d7fee32
--- /dev/null
+++ b/examples/bluetooth/lowenergyscanner/Services.qml
@@ -0,0 +1,115 @@
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+import QtQuick
+
+Rectangle {
+ id: servicesPage
+
+ signal showCharacteristics
+ signal showDevices
+
+ width: 300
+ height: 600
+
+ Component.onCompleted: {
+ // Loading this page may take longer than QLEController
+ // stopping with an error, go back and readjust this view
+ // based on controller errors
+ if (Device.controllerError) {
+ info.visible = false
+ menu.menuText = Device.update
+ }
+ }
+
+ Header {
+ id: header
+ anchors.top: parent.top
+ headerText: "Services list"
+ }
+
+ Dialog {
+ id: info
+ anchors.centerIn: parent
+ visible: true
+ dialogText: "Scanning for services..."
+ }
+
+ Connections {
+ target: Device
+ function onServicesUpdated() {
+ if (servicesview.count === 0)
+ info.dialogText = "No services found"
+ else
+ info.visible = false
+ }
+
+ function onDisconnected() {
+ servicesPage.showDevices()
+ }
+ }
+
+ ListView {
+ id: servicesview
+ width: parent.width
+ anchors.top: header.bottom
+ anchors.bottom: menu.top
+ model: Device.servicesList
+ clip: true
+
+ delegate: Rectangle {
+ required property var modelData
+ id: box
+ height: 100
+ color: "lightsteelblue"
+ border.width: 2
+ border.color: "black"
+ radius: 5
+ width: servicesview.width
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ Device.connectToService(box.modelData.serviceUuid)
+ servicesPage.showCharacteristics()
+ }
+ }
+
+ Label {
+ id: serviceName
+ textContent: box.modelData.serviceName
+ anchors.top: parent.top
+ anchors.topMargin: 5
+ }
+
+ Label {
+ textContent: box.modelData.serviceType
+ font.pointSize: serviceName.font.pointSize * 0.5
+ anchors.top: serviceName.bottom
+ }
+
+ Label {
+ id: serviceUuid
+ font.pointSize: serviceName.font.pointSize * 0.5
+ textContent: box.modelData.serviceUuid
+ anchors.bottom: box.bottom
+ anchors.bottomMargin: 5
+ }
+ }
+ }
+
+ Menu {
+ id: menu
+ anchors.bottom: parent.bottom
+ menuWidth: parent.width
+ menuText: Device.update
+ menuHeight: (parent.height / 6)
+ onButtonClick: {
+ Device.disconnectFromDevice()
+ servicesPage.showDevices()
+ Device.update = "Search"
+ }
+ }
+}
diff --git a/examples/bluetooth/lowenergyscanner/assets/Characteristics.qml b/examples/bluetooth/lowenergyscanner/assets/Characteristics.qml
deleted file mode 100644
index 4bfc2c0a..00000000
--- a/examples/bluetooth/lowenergyscanner/assets/Characteristics.qml
+++ /dev/null
@@ -1,161 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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 QtQuick 2.0
-
-Rectangle {
- width: 300
- height: 600
-
- Header {
- id: header
- anchors.top: parent.top
- headerText: "Characteristics list"
- }
-
- Dialog {
- id: info
- anchors.centerIn: parent
- visible: true
- dialogText: "Scanning for characteristics...";
- }
-
- Connections {
- target: device
- onCharacteristicsUpdated: {
- menu.menuText = "Back"
- if (characteristicview.count === 0) {
- info.dialogText = "No characteristic found"
- info.busyImage = false
- } else {
- info.visible = false
- info.busyImage = true
- }
- }
-
- onDisconnected: {
- pageLoader.source = "main.qml"
- }
- }
-
- ListView {
- id: characteristicview
- width: parent.width
- clip: true
-
- anchors.top: header.bottom
- anchors.bottom: menu.top
- model: device.characteristicList
-
- delegate: Rectangle {
- id: characteristicbox
- height:300
- width: parent.width
- color: "lightsteelblue"
- border.width: 2
- border.color: "black"
- radius: 5
-
- Label {
- id: characteristicName
- textContent: modelData.characteristicName
- anchors.top: parent.top
- anchors.topMargin: 5
- }
-
- Label {
- id: characteristicUuid
- font.pointSize: characteristicName.font.pointSize*0.7
- textContent: modelData.characteristicUuid
- anchors.top: characteristicName.bottom
- anchors.topMargin: 5
- }
-
- Label {
- id: characteristicValue
- font.pointSize: characteristicName.font.pointSize*0.7
- textContent: ("Value: " + modelData.characteristicValue)
- anchors.bottom: characteristicHandle.top
- horizontalAlignment: Text.AlignHCenter
- anchors.topMargin: 5
- }
-
- Label {
- id: characteristicHandle
- font.pointSize: characteristicName.font.pointSize*0.7
- textContent: ("Handlers: " + modelData.characteristicHandle)
- anchors.bottom: characteristicPermission.top
- anchors.topMargin: 5
- }
-
- Label {
- id: characteristicPermission
- font.pointSize: characteristicName.font.pointSize*0.7
- textContent: modelData.characteristicPermission
- anchors.bottom: parent.bottom
- anchors.topMargin: 5
- anchors.bottomMargin: 5
- }
- }
- }
-
- Menu {
- id: menu
- anchors.bottom: parent.bottom
- menuWidth: parent.width
- menuText: device.update
- menuHeight: (parent.height/6)
- onButtonClick: {
- pageLoader.source = "Services.qml"
- device.update = "Back"
- }
- }
-}
diff --git a/examples/bluetooth/lowenergyscanner/assets/Dialog.qml b/examples/bluetooth/lowenergyscanner/assets/Dialog.qml
deleted file mode 100644
index 8edabbbf..00000000
--- a/examples/bluetooth/lowenergyscanner/assets/Dialog.qml
+++ /dev/null
@@ -1,89 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 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: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 QtQuick 2.0
-
-Rectangle {
- width: parent.width/3*2
- height: dialogTextId.height + background.height + 20
- z: 50
- property string dialogText: ""
- property bool busyImage: true
- border.width: 1
- border.color: "#363636"
- radius: 10
-
- Text {
- id: dialogTextId
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.top: parent.top;
- anchors.topMargin: 10
-
- elide: Text.ElideMiddle
- text: dialogText
- color: "#363636"
- wrapMode: Text.Wrap
- }
-
- Image {
- id: background
-
- width:20
- height:20
- anchors.top: dialogTextId.bottom
- anchors.horizontalCenter: dialogTextId.horizontalCenter
- visible: parent.busyImage
- source: "busy_dark.png"
- fillMode: Image.PreserveAspectFit
- NumberAnimation on rotation { duration: 3000; from:0; to: 360; loops: Animation.Infinite}
- }
-}
diff --git a/examples/bluetooth/lowenergyscanner/assets/Header.qml b/examples/bluetooth/lowenergyscanner/assets/Header.qml
deleted file mode 100644
index 2da35b97..00000000
--- a/examples/bluetooth/lowenergyscanner/assets/Header.qml
+++ /dev/null
@@ -1,71 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 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: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 QtQuick 2.0
-
-Rectangle {
- width: parent.width
- height: 70
- border.width: 1
- border.color: "#363636"
- radius: 5
- property string headerText: ""
-
- Text {
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- anchors.fill: parent
- text: headerText
- font.bold: true
- font.pointSize: 20
- elide: Text.ElideMiddle
- color: "#363636"
- }
-}
diff --git a/examples/bluetooth/lowenergyscanner/assets/Label.qml b/examples/bluetooth/lowenergyscanner/assets/Label.qml
deleted file mode 100644
index aaa7746d..00000000
--- a/examples/bluetooth/lowenergyscanner/assets/Label.qml
+++ /dev/null
@@ -1,63 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 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: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 QtQuick 2.0
-
-Text {
- property string textContent: ""
- font.pointSize: 20
- anchors.horizontalCenter: parent.horizontalCenter
- color: "#363636"
- horizontalAlignment: Text.AlignHCenter
- elide: Text.ElideMiddle
- width: parent.width
- wrapMode: Text.Wrap
- text: textContent
-}
diff --git a/examples/bluetooth/lowenergyscanner/assets/Menu.qml b/examples/bluetooth/lowenergyscanner/assets/Menu.qml
deleted file mode 100644
index 1e0aa2ad..00000000
--- a/examples/bluetooth/lowenergyscanner/assets/Menu.qml
+++ /dev/null
@@ -1,101 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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 QtQuick 2.0
-
-Rectangle {
-
- property real menuWidth: 100
- property real menuHeight: 50
- property string menuText: "Search"
- signal buttonClick()
-
- height: menuHeight
- width: menuWidth
-
- Rectangle {
- id: search
- width: parent.width
- height: parent.height
- anchors.centerIn: parent
- color: "#363636"
- border.width: 1
- border.color: "#E3E3E3"
- radius: 5
- Text {
- id: searchText
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- anchors.fill: parent
- text: menuText
- elide: Text.ElideMiddle
- color: "#E3E3E3"
- wrapMode: Text.WordWrap
- }
-
- MouseArea {
- anchors.fill: parent
- onPressed: {
- search.width = search.width - 7
- search.height = search.height - 5
- }
-
- onReleased: {
- search.width = search.width + 7
- search.height = search.height + 5
- }
-
- onClicked: {
- buttonClick()
- }
- }
- }
-}
diff --git a/examples/bluetooth/lowenergyscanner/assets/Services.qml b/examples/bluetooth/lowenergyscanner/assets/Services.qml
deleted file mode 100644
index 68d7d447..00000000
--- a/examples/bluetooth/lowenergyscanner/assets/Services.qml
+++ /dev/null
@@ -1,158 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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 QtQuick 2.0
-
-Rectangle {
- width: 300
- height: 600
-
- Component.onCompleted: {
- // Loading this page may take longer than QLEController
- // stopping with an error, go back and readjust this view
- // based on controller errors
- if (device.controllerError) {
- info.visible = false;
- menu.menuText = device.update
- }
- }
-
- Header {
- id: header
- anchors.top: parent.top
- headerText: "Services list"
- }
-
- Dialog {
- id: info
- anchors.centerIn: parent
- visible: true
- dialogText: "Scanning for services...";
- }
-
- Connections {
- target: device
- onServicesUpdated: {
- if (servicesview.count === 0)
- info.dialogText = "No services found"
- else
- info.visible = false;
- }
-
- onDisconnected: {
- pageLoader.source = "main.qml"
- }
- }
-
- ListView {
- id: servicesview
- width: parent.width
- anchors.top: header.bottom
- anchors.bottom: menu.top
- model: device.servicesList
- clip: true
-
- delegate: Rectangle {
- id: servicebox
- height:100
- color: "lightsteelblue"
- border.width: 2
- border.color: "black"
- radius: 5
- width: parent.width
- Component.onCompleted: {
- info.visible = false
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- pageLoader.source = "Characteristics.qml";
- device.connectToService(modelData.serviceUuid);
- }
- }
-
- Label {
- id: serviceName
- textContent: modelData.serviceName
- anchors.top: parent.top
- anchors.topMargin: 5
- }
-
- Label {
- textContent: modelData.serviceType
- font.pointSize: serviceName.font.pointSize * 0.5
- anchors.top: serviceName.bottom
- }
-
- Label {
- id: serviceUuid
- font.pointSize: serviceName.font.pointSize * 0.5
- textContent: modelData.serviceUuid
- anchors.bottom: servicebox.bottom
- anchors.bottomMargin: 5
- }
- }
- }
-
- Menu {
- id: menu
- anchors.bottom: parent.bottom
- menuWidth: parent.width
- menuText: device.update
- menuHeight: (parent.height/6)
- onButtonClick: {
- device.disconnectFromDevice()
- pageLoader.source = "main.qml"
- device.update = "Search"
- }
- }
-}
diff --git a/examples/bluetooth/lowenergyscanner/assets/main.qml b/examples/bluetooth/lowenergyscanner/assets/main.qml
deleted file mode 100644
index 2424dbcf..00000000
--- a/examples/bluetooth/lowenergyscanner/assets/main.qml
+++ /dev/null
@@ -1,162 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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 QtQuick 2.0
-
-Rectangle {
- id: back
- width: 300
- height: 600
- property bool deviceState: device.state
- onDeviceStateChanged: {
- if (!device.state)
- info.visible = false;
- }
-
- Header {
- id: header
- anchors.top: parent.top
- headerText: "Start Discovery"
- }
-
- Dialog {
- id: info
- anchors.centerIn: parent
- visible: false
- }
-
- ListView {
- id: theListView
- width: parent.width
- clip: true
-
- anchors.top: header.bottom
- anchors.bottom: connectToggle.top
- model: device.devicesList
-
- delegate: Rectangle {
- id: box
- height:100
- width: parent.width
- color: "lightsteelblue"
- border.width: 2
- border.color: "black"
- radius: 5
-
- Component.onCompleted: {
- info.visible = false;
- header.headerText = "Select a device";
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- device.scanServices(modelData.deviceAddress);
- pageLoader.source = "Services.qml"
- }
- }
-
- Label {
- id: deviceName
- textContent: modelData.deviceName
- anchors.top: parent.top
- anchors.topMargin: 5
- }
-
- Label {
- id: deviceAddress
- textContent: modelData.deviceAddress
- font.pointSize: deviceName.font.pointSize*0.7
- anchors.bottom: box.bottom
- anchors.bottomMargin: 5
- }
- }
- }
-
- Menu {
- id: connectToggle
-
- menuWidth: parent.width
- anchors.bottom: menu.top
- menuText: { if (device.devicesList.length)
- visible = true
- else
- visible = false
- if (device.useRandomAddress)
- "Address type: Random"
- else
- "Address type: Public"
- }
-
- onButtonClick: device.useRandomAddress = !device.useRandomAddress;
- }
-
- Menu {
- id: menu
- anchors.bottom: parent.bottom
- menuWidth: parent.width
- menuHeight: (parent.height/6)
- menuText: device.update
- onButtonClick: {
- device.startDeviceDiscovery();
- // if startDeviceDiscovery() failed device.state is not set
- if (device.state) {
- info.dialogText = "Searching...";
- info.visible = true;
- }
- }
- }
-
- Loader {
- id: pageLoader
- anchors.fill: parent
- }
-}
diff --git a/examples/bluetooth/lowenergyscanner/characteristicinfo.cpp b/examples/bluetooth/lowenergyscanner/characteristicinfo.cpp
index 2402f4d1..59df54c1 100644
--- a/examples/bluetooth/lowenergyscanner/characteristicinfo.cpp
+++ b/examples/bluetooth/lowenergyscanner/characteristicinfo.cpp
@@ -1,58 +1,15 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "characteristicinfo.h"
-#include "qbluetoothuuid.h"
+
+#include <QBluetoothUuid>
+
#include <QByteArray>
+using namespace Qt::StringLiterals;
+
CharacteristicInfo::CharacteristicInfo(const QLowEnergyCharacteristic &characteristic):
m_characteristic(characteristic)
{
@@ -74,7 +31,7 @@ QString CharacteristicInfo::getName() const
// find descriptor with CharacteristicUserDescription
const QList<QLowEnergyDescriptor> descriptors = m_characteristic.descriptors();
for (const QLowEnergyDescriptor &descriptor : descriptors) {
- if (descriptor.type() == QBluetoothUuid::CharacteristicUserDescription) {
+ if (descriptor.type() == QBluetoothUuid::DescriptorType::CharacteristicUserDescription) {
name = descriptor.value();
break;
}
@@ -82,7 +39,7 @@ QString CharacteristicInfo::getName() const
//! [les-get-descriptors]
if (name.isEmpty())
- name = "Unknown";
+ name = u"Unknown"_s;
return name;
}
@@ -93,13 +50,13 @@ QString CharacteristicInfo::getUuid() const
bool success = false;
quint16 result16 = uuid.toUInt16(&success);
if (success)
- return QStringLiteral("0x") + QString::number(result16, 16);
+ return u"0x"_s + QString::number(result16, 16);
quint32 result32 = uuid.toUInt32(&success);
if (success)
- return QStringLiteral("0x") + QString::number(result32, 16);
+ return u"0x"_s + QString::number(result32, 16);
- return uuid.toString().remove(QLatin1Char('{')).remove(QLatin1Char('}'));
+ return uuid.toString().remove('{'_L1).remove('}'_L1);
}
QString CharacteristicInfo::getValue() const
@@ -108,43 +65,38 @@ QString CharacteristicInfo::getValue() const
QByteArray a = m_characteristic.value();
QString result;
if (a.isEmpty()) {
- result = QStringLiteral("<none>");
+ result = u"<none>"_s;
return result;
}
result = a;
- result += QLatin1Char('\n');
+ result += '\n'_L1;
result += a.toHex();
return result;
}
-QString CharacteristicInfo::getHandle() const
-{
- return QStringLiteral("0x") + QString::number(m_characteristic.handle(), 16);
-}
-
QString CharacteristicInfo::getPermission() const
{
- QString properties = "( ";
+ QString properties = u"( "_s;
uint permission = m_characteristic.properties();
if (permission & QLowEnergyCharacteristic::Read)
- properties += QStringLiteral(" Read");
+ properties += u" Read"_s;
if (permission & QLowEnergyCharacteristic::Write)
- properties += QStringLiteral(" Write");
+ properties += u" Write"_s;
if (permission & QLowEnergyCharacteristic::Notify)
- properties += QStringLiteral(" Notify");
+ properties += u" Notify"_s;
if (permission & QLowEnergyCharacteristic::Indicate)
- properties += QStringLiteral(" Indicate");
+ properties += u" Indicate"_s;
if (permission & QLowEnergyCharacteristic::ExtendedProperty)
- properties += QStringLiteral(" ExtendedProperty");
+ properties += u" ExtendedProperty"_s;
if (permission & QLowEnergyCharacteristic::Broadcasting)
- properties += QStringLiteral(" Broadcast");
+ properties += u" Broadcast"_s;
if (permission & QLowEnergyCharacteristic::WriteNoResponse)
- properties += QStringLiteral(" WriteNoResp");
+ properties += u" WriteNoResp"_s;
if (permission & QLowEnergyCharacteristic::WriteSigned)
- properties += QStringLiteral(" WriteSigned");
- properties += " )";
+ properties += u" WriteSigned"_s;
+ properties += u" )"_s;
return properties;
}
diff --git a/examples/bluetooth/lowenergyscanner/characteristicinfo.h b/examples/bluetooth/lowenergyscanner/characteristicinfo.h
index 3f3600ab..a39ce823 100644
--- a/examples/bluetooth/lowenergyscanner/characteristicinfo.h
+++ b/examples/bluetooth/lowenergyscanner/characteristicinfo.h
@@ -1,59 +1,16 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef CHARACTERISTICINFO_H
#define CHARACTERISTICINFO_H
+
+#include <QLowEnergyCharacteristic>
+
#include <QObject>
#include <QString>
-#include <QtBluetooth/QLowEnergyCharacteristic>
+
+#include <QQmlEngine>
class CharacteristicInfo: public QObject
{
@@ -61,9 +18,10 @@ class CharacteristicInfo: public QObject
Q_PROPERTY(QString characteristicName READ getName NOTIFY characteristicChanged)
Q_PROPERTY(QString characteristicUuid READ getUuid NOTIFY characteristicChanged)
Q_PROPERTY(QString characteristicValue READ getValue NOTIFY characteristicChanged)
- Q_PROPERTY(QString characteristicHandle READ getHandle NOTIFY characteristicChanged)
Q_PROPERTY(QString characteristicPermission READ getPermission NOTIFY characteristicChanged)
+ QML_ANONYMOUS
+
public:
CharacteristicInfo() = default;
CharacteristicInfo(const QLowEnergyCharacteristic &characteristic);
@@ -71,7 +29,6 @@ public:
QString getName() const;
QString getUuid() const;
QString getValue() const;
- QString getHandle() const;
QString getPermission() const;
QLowEnergyCharacteristic getCharacteristic() const;
diff --git a/examples/bluetooth/lowenergyscanner/device.cpp b/examples/bluetooth/lowenergyscanner/device.cpp
index e1d96be3..87c2d9cb 100644
--- a/examples/bluetooth/lowenergyscanner/device.cpp
+++ b/examples/bluetooth/lowenergyscanner/device.cpp
@@ -1,85 +1,44 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "device.h"
-#include <qbluetoothaddress.h>
-#include <qbluetoothdevicediscoveryagent.h>
-#include <qbluetoothlocaldevice.h>
-#include <qbluetoothdeviceinfo.h>
-#include <qbluetoothservicediscoveryagent.h>
+#include <QBluetoothDeviceInfo>
+#include <QBluetoothUuid>
+
#include <QDebug>
-#include <QList>
-#include <QMetaEnum>
+#include <QMetaObject>
#include <QTimer>
+#if QT_CONFIG(permissions)
+#include <QPermissions>
+
+#include <QGuiApplication>
+#endif
+
+using namespace Qt::StringLiterals;
+
Device::Device()
{
//! [les-devicediscovery-1]
- discoveryAgent = new QBluetoothDeviceDiscoveryAgent();
- discoveryAgent->setLowEnergyDiscoveryTimeout(5000);
+ discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
+ discoveryAgent->setLowEnergyDiscoveryTimeout(25000);
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
this, &Device::addDevice);
- connect(discoveryAgent, QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error),
+ connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::errorOccurred,
this, &Device::deviceScanError);
- connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &Device::deviceScanFinished);
+ connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished,
+ this, &Device::deviceScanFinished);
+ connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::canceled,
+ this, &Device::deviceScanFinished);
//! [les-devicediscovery-1]
- setUpdate("Search");
+ setUpdate(u"Search"_s);
}
Device::~Device()
{
- delete discoveryAgent;
- delete controller;
qDeleteAll(devices);
qDeleteAll(m_services);
qDeleteAll(m_characteristics);
@@ -94,39 +53,52 @@ void Device::startDeviceDiscovery()
devices.clear();
emit devicesUpdated();
- setUpdate("Scanning for devices ...");
//! [les-devicediscovery-2]
discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
//! [les-devicediscovery-2]
if (discoveryAgent->isActive()) {
+ setUpdate(u"Stop"_s);
m_deviceScanState = true;
Q_EMIT stateChanged();
}
}
+void Device::stopDeviceDiscovery()
+{
+ if (discoveryAgent->isActive())
+ discoveryAgent->stop();
+}
+
//! [les-devicediscovery-3]
void Device::addDevice(const QBluetoothDeviceInfo &info)
{
- if (info.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration)
- setUpdate("Last device added: " + info.name());
+ if (info.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration) {
+ auto devInfo = new DeviceInfo(info);
+ auto it = std::find_if(devices.begin(), devices.end(),
+ [devInfo](DeviceInfo *dev) {
+ return devInfo->getAddress() == dev->getAddress();
+ });
+ if (it == devices.end()) {
+ devices.append(devInfo);
+ } else {
+ auto oldDev = *it;
+ *it = devInfo;
+ delete oldDev;
+ }
+ emit devicesUpdated();
+ }
}
//! [les-devicediscovery-3]
void Device::deviceScanFinished()
{
- const QList<QBluetoothDeviceInfo> foundDevices = discoveryAgent->discoveredDevices();
- for (auto nextDevice : foundDevices)
- if (nextDevice.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration)
- devices.append(new DeviceInfo(nextDevice));
-
- emit devicesUpdated();
m_deviceScanState = false;
emit stateChanged();
if (devices.isEmpty())
- setUpdate("No Low Energy devices found...");
+ setUpdate(u"No Low Energy devices found..."_s);
else
- setUpdate("Done! Scan Again!");
+ setUpdate(u"Done! Scan Again!"_s);
}
QVariant Device::getDevices()
@@ -153,9 +125,9 @@ void Device::scanServices(const QString &address)
{
// We need the current device for service discovery.
- for (auto d: qAsConst(devices)) {
+ for (auto d: std::as_const(devices)) {
if (auto device = qobject_cast<DeviceInfo *>(d)) {
- if (device->getAddress() == address ) {
+ if (device->getAddress() == address) {
currentDevice.setDevice(device->getDevice());
break;
}
@@ -174,7 +146,7 @@ void Device::scanServices(const QString &address)
m_services.clear();
emit servicesUpdated();
- setUpdate("Back\n(Connecting to device...)");
+ setUpdate(u"Back\n(Connecting to device...)"_s);
if (controller && m_previousAddress != currentDevice.getAddress()) {
controller->disconnectFromDevice();
@@ -185,11 +157,10 @@ void Device::scanServices(const QString &address)
//! [les-controller-1]
if (!controller) {
// Connecting signals and slots for connecting to LE services.
- controller = QLowEnergyController::createCentral(currentDevice.getDevice());
+ controller = QLowEnergyController::createCentral(currentDevice.getDevice(), this);
connect(controller, &QLowEnergyController::connected,
this, &Device::deviceConnected);
- connect(controller, QOverload<QLowEnergyController::Error>::of(&QLowEnergyController::error),
- this, &Device::errorReceived);
+ connect(controller, &QLowEnergyController::errorOccurred, this, &Device::errorReceived);
connect(controller, &QLowEnergyController::disconnected,
this, &Device::deviceDisconnected);
connect(controller, &QLowEnergyController::serviceDiscovered,
@@ -226,7 +197,7 @@ void Device::addLowEnergyService(const QBluetoothUuid &serviceUuid)
void Device::serviceScanDone()
{
- setUpdate("Back\n(Service scan done!)");
+ setUpdate(u"Back\n(Service scan done!)"_s);
// force UI in case we didn't find anything
if (m_services.isEmpty())
emit servicesUpdated();
@@ -235,7 +206,7 @@ void Device::serviceScanDone()
void Device::connectToService(const QString &uuid)
{
QLowEnergyService *service = nullptr;
- for (auto s: qAsConst(m_services)) {
+ for (auto s: std::as_const(m_services)) {
auto serviceInfo = qobject_cast<ServiceInfo *>(s);
if (!serviceInfo)
continue;
@@ -253,12 +224,12 @@ void Device::connectToService(const QString &uuid)
m_characteristics.clear();
emit characteristicsUpdated();
- if (service->state() == QLowEnergyService::DiscoveryRequired) {
+ if (service->state() == QLowEnergyService::RemoteService) {
//! [les-service-3]
connect(service, &QLowEnergyService::stateChanged,
this, &Device::serviceDetailsDiscovered);
service->discoverDetails();
- setUpdate("Back\n(Discovering details...)");
+ setUpdate(u"Back\n(Discovering details...)"_s);
//! [les-service-3]
return;
}
@@ -275,7 +246,7 @@ void Device::connectToService(const QString &uuid)
void Device::deviceConnected()
{
- setUpdate("Back\n(Discovering services...)");
+ setUpdate(u"Back\n(Discovering services...)"_s);
connected = true;
//! [les-service-2]
controller->discoverServices();
@@ -285,7 +256,7 @@ void Device::deviceConnected()
void Device::errorReceived(QLowEnergyController::Error /*error*/)
{
qWarning() << "Error: " << controller->errorString();
- setUpdate(QString("Back\n(%1)").arg(controller->errorString()));
+ setUpdate(u"Back\n(%1)"_s.arg(controller->errorString()));
}
void Device::setUpdate(const QString &message)
@@ -315,12 +286,12 @@ void Device::deviceDisconnected()
void Device::serviceDetailsDiscovered(QLowEnergyService::ServiceState newState)
{
- if (newState != QLowEnergyService::ServiceDiscovered) {
+ if (newState != QLowEnergyService::RemoteServiceDiscovered) {
// do not hang in "Scanning for characteristics" mode forever
// in case the service discovery failed
// We have to queue the signal up to give UI time to even enter
// the above mode
- if (newState != QLowEnergyService::DiscoveringServices) {
+ if (newState != QLowEnergyService::RemoteServiceDiscovering) {
QMetaObject::invokeMethod(this, "characteristicsUpdated",
Qt::QueuedConnection);
}
@@ -346,18 +317,17 @@ void Device::serviceDetailsDiscovered(QLowEnergyService::ServiceState newState)
void Device::deviceScanError(QBluetoothDeviceDiscoveryAgent::Error error)
{
- if (error == QBluetoothDeviceDiscoveryAgent::PoweredOffError)
- setUpdate("The Bluetooth adaptor is powered off, power it on before doing discovery.");
- else if (error == QBluetoothDeviceDiscoveryAgent::InputOutputError)
- setUpdate("Writing or reading from the device resulted in an error.");
- else {
+ if (error == QBluetoothDeviceDiscoveryAgent::PoweredOffError) {
+ setUpdate(u"The Bluetooth adaptor is powered off, power it on before doing discovery."_s);
+ } else if (error == QBluetoothDeviceDiscoveryAgent::InputOutputError) {
+ setUpdate(u"Writing or reading from the device resulted in an error."_s);
+ } else {
static QMetaEnum qme = discoveryAgent->metaObject()->enumerator(
discoveryAgent->metaObject()->indexOfEnumerator("Error"));
- setUpdate("Error: " + QLatin1String(qme.valueToKey(error)));
+ setUpdate(u"Error: "_s + QLatin1StringView(qme.valueToKey(error)));
}
m_deviceScanState = false;
- emit devicesUpdated();
emit stateChanged();
}
diff --git a/examples/bluetooth/lowenergyscanner/device.h b/examples/bluetooth/lowenergyscanner/device.h
index ef94c7f9..4a7e7f80 100644
--- a/examples/bluetooth/lowenergyscanner/device.h
+++ b/examples/bluetooth/lowenergyscanner/device.h
@@ -1,70 +1,27 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the demonstration applications 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
#ifndef DEVICE_H
#define DEVICE_H
-#include <qbluetoothlocaldevice.h>
-#include <QObject>
-#include <QVariant>
-#include <QList>
-#include <QBluetoothServiceDiscoveryAgent>
-#include <QBluetoothDeviceDiscoveryAgent>
-#include <QLowEnergyController>
-#include <QBluetoothServiceInfo>
+#include "characteristicinfo.h"
#include "deviceinfo.h"
#include "serviceinfo.h"
-#include "characteristicinfo.h"
-QT_FORWARD_DECLARE_CLASS (QBluetoothDeviceInfo)
-QT_FORWARD_DECLARE_CLASS (QBluetoothServiceInfo)
+#include <QBluetoothDeviceDiscoveryAgent>
+#include <QLowEnergyController>
+#include <QLowEnergyService>
+
+#include <QList>
+#include <QObject>
+#include <QVariant>
+
+#include <QQmlEngine>
+
+QT_BEGIN_NAMESPACE
+class QBluetoothDeviceInfo;
+class QBluetoothUuid;
+QT_END_NAMESPACE
class Device: public QObject
{
@@ -73,9 +30,14 @@ class Device: public QObject
Q_PROPERTY(QVariant servicesList READ getServices NOTIFY servicesUpdated)
Q_PROPERTY(QVariant characteristicList READ getCharacteristics NOTIFY characteristicsUpdated)
Q_PROPERTY(QString update READ getUpdate WRITE setUpdate NOTIFY updateChanged)
- Q_PROPERTY(bool useRandomAddress READ isRandomAddress WRITE setRandomAddress NOTIFY randomAddressChanged)
+ Q_PROPERTY(bool useRandomAddress READ isRandomAddress WRITE setRandomAddress
+ NOTIFY randomAddressChanged)
Q_PROPERTY(bool state READ state NOTIFY stateChanged)
Q_PROPERTY(bool controllerError READ hasControllerError)
+
+ QML_ELEMENT
+ QML_SINGLETON
+
public:
Device();
~Device();
@@ -91,6 +53,7 @@ public:
public slots:
void startDeviceDiscovery();
+ void stopDeviceDiscovery();
void scanServices(const QString &address);
void connectToService(const QString &uuid);
@@ -125,9 +88,9 @@ private:
void setUpdate(const QString &message);
QBluetoothDeviceDiscoveryAgent *discoveryAgent;
DeviceInfo currentDevice;
- QList<QObject *> devices;
- QList<QObject *> m_services;
- QList<QObject *> m_characteristics;
+ QList<DeviceInfo *> devices;
+ QList<ServiceInfo *> m_services;
+ QList<CharacteristicInfo *> m_characteristics;
QString m_previousAddress;
QString m_message;
bool connected = false;
diff --git a/examples/bluetooth/lowenergyscanner/deviceinfo.cpp b/examples/bluetooth/lowenergyscanner/deviceinfo.cpp
index 23acc440..66300a28 100644
--- a/examples/bluetooth/lowenergyscanner/deviceinfo.cpp
+++ b/examples/bluetooth/lowenergyscanner/deviceinfo.cpp
@@ -1,58 +1,15 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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$
-**
-****************************************************************************/
-
-#include <qbluetoothuuid.h>
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "deviceinfo.h"
+#ifdef Q_OS_DARWIN
+# include <QBluetoothUuid>
+#else
+# include <QBluetoothAddress>
+#endif
+
DeviceInfo::DeviceInfo(const QBluetoothDeviceInfo &d)
{
device = d;
@@ -60,7 +17,7 @@ DeviceInfo::DeviceInfo(const QBluetoothDeviceInfo &d)
QString DeviceInfo::getAddress() const
{
-#ifdef Q_OS_MAC
+#ifdef Q_OS_DARWIN
// On OS X and iOS we do not have addresses,
// only unique UUIDs generated by Core Bluetooth.
return device.deviceUuid().toString();
diff --git a/examples/bluetooth/lowenergyscanner/deviceinfo.h b/examples/bluetooth/lowenergyscanner/deviceinfo.h
index 249afad2..7a0c7352 100644
--- a/examples/bluetooth/lowenergyscanner/deviceinfo.h
+++ b/examples/bluetooth/lowenergyscanner/deviceinfo.h
@@ -1,68 +1,25 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef DEVICEINFO_H
#define DEVICEINFO_H
-#include <QObject>
-#include <qbluetoothdeviceinfo.h>
-#include <qbluetoothaddress.h>
+#include <QBluetoothDeviceInfo>
+
#include <QList>
-#include "deviceinfo.h"
+#include <QObject>
+
+#include <QQmlEngine>
class DeviceInfo: public QObject
{
Q_OBJECT
Q_PROPERTY(QString deviceName READ getName NOTIFY deviceChanged)
Q_PROPERTY(QString deviceAddress READ getAddress NOTIFY deviceChanged)
+
+ QML_ANONYMOUS
+
public:
DeviceInfo() = default;
DeviceInfo(const QBluetoothDeviceInfo &d);
diff --git a/examples/bluetooth/lowenergyscanner/doc/src/lowenergyscanner.qdoc b/examples/bluetooth/lowenergyscanner/doc/src/lowenergyscanner.qdoc
index bb2372a0..da44fcce 100644
--- a/examples/bluetooth/lowenergyscanner/doc/src/lowenergyscanner.qdoc
+++ b/examples/bluetooth/lowenergyscanner/doc/src/lowenergyscanner.qdoc
@@ -1,40 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited all rights reserved
-** 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) 2013 BlackBerry Limited all rights reserved
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example lowenergyscanner
- \title Bluetooth Low Energy Scanner Example
+ \title Bluetooth Low Energy Scanner
+ \examplecategory {Connectivity}
+ \meta tags {bluetooth, ble}
\brief An application designed to browse the content of Bluetooth Low
- Energy peripheral devices. The example demonstrates the use of all Qt Bluetooth
+ Energy peripheral devices. The example demonstrates the use of all \l{Qt Bluetooth}
Low Energy classes.
The Bluetooth Low Energy Scanner Example shows how to develop Bluetooth
- Low Energy applications using the Qt Bluetooth API. The application covers
+ Low Energy applications using the \l{QtBluetooth}{Qt Bluetooth API}. The application covers
scanning for Low Energy devices, scanning their services and reading
the service characteristics and descriptors.
@@ -56,6 +34,22 @@
\include examples-run.qdocinc
+ \section1 Requesting Permission to use Bluetooth
+
+ On certain platforms, it is required to explicitly grant permissions for
+ using Bluetooth. The example uses \c BluetoothPermission QML object to
+ check and request the permissions, if required:
+
+ \snippet lowenergyscanner/Devices.qml permission-object
+
+ The permission request dialog is triggered when the user tries to start
+ the device discovery, and the permission status is \c {Undetermined}:
+
+ \snippet lowenergyscanner/Devices.qml permission-request
+
+ The device discovery starts if the permission is granted by the user.
+ Otherwise the application is non-functional.
+
\section1 Scanning for Devices
The first step is to find all peripheral devices. The devices can be found using
@@ -70,6 +64,10 @@
device. It filters all found devices which
have the \l QBluetoothDeviceInfo::LowEnergyCoreConfiguration flag and adds them to a
list which is shown to the user.
+ 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 lowenergyscanner/device.cpp les-devicediscovery-3
@@ -110,9 +108,9 @@
Change notifications can be triggered as a result of writing a value or due to an on-device
update potentially triggered by the internal logic.
During the initial 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 lowenergyscanner/device.cpp les-service-3
@@ -132,7 +130,7 @@
Although the example application does not display descriptors it uses descriptors to
get the name of an individual characteristic if its name cannot be discerned based on its
UUID. The second way to obtain the name is the existence of a descriptor of the type
- \l {QBluetoothUuid::CharacteristicUserDescription}. The code below demonstrates how this
+ \l {QBluetoothUuid::DescriptorType::CharacteristicUserDescription}. The code below demonstrates how this
may be achieved:
\snippet lowenergyscanner/characteristicinfo.cpp les-get-descriptors
diff --git a/examples/bluetooth/lowenergyscanner/lowenergyscanner.pro b/examples/bluetooth/lowenergyscanner/lowenergyscanner.pro
index f3378b4c..1e798a55 100644
--- a/examples/bluetooth/lowenergyscanner/lowenergyscanner.pro
+++ b/examples/bluetooth/lowenergyscanner/lowenergyscanner.pro
@@ -1,25 +1,45 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+TEMPLATE = app
TARGET = lowenergyscanner
-INCLUDEPATH += .
QT += quick bluetooth
-# Input
+CONFIG += qmltypes
+QML_IMPORT_NAME = Scanner
+QML_IMPORT_MAJOR_VERSION = 1
+
SOURCES += main.cpp \
device.cpp \
deviceinfo.cpp \
serviceinfo.cpp \
characteristicinfo.cpp
-OTHER_FILES += assets/*.qml
-
HEADERS += \
device.h \
deviceinfo.h \
serviceinfo.h \
characteristicinfo.h
-RESOURCES += \
- resources.qrc
+qml_resources.files = \
+ qmldir \
+ Characteristics.qml \
+ Devices.qml \
+ Dialog.qml \
+ Header.qml \
+ Label.qml \
+ Main.qml \
+ Menu.qml \
+ Services.qml \
+ assets/busy_dark.png
+
+qml_resources.prefix = /qt/qml/Scanner
+
+RESOURCES = qml_resources
+
+ios: QMAKE_INFO_PLIST = ../shared/Info.qmake.ios.plist
+macos: QMAKE_INFO_PLIST = ../shared/Info.qmake.macos.plist
target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/lowenergyscanner
INSTALLS += target
diff --git a/examples/bluetooth/lowenergyscanner/main.cpp b/examples/bluetooth/lowenergyscanner/main.cpp
index f223b028..16ff1183 100644
--- a/examples/bluetooth/lowenergyscanner/main.cpp
+++ b/examples/bluetooth/lowenergyscanner/main.cpp
@@ -1,73 +1,24 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-#include <QtCore/QLoggingCategory>
-#include <QQmlContext>
-#include <QGuiApplication>
-#include <QQuickView>
#include "device.h"
+#include <QLoggingCategory>
+
+#include <QGuiApplication>
+
+#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
- //QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
- QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ // QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
QGuiApplication app(argc, argv);
- Device d;
- auto view = new QQuickView;
- view->rootContext()->setContextProperty("device", &d);
+ QQmlApplicationEngine engine;
+ QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &app,
+ []() { QCoreApplication::exit(1); }, Qt::QueuedConnection);
+ engine.loadFromModule("Scanner", "Main");
- view->setSource(QUrl("qrc:/assets/main.qml"));
- view->setResizeMode(QQuickView::SizeRootObjectToView);
- view->show();
- return QGuiApplication::exec();
+ return app.exec();
}
diff --git a/examples/bluetooth/lowenergyscanner/qmldir b/examples/bluetooth/lowenergyscanner/qmldir
new file mode 100644
index 00000000..c2f4d141
--- /dev/null
+++ b/examples/bluetooth/lowenergyscanner/qmldir
@@ -0,0 +1,11 @@
+module Scanner
+prefer :/qt/qml/Scanner/
+Characteristics 1.0 Characteristics.qml
+Devices 1.0 Devices.qml
+Dialog 1.0 Dialog.qml
+Header 1.0 Header.qml
+Label 1.0 Label.qml
+Main 1.0 Main.qml
+Menu 1.0 Menu.qml
+Services 1.0 Services.qml
+
diff --git a/examples/bluetooth/lowenergyscanner/resources.qrc b/examples/bluetooth/lowenergyscanner/resources.qrc
deleted file mode 100644
index 4634cf6b..00000000
--- a/examples/bluetooth/lowenergyscanner/resources.qrc
+++ /dev/null
@@ -1,12 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>assets/Characteristics.qml</file>
- <file>assets/main.qml</file>
- <file>assets/Menu.qml</file>
- <file>assets/Services.qml</file>
- <file>assets/Header.qml</file>
- <file>assets/Dialog.qml</file>
- <file>assets/Label.qml</file>
- <file>assets/busy_dark.png</file>
- </qresource>
-</RCC>
diff --git a/examples/bluetooth/lowenergyscanner/serviceinfo.cpp b/examples/bluetooth/lowenergyscanner/serviceinfo.cpp
index 720619d0..d9c81a5b 100644
--- a/examples/bluetooth/lowenergyscanner/serviceinfo.cpp
+++ b/examples/bluetooth/lowenergyscanner/serviceinfo.cpp
@@ -1,56 +1,14 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "serviceinfo.h"
+#include <QBluetoothUuid>
+#include <QLowEnergyService>
+
+using namespace Qt::StringLiterals;
+
ServiceInfo::ServiceInfo(QLowEnergyService *service):
m_service(service)
{
@@ -77,14 +35,14 @@ QString ServiceInfo::getType() const
QString result;
if (m_service->type() & QLowEnergyService::PrimaryService)
- result += QStringLiteral("primary");
+ result += u"primary"_s;
else
- result += QStringLiteral("secondary");
+ result += u"secondary"_s;
if (m_service->type() & QLowEnergyService::IncludedService)
- result += QStringLiteral(" included");
+ result += u" included"_s;
- result.prepend('<').append('>');
+ result.prepend('<'_L1).append('>'_L1);
return result;
}
@@ -98,11 +56,11 @@ QString ServiceInfo::getUuid() const
bool success = false;
quint16 result16 = uuid.toUInt16(&success);
if (success)
- return QStringLiteral("0x") + QString::number(result16, 16);
+ return u"0x"_s + QString::number(result16, 16);
quint32 result32 = uuid.toUInt32(&success);
if (success)
- return QStringLiteral("0x") + QString::number(result32, 16);
+ return u"0x"_s + QString::number(result32, 16);
- return uuid.toString().remove(QLatin1Char('{')).remove(QLatin1Char('}'));
+ return uuid.toString().remove('{'_L1).remove('}'_L1);
}
diff --git a/examples/bluetooth/lowenergyscanner/serviceinfo.h b/examples/bluetooth/lowenergyscanner/serviceinfo.h
index 6709be69..f4347d47 100644
--- a/examples/bluetooth/lowenergyscanner/serviceinfo.h
+++ b/examples/bluetooth/lowenergyscanner/serviceinfo.h
@@ -1,57 +1,17 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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) 2013 BlackBerry Limited. All rights reserved.
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef SERVICEINFO_H
#define SERVICEINFO_H
-#include <QtBluetooth/QLowEnergyService>
+
+#include <QObject>
+
+#include <QQmlEngine>
+
+QT_BEGIN_NAMESPACE
+class QLowEnergyService;
+QT_END_NAMESPACE
class ServiceInfo: public QObject
{
@@ -59,6 +19,9 @@ class ServiceInfo: public QObject
Q_PROPERTY(QString serviceName READ getName NOTIFY serviceChanged)
Q_PROPERTY(QString serviceUuid READ getUuid NOTIFY serviceChanged)
Q_PROPERTY(QString serviceType READ getType NOTIFY serviceChanged)
+
+ QML_ANONYMOUS
+
public:
ServiceInfo() = default;
ServiceInfo(QLowEnergyService *service);
diff --git a/examples/bluetooth/picturetransfer/Button.qml b/examples/bluetooth/picturetransfer/Button.qml
deleted file mode 100644
index be8bbbf8..00000000
--- a/examples/bluetooth/picturetransfer/Button.qml
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 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: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 QtQuick 2.1
-
-Rectangle {
- property alias text: label.text
- signal clicked();
- opacity: 0.7
- height: label.height + 30
- width: label.width + 90
- border.color: Qt.lighter("#67b0d1")
- border.width: 1
- color: mArea.pressed ? "#5c9fba" : "#67b0d1"
- Text {
- id: label
- anchors.centerIn: parent
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- font.pointSize: 10
- color: "black"
- }
- MouseArea {
- id: mArea
- anchors.fill: parent
- onClicked: parent.clicked()
- }
-}
diff --git a/examples/bluetooth/picturetransfer/DeviceDiscovery.qml b/examples/bluetooth/picturetransfer/DeviceDiscovery.qml
deleted file mode 100644
index 2ab99f86..00000000
--- a/examples/bluetooth/picturetransfer/DeviceDiscovery.qml
+++ /dev/null
@@ -1,109 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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 QtQuick 2.1
-import QtBluetooth 5.2
-
-Item {
- Rectangle {
- id: title
- opacity: 0.7
- height: titleLabel.height + 90
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.top: parent.top
- anchors.margins: 100
-
- color: "#5c9fba"
- Text {
- id: titleLabel
- text: "Select device"
- color: "black"
- font.pointSize: 15
- anchors.centerIn: parent
- }
- }
-
-//! [Discovery-1]
- ListView {
-//! [Discovery-1]
- id: listView
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- anchors.top: title.bottom
- anchors.topMargin: 0
- anchors.margins: 100
- clip: true
- add: Transition {
- NumberAnimation { properties: "x"; from: 1000; duration: 500 }
- }
-//! [Discovery-2]
- model: BluetoothDiscoveryModel {
- discoveryMode: BluetoothDiscoveryModel.DeviceDiscovery
- onErrorChanged: {
- if (error == BluetoothDiscoveryModel.NoError)
- return;
- if (error == BluetoothDiscoveryModel.PoweredOffError)
- titleLabel.text = "Bluetooth turned off";
- else
- titleLabel.text = "Cannot find devices";
- }
- }
-
- delegate: Button {
- width: listView.width + 2
- text: model.name
- onClicked: root.remoteDevice = model.remoteAddress
- }
- }
-//! [Discovery-2]
-}
diff --git a/examples/bluetooth/picturetransfer/FileSending.qml b/examples/bluetooth/picturetransfer/FileSending.qml
deleted file mode 100644
index 336488a6..00000000
--- a/examples/bluetooth/picturetransfer/FileSending.qml
+++ /dev/null
@@ -1,111 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 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: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 QtQuick 2.1
-
-Item {
- Button {
- x: 40
- y: 40
- text: "Back"
- onClicked: loader.source = "DeviceDiscovery.qml"
- }
-
- Text {
- anchors.bottom: theProgress.top
- anchors.left: theProgress.left
- anchors.right: parent.right
- anchors.rightMargin: 100
- anchors.bottomMargin: 40
- wrapMode: Text.Wrap
- color: "white"
- text: "Sending file: " + root.fileName + "<br>" + "Remote-Device:" + root.remoteDevice
- }
-
- Rectangle {
- id: theProgress
- anchors.left: parent.left
- anchors.verticalCenter: parent.verticalCenter
- anchors.leftMargin: 100
- width: (parent.width - 200) * fileTransfer.progress
- height: 50
- color: "#5c9fba"
- opacity: 0.7
- Behavior on width {
- NumberAnimation {duration: 300}
- }
- }
- Text {
- text: "0%"
- anchors.horizontalCenter: theProgress.left
- anchors.top: theProgress.bottom
- anchors.topMargin: 10
- color: "white"
- }
-
- Text {
- text: "100%"
- anchors.right: parent.right
- anchors.rightMargin: 100 - width/2
- anchors.top: theProgress.bottom
- anchors.topMargin: 10
- color: "white"
- }
-
- Image {
- anchors.top: theProgress.bottom
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- anchors.margins: 60
- fillMode: Image.PreserveAspectFit
- source: "file://" + root.fileName
- }
-}
diff --git a/examples/bluetooth/picturetransfer/PictureSelector.qml b/examples/bluetooth/picturetransfer/PictureSelector.qml
deleted file mode 100644
index d9dd401b..00000000
--- a/examples/bluetooth/picturetransfer/PictureSelector.qml
+++ /dev/null
@@ -1,142 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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 QtQuick 2.1
-import Qt.labs.folderlistmodel 1.0
-
-Item {
- Rectangle {
- id: title
- opacity: 0.7
- height: titleLabel.height + 90
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.top: parent.top
- anchors.margins: 70
-
- color: "#5c9fba"
- Text {
- id: titleLabel
- text: "Select picture"
- color: "white"
- font.bold: true
- font.pointSize: 15
- anchors.centerIn: parent
- }
- }
-
- ListView {
- id: listView
- clip: true
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.bottom: parent.bottom
- anchors.top: title.bottom
- anchors.topMargin: 0
- anchors.margins: 70
- spacing: 5
- add: Transition {
- NumberAnimation { properties: "x"; from: 1000; duration: 500 }
- }
-
-//! [FileSelect-1]
- model: FolderListModel {
- folder: "file://"+SystemPictureFolder
- showDirs: false
- }
-
- delegate: Rectangle {
-//! [FileSelect-1]
- opacity: 0.7
- height: label.height + 130
- width: listView.width + 2
- x: -1
- border.color: Qt.lighter("#67b0d1")
- border.width: 1
- color: mArea.pressed ? "#5c9fba" : "#67b0d1"
- Image {
- id: picture
- anchors.verticalCenter: parent.verticalCenter
- height: parent.height-10
- fillMode: Image.PreserveAspectFit
- asynchronous: true
- source: "file://" + model.filePath
- }
-
-//! [FileSelect-2]
- Text {
-//! [FileSelect-2]
- id: label
- anchors.verticalCenter: parent.verticalCenter
- anchors.right: parent.right
- anchors.margins: 20
- anchors.left: picture.right
-//! [FileSelect-3]
- text: model.fileName
-//! [FileSelect-3]
- font.bold: true
- font.pointSize: 10
- color: "white"
- wrapMode: Text.WordWrap
-//! [FileSelect-4]
- }
- MouseArea {
- id: mArea
- anchors.fill: parent
- onClicked: {
- print ("path: " + model.filePath + " " + model.fileName)
- root.fileName = model.filePath
- }
- }
- }
-//! [FileSelect-4]
- }
-}
diff --git a/examples/bluetooth/picturetransfer/background.png b/examples/bluetooth/picturetransfer/background.png
deleted file mode 100644
index c9f80fb5..00000000
--- a/examples/bluetooth/picturetransfer/background.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/picturetransfer/bttransfer.qml b/examples/bluetooth/picturetransfer/bttransfer.qml
deleted file mode 100644
index 46ce24a3..00000000
--- a/examples/bluetooth/picturetransfer/bttransfer.qml
+++ /dev/null
@@ -1,83 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** 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: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 QtQuick 2.1
-
-//! [Root-1]
-Image {
- id: root
-//! [Root-1]
- width: 600; height: 800
- fillMode: Image.PreserveAspectCrop
- source: "background.png"
-//! [Root-2]
- property string remoteDevice;
- property string fileName;
-//! [Root-2]
- onRemoteDeviceChanged: {
- loader.source = "PictureSelector.qml"
- }
-
-//! [Root-3]
- onFileNameChanged: {
- fileTransfer.initTransfer(remoteDevice, fileName);
- loader.source = "FileSending.qml"
- }
-//! [Root-3]
-
- Loader {
- id: loader
- anchors.fill: parent
- source: "DeviceDiscovery.qml"
- }
-//! [Root-4]
-}
-//! [Root-4]
diff --git a/examples/bluetooth/picturetransfer/doc/images/opp-example-1.png b/examples/bluetooth/picturetransfer/doc/images/opp-example-1.png
deleted file mode 100644
index cf972277..00000000
--- a/examples/bluetooth/picturetransfer/doc/images/opp-example-1.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/picturetransfer/doc/images/opp-example-2.png b/examples/bluetooth/picturetransfer/doc/images/opp-example-2.png
deleted file mode 100644
index bc248284..00000000
--- a/examples/bluetooth/picturetransfer/doc/images/opp-example-2.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/picturetransfer/doc/images/opp-example-3.png b/examples/bluetooth/picturetransfer/doc/images/opp-example-3.png
deleted file mode 100644
index de7231dc..00000000
--- a/examples/bluetooth/picturetransfer/doc/images/opp-example-3.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/picturetransfer/doc/src/picturetransfer.qdoc b/examples/bluetooth/picturetransfer/doc/src/picturetransfer.qdoc
deleted file mode 100644
index a2acafb9..00000000
--- a/examples/bluetooth/picturetransfer/doc/src/picturetransfer.qdoc
+++ /dev/null
@@ -1,100 +0,0 @@
-a/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the QtBluetooth module.
-**
-** $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$
-**
-****************************************************************************/
-
-/*!
-\example picturetransfer
-\title QML Bluetooth Picture Push Example
-\brief An example showing the use Bluetooth Object Push Profile (OPP).
-
-The Bluetooth Picture Push example shows how to use the \l
-QBluetoothTransferManager API. The example transfers a local image to a remote
-device. Unfortunately this example cannot be used on Android as Qt does not
-support the Object Push Profile (OPP) on this platform.
-
-On the first user interface page the application scans for remote Bluetooth
-devices. The user must select the appropriate device to continue:
-
-\image opp-example-1.png
-
-The next page presents a list of image files on the device. The files must be
-located under \l QStandardPaths::PicturesLocation}:
-
-\image opp-example-2.png
-
-Once the picture was selected the UI shows the progress of the file transfer:
-
-\image opp-example-3.png
-
-\include examples-run.qdocinc
-
-\sa {Qt Bluetooth}
-
-\section1 Device Discovery
-
-The device discovery uses the \l BluetoothDiscoveryModel to detect the remote
-devices. Each discovery is displayed as an entry in a list. Once a device was
-selected the device address is stored in the \c root element. More details about
-the \c root element will follow further below.
-
-\snippet picturetransfer/DeviceDiscovery.qml Discovery-1
-\snippet picturetransfer/DeviceDiscovery.qml Discovery-2
-
-\section1 File Selection
-
-The file is selected with the help of \l FolderListModel. Once again the
-selected file is stored in the \c root element:
-
-\snippet picturetransfer/PictureSelector.qml FileSelect-1
-\snippet picturetransfer/PictureSelector.qml FileSelect-2
-\snippet picturetransfer/PictureSelector.qml FileSelect-3
-\snippet picturetransfer/PictureSelector.qml FileSelect-4
-
-\section1 Root Element
-
-The already mentioned \c root element collects the necessary pieces of data for
-the picture transfer. Once the file name has been set it triggers the file
-transfer:
-
-
-\snippet picturetransfer/bttransfer.qml Root-1
-\snippet picturetransfer/bttransfer.qml Root-2
-\snippet picturetransfer/bttransfer.qml Root-3
-\snippet picturetransfer/bttransfer.qml Root-3
-
-\section1 File Transfer
-
-The file transfer is implemented in C++:
-
-\snippet picturetransfer/filetransfer.cpp Transfer-1
-
-and exposed to QML via a context property:
-
-\snippet picturetransfer/main.cpp Transfer-2
-
-
-
-*/
diff --git a/examples/bluetooth/picturetransfer/filetransfer.cpp b/examples/bluetooth/picturetransfer/filetransfer.cpp
deleted file mode 100644
index 5816413b..00000000
--- a/examples/bluetooth/picturetransfer/filetransfer.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 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: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$
-**
-****************************************************************************/
-
-#include "filetransfer.h"
-#include <QFile>
-#include <QBluetoothTransferReply>
-#include <QDebug>
-
-FileTransfer::FileTransfer(QObject *parent) :
- QObject(parent), m_progress(0)
-{
-}
-
-//! [Transfer-1]
-void FileTransfer::initTransfer(QString address, QString fileName)
-{
- qDebug() << "Begin sharing file: " << address << fileName;
- QBluetoothAddress btAddress = QBluetoothAddress(address);
- QBluetoothTransferRequest request(btAddress);
- QFile *file = new QFile(fileName);
- reply = manager.put(request, file);
- connect(reply, SIGNAL(transferProgress(qint64,qint64)), this, SLOT(updateProgress(qint64,qint64)));
-}
-//! [Transfer-1]
-
-void FileTransfer::updateProgress(qint64 transferred, qint64 total)
-{
- m_progress = ((float)transferred)/((float)total);
- emit progressChanged();
-}
diff --git a/examples/bluetooth/picturetransfer/filetransfer.h b/examples/bluetooth/picturetransfer/filetransfer.h
deleted file mode 100644
index 4dee32fe..00000000
--- a/examples/bluetooth/picturetransfer/filetransfer.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 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: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$
-**
-****************************************************************************/
-
-#ifndef FILETRANSFER_H
-#define FILETRANSFER_H
-
-#include <QObject>
-#include <QBluetoothTransferManager>
-
-class FileTransfer : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(float progress READ getProgress NOTIFY progressChanged)
-public:
- explicit FileTransfer(QObject *parent = nullptr);
- float getProgress() { return m_progress;}
-
-signals:
- void progressChanged();
-
-public slots:
- void initTransfer(QString address, QString fileName);
- void updateProgress(qint64,qint64);
-
-private:
- QBluetoothTransferManager manager;
- QBluetoothTransferReply *reply;
- float m_progress;
-};
-
-#endif // FILETRANSFER_H
diff --git a/examples/bluetooth/picturetransfer/icon.png b/examples/bluetooth/picturetransfer/icon.png
deleted file mode 100644
index e378a26d..00000000
--- a/examples/bluetooth/picturetransfer/icon.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/picturetransfer/main.cpp b/examples/bluetooth/picturetransfer/main.cpp
deleted file mode 100644
index 4622e87e..00000000
--- a/examples/bluetooth/picturetransfer/main.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 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: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$
-**
-****************************************************************************/
-
-#include <QGuiApplication>
-#include <QtQml/QQmlEngine>
-#include <QtQuick/QQuickView>
-#include <QDebug>
-#include <QQmlContext>
-#include <QStandardPaths>
-#include "filetransfer.h"
-
-int main(int argc, char *argv[])
-{
- QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
- QGuiApplication application(argc, argv);
-//! [Transfer-2]
- QQuickView view;
- FileTransfer fileTransfer;
- view.rootContext()->setContextProperty("fileTransfer", QVariant::fromValue(&fileTransfer));
-//! [Transfer-2]
- view.rootContext()->setContextProperty("SystemPictureFolder",
- QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).first());
- qDebug() << QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
-
- view.setSource(QUrl(QStringLiteral("qrc:/bttransfer.qml")));
- view.setResizeMode(QQuickView::SizeRootObjectToView);
- QObject::connect(view.engine(), SIGNAL(quit()), qApp, SLOT(quit()));
- view.show();
- return application.exec();
-}
diff --git a/examples/bluetooth/picturetransfer/picturetransfer.pro b/examples/bluetooth/picturetransfer/picturetransfer.pro
deleted file mode 100644
index 077673e9..00000000
--- a/examples/bluetooth/picturetransfer/picturetransfer.pro
+++ /dev/null
@@ -1,28 +0,0 @@
-QT += quick bluetooth
-
-
-TARGET = qml_picturetransfer
-TEMPLATE = app
-
-RESOURCES += \
- qmltransfer.qrc
-
-OTHER_FILES += \
- bttransfer.qml \
- Button.qml \
- DeviceDiscovery.qml \
- PictureSelector.qml \
- FileSending.qml
-
-HEADERS += \
- filetransfer.h
-
-SOURCES += \
- filetransfer.cpp \
- main.cpp
-
-target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/picturetransfer
-INSTALLS += target
-
-EXAMPLE_FILES += \
- icon.png
diff --git a/examples/bluetooth/picturetransfer/qmltransfer.qrc b/examples/bluetooth/picturetransfer/qmltransfer.qrc
deleted file mode 100644
index f28e97ea..00000000
--- a/examples/bluetooth/picturetransfer/qmltransfer.qrc
+++ /dev/null
@@ -1,10 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>bttransfer.qml</file>
- <file>DeviceDiscovery.qml</file>
- <file>PictureSelector.qml</file>
- <file>FileSending.qml</file>
- <file>Button.qml</file>
- <file>background.png</file>
- </qresource>
-</RCC>
diff --git a/examples/bluetooth/pingpong/assets/Board.qml b/examples/bluetooth/pingpong/assets/Board.qml
deleted file mode 100644
index 576772bf..00000000
--- a/examples/bluetooth/pingpong/assets/Board.qml
+++ /dev/null
@@ -1,190 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.0
-import QtQuick.Window 2.1
-
-Rectangle {
- id: board
- width: 600
- height: 300
-
- // 1 - server role; left pedal
- // 2 - client role; right pedal
- property int roleSide: pingPong.role
- onRoleSideChanged: {
- if (pingPong.role == 1) {
- rightMouse.opacity = 0.7
- rightMouse.enabled = false
- }
- else if (pingPong.role == 2) {
- leftMouse.opacity = 0.7
- leftMouse.enabled = false
- }
- }
-
- property bool deviceMessage: pingPong.showDialog
- onDeviceMessageChanged: {
- if (pingPong.showDialog) {
- info.visible = true;
- board.opacity = 0.5;
- } else {
- info.visible = false;
- board.opacity = 1;
- }
- }
-
- // Left pedal - server role
- Rectangle {
- id: leftblock
- y: (parent.height/2)
- width: (parent.width/27)
- height: (parent.height/5)
- anchors.left: parent.left
- color: "#363636"
- radius: 10
-
- MouseArea {
- id: leftMouse
- anchors.fill: parent
- acceptedButtons: Qt.LeftButton
- drag.target: leftblock
- drag.axis: Drag.YAxis
- drag.minimumY: 0
- drag.maximumY: (board.height - leftblock.height)
- }
- }
-
- // Right pedal - client role
- Rectangle {
- id: rightblock
- y: (parent.height/2)
- width: (parent.width/27)
- height: (parent.height/5)
- anchors.right: parent.right
- color: "#363636"
- radius: 10
-
- MouseArea {
- id: rightMouse
- anchors.fill: parent
- acceptedButtons: Qt.LeftButton
- drag.target: rightblock
- drag.axis: Drag.YAxis
- drag.minimumY: 0
- drag.maximumY: (board.height - rightblock.height)
- }
- }
-
- property double leftBlockY: leftblock.y
- onLeftBlockYChanged: pingPong.updateLeftBlock(leftblock.y)
-
- property double leftBlockUpdate: pingPong.leftBlockY
- onLeftBlockUpdateChanged: leftblock.y = pingPong.leftBlockY
-
- property double rightBlockY: rightblock.y
- onRightBlockYChanged: pingPong.updateRightBlock(rightblock.y)
-
- property double rightBlockUpdate: pingPong.rightBlockY
- onRightBlockUpdateChanged: rightblock.y = pingPong.rightBlockY
-
- Rectangle {
- id: splitter
- color: "#363636"
- anchors.horizontalCenter: parent.horizontalCenter
- height: parent.height
- width: parent.width/100
- }
-
- Text {
- id: leftResult
- text: pingPong.leftResult
- font.bold: true
- font.pixelSize: 30
- anchors.right: splitter.left
- anchors.top: parent.top
- anchors.margins: 15
- }
-
- Text {
- id: rightResult
- text: pingPong.rightResult
- font.bold: true
- font.pixelSize: 30
- anchors.left: splitter.right
- anchors.top: parent.top
- anchors.margins: 15
- }
-
- Rectangle {
- id: ball
- width: leftblock.width/2
- height: leftblock.width/2
- radius: width
- color: "#363636"
- x: pingPong.ballX
- y: pingPong.ballY
-
- SequentialAnimation {
- running: true
- NumberAnimation { target: ball; property: "x"; duration: 50 }
- NumberAnimation { target: ball; property: "y"; duration: 50 }
- }
- }
-
- Component.onCompleted: {
- if (menulist.height == Screen.height && menulist.width == Screen.width)
- pingPong.setSize(Screen.width, Screen.height)
- else
- pingPong.setSize(board.width, board.height)
- pingPong.updateLeftBlock(leftblock.y)
- pingPong.updateRightBlock(rightblock.y)
- }
-}
diff --git a/examples/bluetooth/pingpong/assets/Dialog.qml b/examples/bluetooth/pingpong/assets/Dialog.qml
deleted file mode 100644
index 6ec4f1dc..00000000
--- a/examples/bluetooth/pingpong/assets/Dialog.qml
+++ /dev/null
@@ -1,71 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.0
-
-Rectangle {
- width: parent.width/2
- height: message.implicitHeight*2
- z: 50
- border.width: 2
- border.color: "#363636"
- radius: 10
-
- Text {
- id: message
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- anchors.fill: parent
- wrapMode: Text.WordWrap
- elide: Text.ElideMiddle
- text: pingPong.message
- color: "#363636"
- }
-}
diff --git a/examples/bluetooth/pingpong/assets/Menu.qml b/examples/bluetooth/pingpong/assets/Menu.qml
deleted file mode 100644
index 019718cf..00000000
--- a/examples/bluetooth/pingpong/assets/Menu.qml
+++ /dev/null
@@ -1,132 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.0
-
-Rectangle {
- width: 600
- height: 300
-
-
- Rectangle {
- width: parent.width
- height: headerText.implicitHeight *1.2
- border.width: 1
- border.color: "#363636"
- radius: 5
-
- Text {
- id: headerText
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- anchors.fill: parent
- text: "Welcome to PingPong Game \n Please select an option"
- font.pointSize: 20
- elide: Text.ElideMiddle
- color: "#363636"
- }
- }
-
- Rectangle {
- id: startServer
- anchors.centerIn: parent
- width: parent.width/2
- height: startServerText.implicitHeight*5
- color: "#363636"
-
- Text {
- id: startServerText
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- anchors.fill: parent
- font.bold: true
- text: "Start PingPong server"
- color: "#E3E3E3"
- wrapMode: Text.WordWrap
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- pageLoader.source = "Board.qml";
- pingPong.startServer();
- }
- }
- }
-
- Rectangle {
- id: startClient
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.top: startServer.bottom
- anchors.topMargin: 10
- width: parent.width/2
- height: startClientText.implicitHeight*5
- color: "#363636"
-
- Text {
- id: startClientText
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- anchors.fill: parent
- font.bold: true
- text: "Start PingPong client"
- color: "#E3E3E3"
- wrapMode: Text.WordWrap
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- pageLoader.source = "Board.qml";
- pingPong.startClient()
- }
- }
- }
-}
diff --git a/examples/bluetooth/pingpong/assets/main.qml b/examples/bluetooth/pingpong/assets/main.qml
deleted file mode 100644
index 10e477df..00000000
--- a/examples/bluetooth/pingpong/assets/main.qml
+++ /dev/null
@@ -1,72 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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 QtQuick 2.0
-import QtQuick.Window 2.1
-
-Window {
- id: menulist
- width: 600
- height: 300
- visible: true
-
- Dialog {
- id: info
- anchors.centerIn: parent
- visible: false
- }
-
- Component.onCompleted: pageLoader.source = "Menu.qml"
-
- Loader {
- id: pageLoader
- anchors.fill: parent
- }
-}
diff --git a/examples/bluetooth/pingpong/doc/images/intro.png b/examples/bluetooth/pingpong/doc/images/intro.png
deleted file mode 100644
index 062b8ea0..00000000
--- a/examples/bluetooth/pingpong/doc/images/intro.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/pingpong/doc/images/intro1.png b/examples/bluetooth/pingpong/doc/images/intro1.png
deleted file mode 100644
index c1cedae2..00000000
--- a/examples/bluetooth/pingpong/doc/images/intro1.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/pingpong/doc/src/pingpong.qdoc b/examples/bluetooth/pingpong/doc/src/pingpong.qdoc
deleted file mode 100644
index 259b6b97..00000000
--- a/examples/bluetooth/pingpong/doc/src/pingpong.qdoc
+++ /dev/null
@@ -1,82 +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: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$
-**
-****************************************************************************/
-
-/*!
- \example pingpong
- \title Bluetooth QML Ping Pong example
- \brief A QML example showing Bluetooth communication.
-
- The Bluetooth QML Ping Pong example presents the socket communication between two
- Bluetooth devices. The basic concept is the ping pong game where two players
- communicate via sockets.
-
- \image intro.png
-
- \include examples-run.qdocinc
-
- At the beginning, the user selects the role. One device acts as a server and the second
- one as a client. After selecting the role, adjustments to the screen size are done
- (two devices might have different screen sizes). The server side starts a service named
- "PingPong server".
-
- \snippet pingpong/pingpong.cpp Starting the server
-
- On the client side, the full service discovery on the nearby Bluetooth devices is done.
-
- \snippet pingpong/pingpong.cpp Searching for the service
-
- When the ping pong service is discovered, the client connects to the server using the socket.
-
- \snippet pingpong/pingpong.cpp Connecting the socket
-
- On the server side, the connected signal is emitted initiating that the client is connected.
- The necessary signals and slots on the server side are connected.
-
- \snippet pingpong/pingpong.cpp Initiating server socket
-
- The game starts after the devices are connected and the screen is adjusted.
-
- \snippet pingpong/pingpong.cpp Start the game
-
- The server updates the ball direction and coordinates. The coordinates of pedals are sent
- to each other every 50ms.
-
- \snippet pingpong/pingpong.cpp Updating coordinates
-
- The coordinates are updated and exchanged via sockets. As presented, the server sends its
- pedal's y coordinate and the ball coordinates whereas, the client sends only its pedal
- y coordinate.
-
- \snippet pingpong/pingpong.cpp Checking the boundaries
-
- In the code above, it was shown how the server checks whether the ball has reached
- the boundaries of the board. In the case of the goal, the server updates
- the results via its socket.
-
- \image intro1.png
-
-*/
diff --git a/examples/bluetooth/pingpong/main.cpp b/examples/bluetooth/pingpong/main.cpp
deleted file mode 100644
index 7c34b135..00000000
--- a/examples/bluetooth/pingpong/main.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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$
-**
-****************************************************************************/
-
-#include <QQmlContext>
-#include <QGuiApplication>
-#include <QQmlApplicationEngine>
-#include <QLoggingCategory>
-#include "pingpong.h"
-
-
-int main(int argc, char *argv[])
-{
- //QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
- QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
- QGuiApplication app(argc, argv);
- PingPong pingPong;
- QQmlApplicationEngine engine;
- engine.rootContext()->setContextProperty("pingPong", &pingPong);
- engine.load(QUrl("qrc:/assets/main.qml"));
- return app.exec();
-}
diff --git a/examples/bluetooth/pingpong/pingpong.cpp b/examples/bluetooth/pingpong/pingpong.cpp
deleted file mode 100644
index d80df3d6..00000000
--- a/examples/bluetooth/pingpong/pingpong.cpp
+++ /dev/null
@@ -1,489 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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$
-**
-****************************************************************************/
-
-#include "pingpong.h"
-#include <QDebug>
-#ifdef Q_OS_ANDROID
-#include <QtAndroid>
-#endif
-
-PingPong::PingPong():
- m_serverInfo(0), socket(0), discoveryAgent(0), interval(5), m_resultLeft(0), m_resultRight(0),
- m_showDialog(false), m_role(0), m_proportionX(0), m_proportionY(0), m_serviceFound(false)
-{
- m_timer = new QTimer(this);
- connect(m_timer, &QTimer::timeout, this, &PingPong::update);
-}
-
-PingPong::~PingPong()
-{
- delete m_timer;
- delete m_serverInfo;
- delete socket;
- delete discoveryAgent;
-}
-
-void PingPong::startGame()
-{
- m_showDialog = false;
- emit showDialogChanged();
- //! [Start the game]
- if (m_role == 1)
- updateDirection();
-
- m_timer->start(50);
- //! [Start the game]
-}
-
-void PingPong::update()
-{
- QByteArray size;
- // Server is only updating the coordinates
- //! [Updating coordinates]
- if (m_role == 1) {
- checkBoundaries();
- m_ballPreviousX = m_ballX;
- m_ballPreviousY = m_ballY;
- m_ballY = m_direction*(m_ballX+interval) - m_direction*m_ballX + m_ballY;
- m_ballX = m_ballX + interval;
-
- size.setNum(m_ballX);
- size.append(' ');
- QByteArray size1;
- size1.setNum(m_ballY);
- size.append(size1);
- size.append(' ');
- size1.setNum(m_leftBlockY);
- size.append(size1);
- size.append(" \n");
- socket->write(size.constData());
- emit ballChanged();
- }
- else if (m_role == 2) {
- size.setNum(m_rightBlockY);
- size.append(" \n");
- socket->write(size.constData());
- }
- //! [Updating coordinates]
-}
-
-
-
-void PingPong::setSize(const float &x, const float &y)
-{
- m_boardWidth = x;
- m_boardHeight = y;
- m_targetX = m_boardWidth;
- m_targetY = m_boardHeight/2;
- m_ballPreviousX = m_ballX = m_boardWidth/2;
- m_ballPreviousY = m_ballY = m_boardHeight - m_boardWidth/54;
- emit ballChanged();
-}
-
-void PingPong::updateBall(const float &bX, const float &bY)
-{
- m_ballX = bX;
- m_ballY = bY;
-}
-
-void PingPong::updateLeftBlock(const float &lY)
-{
- m_leftBlockY = lY;
-}
-
-void PingPong::updateRightBlock(const float &rY)
-{
- m_rightBlockY = rY;
-}
-
-void PingPong::checkBoundaries()
-{
- float ballWidth = m_boardWidth/54;
- float blockSize = m_boardWidth/27;
- float blockHeight = m_boardHeight/5;
- //! [Checking the boundaries]
- if (((m_ballX + ballWidth) > (m_boardWidth - blockSize)) && ((m_ballY + ballWidth) < (m_rightBlockY + blockHeight))
- && (m_ballY > m_rightBlockY)) {
- m_targetY = 2 * m_ballY - m_ballPreviousY;
- m_targetX = m_ballPreviousX;
- interval = -5;
- updateDirection();
- }
- else if ((m_ballX < blockSize) && ((m_ballY + ballWidth) < (m_leftBlockY + blockHeight))
- && (m_ballY > m_leftBlockY)) {
- m_targetY = 2 * m_ballY - m_ballPreviousY;
- m_targetX = m_ballPreviousX;
- interval = 5;
- updateDirection();
- }
- else if (m_ballY < 0 || (m_ballY + ballWidth > m_boardHeight)) {
- m_targetY = m_ballPreviousY;
- m_targetX = m_ballX + interval;
- updateDirection();
- }
- //! [Checking the boundaries]
- else if ((m_ballX + ballWidth) > m_boardWidth) {
- m_resultLeft++;
- m_targetX = m_boardWidth;
- m_targetY = m_boardHeight/2;
- m_ballPreviousX = m_ballX = m_boardWidth/2;
- m_ballPreviousY = m_ballY = m_boardHeight - m_boardWidth/54;
-
- updateDirection();
- checkResult();
- QByteArray result;
- result.append("result ");
- QByteArray res;
- res.setNum(m_resultLeft);
- result.append(res);
- result.append(' ');
- res.setNum(m_resultRight);
- result.append(res);
- result.append(" \n");
- socket->write(result);
- qDebug() << result;
- emit resultChanged();
- }
- else if (m_ballX < 0) {
- m_resultRight++;
- m_targetX = 0;
- m_targetY = m_boardHeight/2;
- m_ballPreviousX = m_ballX = m_boardWidth/2;
- m_ballPreviousY = m_ballY = m_boardHeight - m_boardWidth/54;
- updateDirection();
- checkResult();
- QByteArray result;
- result.append("result ");
- QByteArray res;
- res.setNum(m_resultLeft);
- result.append(res);
- result.append(' ');
- res.setNum(m_resultRight);
- result.append(res);
- result.append(" \n");
- socket->write(result);
- emit resultChanged();
- }
-}
-
-void PingPong::checkResult()
-{
- if (m_resultRight == 10 && m_role == 2) {
- setMessage("Game over. You win!");
- m_timer->stop();
- }
- else if (m_resultRight == 10 && m_role == 1) {
- setMessage("Game over. You lose!");
- m_timer->stop();
- }
- else if (m_resultLeft == 10 && m_role == 1) {
- setMessage("Game over. You win!");
- m_timer->stop();
- }
- else if (m_resultLeft == 10 && m_role == 2) {
- setMessage("Game over. You lose!");
- m_timer->stop();
- }
-}
-
-void PingPong::updateDirection()
-{
- m_direction = (m_targetY - m_ballY)/(m_targetX - m_ballX);
-}
-
-void PingPong::startServer()
-{
- setMessage(QStringLiteral("Starting the server"));
- //! [Starting the server]
- m_serverInfo = new QBluetoothServer(QBluetoothServiceInfo::RfcommProtocol, this);
- connect(m_serverInfo, &QBluetoothServer::newConnection,
- this, &PingPong::clientConnected);
- connect(m_serverInfo, QOverload<QBluetoothServer::Error>::of(&QBluetoothServer::error),
- this, &PingPong::serverError);
- const QBluetoothUuid uuid(serviceUuid);
-
- m_serverInfo->listen(uuid, QStringLiteral("PingPong server"));
- //! [Starting the server]
- setMessage(QStringLiteral("Server started, waiting for the client. You are the left player."));
- // m_role is set to 1 if it is a server
- m_role = 1;
- emit roleChanged();
-}
-
-void PingPong::startClient()
-{
- //! [Searching for the service]
- discoveryAgent = new QBluetoothServiceDiscoveryAgent(QBluetoothAddress());
-
- connect(discoveryAgent, &QBluetoothServiceDiscoveryAgent::serviceDiscovered,
- this, &PingPong::addService);
- connect(discoveryAgent, &QBluetoothServiceDiscoveryAgent::finished,
- this, &PingPong::done);
- connect(discoveryAgent, QOverload<QBluetoothServiceDiscoveryAgent::Error>::of(&QBluetoothServiceDiscoveryAgent::error),
- this, &PingPong::serviceScanError);
-#ifdef Q_OS_ANDROID //see QTBUG-61392
- if (QtAndroid::androidSdkVersion() >= 23)
- discoveryAgent->setUuidFilter(QBluetoothUuid(androidUuid));
- else
- discoveryAgent->setUuidFilter(QBluetoothUuid(serviceUuid));
-#else
- discoveryAgent->setUuidFilter(QBluetoothUuid(serviceUuid));
-#endif
- discoveryAgent->start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
-
- //! [Searching for the service]
- setMessage(QStringLiteral("Starting server discovery. You are the right player"));
- // m_role is set to 2 if it is a client
- m_role = 2;
- emit roleChanged();
-}
-
-void PingPong::clientConnected()
-{
- //! [Initiating server socket]
- if (!m_serverInfo->hasPendingConnections()) {
- setMessage("FAIL: expected pending server connection");
- return;
- }
- socket = m_serverInfo->nextPendingConnection();
- if (!socket)
- return;
- socket->setParent(this);
- connect(socket, &QBluetoothSocket::readyRead,
- this, &PingPong::readSocket);
- connect(socket, &QBluetoothSocket::disconnected,
- this, &PingPong::clientDisconnected);
- connect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error),
- this, &PingPong::socketError);
-
- //! [Initiating server socket]
- setMessage(QStringLiteral("Client connected."));
-
- QByteArray size;
- size.setNum(m_boardWidth);
- size.append(' ');
- QByteArray size1;
- size1.setNum(m_boardHeight);
- size.append(size1);
- size.append(" \n");
- socket->write(size.constData());
-
-}
-
-void PingPong::clientDisconnected()
-{
- setMessage(QStringLiteral("Client disconnected"));
- m_timer->stop();
-}
-
-void PingPong::socketError(QBluetoothSocket::SocketError error)
-{
- Q_UNUSED(error);
- m_timer->stop();
-}
-
-void PingPong::serverError(QBluetoothServer::Error error)
-{
- Q_UNUSED(error);
- m_timer->stop();
-}
-
-void PingPong::done()
-{
- qDebug() << "Service scan done";
- if (!m_serviceFound)
- setMessage("PingPong service not found");
-}
-
-void PingPong::addService(const QBluetoothServiceInfo &service)
-{
- setMessage("Service found. Setting parameters...");
- //! [Connecting the socket]
- socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
- socket->connectToService(service);
-
- connect(socket, &QBluetoothSocket::readyRead, this, &PingPong::readSocket);
- connect(socket, &QBluetoothSocket::connected, this, &PingPong::serverConnected);
- connect(socket, &QBluetoothSocket::disconnected, this, &PingPong::serverDisconnected);
- //! [Connecting the socket]
- m_serviceFound = true;
-}
-
-void PingPong::serviceScanError(QBluetoothServiceDiscoveryAgent::Error error)
-{
- setMessage(QStringLiteral("Scanning error") + error);
-}
-
-bool PingPong::showDialog() const
-{
- return m_showDialog;
-}
-
-QString PingPong::message() const
-{
- return m_message;
-}
-
-void PingPong::serverConnected()
-{
- setMessage("Server Connected");
- QByteArray size;
- size.setNum(m_boardWidth);
- size.append(' ');
- QByteArray size1;
- size1.setNum(m_boardHeight);
- size.append(size1);
- size.append(" \n");
- socket->write(size.constData());
-}
-
-void PingPong::serverDisconnected()
-{
- setMessage("Server Disconnected");
- m_timer->stop();
-}
-
-void PingPong::readSocket()
-{
- if (!socket)
- return;
- const char sep = ' ';
- QByteArray line;
- while (socket->canReadLine()) {
- line = socket->readLine();
- //qDebug() << QString::fromUtf8(line.constData(), line.length());
- if (line.contains("result")) {
- QList<QByteArray> result = line.split(sep);
- if (result.size() > 2) {
- QByteArray leftSide = result.at(1);
- QByteArray rightSide = result.at(2);
- m_resultLeft = leftSide.toInt();
- m_resultRight = rightSide.toInt();
- emit resultChanged();
- checkResult();
- }
- }
- }
- if ((m_proportionX == 0 || m_proportionY == 0)) {
- QList<QByteArray> boardSize = line.split(sep);
- if (boardSize.size() > 1) {
- QByteArray boardWidth = boardSize.at(0);
- QByteArray boardHeight = boardSize.at(1);
- m_proportionX = m_boardWidth/boardWidth.toFloat();
- m_proportionY = m_boardHeight/boardHeight.toFloat();
- setMessage("Screen adjusted. Get ready!");
- QTimer::singleShot(3000, this, SLOT(startGame()));
- }
- }
- else if (m_role == 1) {
- QList<QByteArray> boardSize = line.split(sep);
- if (boardSize.size() > 1) {
- QByteArray rightBlockY = boardSize.at(0);
- m_rightBlockY = m_proportionY * rightBlockY.toFloat();
- emit rightBlockChanged();
- }
- }
- else if (m_role == 2) {
- QList<QByteArray> boardSize = line.split(sep);
- if (boardSize.size() > 2) {
- QByteArray ballX = boardSize.at(0);
- QByteArray ballY = boardSize.at(1);
- QByteArray leftBlockY = boardSize.at(2);
- m_ballX = m_proportionX * ballX.toFloat();
- m_ballY = m_proportionY * ballY.toFloat();
- m_leftBlockY = m_proportionY * leftBlockY.toFloat();
- emit leftBlockChanged();
- emit ballChanged();
- }
- }
-}
-
-void PingPong::setMessage(const QString &message)
-{
- m_showDialog = true;
- m_message = message;
- emit showDialogChanged();
-}
-
-int PingPong::role() const
-{
- return m_role;
-}
-
-int PingPong::leftResult() const
-{
- return m_resultLeft;
-}
-
-int PingPong::rightResult() const
-{
- return m_resultRight;
-}
-
-float PingPong::ballX() const
-{
- return m_ballX;
-}
-
-float PingPong::ballY() const
-{
- return m_ballY;
-}
-
-
-float PingPong::leftBlockY() const
-{
- return m_leftBlockY;
-}
-
-float PingPong::rightBlockY() const
-{
- return m_rightBlockY;
-}
diff --git a/examples/bluetooth/pingpong/pingpong.h b/examples/bluetooth/pingpong/pingpong.h
deleted file mode 100644
index 315f270b..00000000
--- a/examples/bluetooth/pingpong/pingpong.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module 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$
-**
-****************************************************************************/
-
-#ifndef PINGPONG_H
-#define PINGPONG_H
-
-#include <QTimer>
-#include <QObject>
-#include <qbluetoothserver.h>
-#include <qbluetoothserviceinfo.h>
-#include <qbluetoothlocaldevice.h>
-#include <qbluetoothservicediscoveryagent.h>
-
-static QString serviceUuid(QStringLiteral("e8e10f95-1a70-4b27-9ccf-02010264e9c9"));
-static QString androidUuid(QStringLiteral("c9e96402-0102-cf9c-274b-701a950fe1e8"));
-
-class PingPong: public QObject
-{
- Q_OBJECT
- Q_PROPERTY(float ballX READ ballX NOTIFY ballChanged)
- Q_PROPERTY(float ballY READ ballY NOTIFY ballChanged)
- Q_PROPERTY(float leftBlockY READ leftBlockY NOTIFY leftBlockChanged)
- Q_PROPERTY(float rightBlockY READ rightBlockY NOTIFY rightBlockChanged)
- Q_PROPERTY(bool showDialog READ showDialog NOTIFY showDialogChanged)
- Q_PROPERTY(QString message READ message NOTIFY showDialogChanged)
- Q_PROPERTY(int role READ role NOTIFY roleChanged)
- Q_PROPERTY(int leftResult READ leftResult NOTIFY resultChanged)
- Q_PROPERTY(int rightResult READ rightResult NOTIFY resultChanged)
-public:
- PingPong();
- ~PingPong();
- float ballX() const;
- float ballY() const;
- float leftBlockY() const;
- float rightBlockY() const;
- void checkBoundaries();
- void updateDirection();
- bool showDialog() const;
- QString message() const;
- void setMessage(const QString &message);
- int role() const;
- int leftResult() const;
- int rightResult() const;
- void checkResult();
-
-public slots:
- void startGame();
- void update();
- void setSize(const float &x, const float &y);
- void updateBall(const float &bX, const float &bY);
- void updateLeftBlock(const float &lY);
- void updateRightBlock(const float &rY);
- void startServer();
- void startClient();
- void clientConnected();
- void clientDisconnected();
- void serverConnected();
- void serverDisconnected();
- void socketError(QBluetoothSocket::SocketError);
- void serverError(QBluetoothServer::Error);
- void serviceScanError(QBluetoothServiceDiscoveryAgent::Error);
- void done();
- void addService(const QBluetoothServiceInfo &);
- void readSocket();
-
-Q_SIGNALS:
- void ballChanged();
- void leftBlockChanged();
- void rightBlockChanged();
- void showDialogChanged();
- void roleChanged();
- void resultChanged();
-
-private:
- QBluetoothServer *m_serverInfo;
- QBluetoothServiceInfo m_serviceInfo;
- QBluetoothSocket *socket;
- QBluetoothServiceDiscoveryAgent *discoveryAgent;
-
- float m_ballX;
- float m_ballY;
- float m_ballPreviousX;
- float m_ballPreviousY;
- float m_leftBlockY;
- float m_rightBlockY;
- QTimer *m_timer;
- float m_boardWidth;
- float m_boardHeight;
- float m_direction;
- float m_targetX;
- float m_targetY;
- int interval;
- int m_resultLeft;
- int m_resultRight;
- bool m_showDialog;
- QString m_message;
- int m_role;
- float m_proportionX;
- float m_proportionY;
- bool m_serviceFound;
-};
-
-#endif // PINGPONG_H
diff --git a/examples/bluetooth/pingpong/pingpong.pro b/examples/bluetooth/pingpong/pingpong.pro
deleted file mode 100644
index aa79212e..00000000
--- a/examples/bluetooth/pingpong/pingpong.pro
+++ /dev/null
@@ -1,20 +0,0 @@
-TEMPLATE = app
-TARGET = pingpong
-
-QT += quick bluetooth
-android: QT += androidextras
-
-# Input
-SOURCES += main.cpp \
- pingpong.cpp
-
-OTHER_FILES += assets/*.qml
-
-RESOURCES += \
- resource.qrc
-
-HEADERS += \
- pingpong.h
-
-target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/pingpong
-INSTALLS += target
diff --git a/examples/bluetooth/pingpong/resource.qrc b/examples/bluetooth/pingpong/resource.qrc
deleted file mode 100644
index 1475a7f3..00000000
--- a/examples/bluetooth/pingpong/resource.qrc
+++ /dev/null
@@ -1,8 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>assets/main.qml</file>
- <file>assets/Board.qml</file>
- <file>assets/Dialog.qml</file>
- <file>assets/Menu.qml</file>
- </qresource>
-</RCC>
diff --git a/examples/bluetooth/scanner/Button.qml b/examples/bluetooth/scanner/Button.qml
deleted file mode 100644
index 3d368cde..00000000
--- a/examples/bluetooth/scanner/Button.qml
+++ /dev/null
@@ -1,89 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module.
-**
-** $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 QtQuick 2.0
-
-Rectangle {
- id: button
-
- property bool active: buttonGroup.activeButton == button
- property bool fullDiscovery: false
- property alias text: label.text
-
- signal clicked()
- height: label.height*1.1
-
- color: active ? "#1c56f3" : "white"
-
- radius: 5
- border.width: 2
-
- Text {
- id: label
- text: "Full Discovery"
- font.bold: true
- font.pointSize: 17
- width: parent.width
- wrapMode: Text.WordWrap
- horizontalAlignment: Text.AlignHCenter
- anchors.centerIn: parent
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- button.clicked()
- //Reset the model
- btModel.running = false
- btModel.running = true
- buttonGroup.activeButton = button
- }
- }
-}
diff --git a/examples/bluetooth/scanner/default.png b/examples/bluetooth/scanner/default.png
deleted file mode 100644
index a1a74af5..00000000
--- a/examples/bluetooth/scanner/default.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/scanner/doc/images/devicescan.png b/examples/bluetooth/scanner/doc/images/devicescan.png
deleted file mode 100644
index d75fdd0e..00000000
--- a/examples/bluetooth/scanner/doc/images/devicescan.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/scanner/doc/images/servicescan.png b/examples/bluetooth/scanner/doc/images/servicescan.png
deleted file mode 100644
index 3a25c437..00000000
--- a/examples/bluetooth/scanner/doc/images/servicescan.png
+++ /dev/null
Binary files differ
diff --git a/examples/bluetooth/scanner/doc/src/scanner.qdoc b/examples/bluetooth/scanner/doc/src/scanner.qdoc
deleted file mode 100644
index 78720c00..00000000
--- a/examples/bluetooth/scanner/doc/src/scanner.qdoc
+++ /dev/null
@@ -1,58 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
-** 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$
-**
-****************************************************************************/
-
-/*!
-\example scanner
-\title QML Bluetooth Scanner Example
-\brief A QML example about locating Bluetooth devices.
-
-This is an example on how to locate Bluetooth devices in QML.
-
-The user has the choice to run three different types of Bluetooth scans. The device retrieves
-information about the remote device within Bluetooth range. This implies that the remote
-device can be discovered. The picture below demonstrates the potential result of such
-a search:
-
-\image devicescan.png
-
-The second and third type of scan dicover the types of services offered by each remote device.
-A full service discovery can take quite some time to finish. The local device connects to each
-remote device and performs an SDP enquiry. The results of such an enquiry can be seen below.
-
-\image servicescan.png
-
-In general a service discovery is based on the results of a previously run device enquiry. A minimal
-service discovery returns the same data set as a full discovery except that the results are retrieved
-from local cache information and may not always be complete and accurate. The primary reason to
-perform a minimal discovery are time constraints. A full service discovery can take up to two minutes.
-Note that not every platform supports a minimal discovery. In such cases the API performs a full discovery.
-
-\include examples-run.qdocinc
-
-\sa {Qt Bluetooth}
-*/
diff --git a/examples/bluetooth/scanner/qmlscanner.cpp b/examples/bluetooth/scanner/qmlscanner.cpp
deleted file mode 100644
index 2dbc0c27..00000000
--- a/examples/bluetooth/scanner/qmlscanner.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module.
-**
-** $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$
-**
-****************************************************************************/
-
-#include <QtGui/QGuiApplication>
-#include <QtQuick/QQuickView>
-#include <QtQml/QQmlEngine>
-#include <QtCore/QLoggingCategory>
-
-int main(int argc, char *argv[])
-{
- //QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
- QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
- QGuiApplication application(argc, argv);
- const QString mainQmlApp(QStringLiteral("qrc:/scanner.qml"));
- QQuickView view;
- view.setSource(QUrl(mainQmlApp));
- view.setResizeMode(QQuickView::SizeRootObjectToView);
- // Qt.quit() called in embedded .qml by default only emits
- // quit() signal, so do this (optionally use Qt.exit()).
- QObject::connect(view.engine(), SIGNAL(quit()), qApp, SLOT(quit()));
- view.setGeometry(QRect(100, 100, 360, 640));
- view.show();
- return application.exec();
-}
diff --git a/examples/bluetooth/scanner/scanner.pro b/examples/bluetooth/scanner/scanner.pro
deleted file mode 100644
index 68572533..00000000
--- a/examples/bluetooth/scanner/scanner.pro
+++ /dev/null
@@ -1,18 +0,0 @@
-QT = core bluetooth quick
-SOURCES += qmlscanner.cpp
-
-TARGET = qml_scanner
-TEMPLATE = app
-
-RESOURCES += \
- scanner.qrc
-
-OTHER_FILES += \
- scanner.qml \
- Button.qml \
- default.png
-
-#DEFINES += QMLJSDEBUGGER
-
-target.path = $$[QT_INSTALL_EXAMPLES]/bluetooth/scanner
-INSTALLS += target
diff --git a/examples/bluetooth/scanner/scanner.qml b/examples/bluetooth/scanner/scanner.qml
deleted file mode 100644
index d4c88a05..00000000
--- a/examples/bluetooth/scanner/scanner.qml
+++ /dev/null
@@ -1,216 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtBluetooth module.
-**
-** $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 QtQuick 2.0
-import QtBluetooth 5.2
-
-Item {
- id: top
-
- property BluetoothService currentService
-
- BluetoothDiscoveryModel {
- id: btModel
- running: true
- discoveryMode: BluetoothDiscoveryModel.DeviceDiscovery
- onDiscoveryModeChanged: console.log("Discovery mode: " + discoveryMode)
- onServiceDiscovered: console.log("Found new service " + service.deviceAddress + " " + service.deviceName + " " + service.serviceName);
- onDeviceDiscovered: console.log("New device: " + device)
- onErrorChanged: {
- switch (btModel.error) {
- case BluetoothDiscoveryModel.PoweredOffError:
- console.log("Error: Bluetooth device not turned on"); break;
- case BluetoothDiscoveryModel.InputOutputError:
- console.log("Error: Bluetooth I/O Error"); break;
- case BluetoothDiscoveryModel.InvalidBluetoothAdapterError:
- console.log("Error: Invalid Bluetooth Adapter Error"); break;
- case BluetoothDiscoveryModel.NoError:
- break;
- default:
- console.log("Error: Unknown Error"); break;
- }
- }
- }
-
- Rectangle {
- id: busy
-
- width: top.width * 0.7;
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.top: top.top;
- height: text.height*1.2;
- radius: 5
- color: "#1c56f3"
- visible: btModel.running
-
- Text {
- id: text
- text: "Scanning"
- font.bold: true
- font.pointSize: 20
- anchors.centerIn: parent
- }
-
- SequentialAnimation on color {
- id: busyThrobber
- ColorAnimation { easing.type: Easing.InOutSine; from: "#1c56f3"; to: "white"; duration: 1000; }
- ColorAnimation { easing.type: Easing.InOutSine; to: "#1c56f3"; from: "white"; duration: 1000 }
- loops: Animation.Infinite
- }
- }
-
- ListView {
- id: mainList
- width: top.width
- anchors.top: busy.bottom
- anchors.bottom: buttonGroup.top
- anchors.bottomMargin: 10
- anchors.topMargin: 10
- clip: true
-
- model: btModel
- delegate: Rectangle {
- id: btDelegate
- width: parent.width
- height: column.height + 10
-
- property bool expended: false;
- clip: true
- Image {
- id: bticon
- source: "qrc:/default.png";
- width: bttext.height;
- height: bttext.height;
- anchors.top: parent.top
- anchors.left: parent.left
- anchors.margins: 5
- }
-
- Column {
- id: column
- anchors.left: bticon.right
- anchors.leftMargin: 5
- Text {
- id: bttext
- text: deviceName ? deviceName : name
- font.family: "FreeSerif"
- font.pointSize: 16
- }
-
- Text {
- id: details
- function get_details(s) {
- if (btModel.discoveryMode == BluetoothDiscoveryModel.DeviceDiscovery) {
- //We are doing a device discovery
- var str = "Address: " + remoteAddress;
- return str;
- } else {
- var str = "Address: " + s.deviceAddress;
- if (s.serviceName) { str += "<br>Service: " + s.serviceName; }
- if (s.serviceDescription) { str += "<br>Description: " + s.serviceDescription; }
- if (s.serviceProtocol) { str += "<br>Protocol: " + s.serviceProtocol; }
- return str;
- }
- }
- visible: opacity !== 0
- opacity: btDelegate.expended ? 1 : 0.0
- text: get_details(service)
- font.family: "FreeSerif"
- font.pointSize: 14
- Behavior on opacity {
- NumberAnimation { duration: 200}
- }
- }
- }
- Behavior on height { NumberAnimation { duration: 200} }
-
- MouseArea {
- anchors.fill: parent
- onClicked: btDelegate.expended = !btDelegate.expended
- }
- }
- focus: true
- }
-
- Row {
- id: buttonGroup
- property var activeButton: devButton
-
- anchors.bottom: parent.bottom
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.bottomMargin: 5
- spacing: 10
-
- Button {
- id: fdButton
- width: top.width/3*0.9
- //mdButton has longest text
- height: mdButton.height
- text: "Full Discovery"
- onClicked: btModel.discoveryMode = BluetoothDiscoveryModel.FullServiceDiscovery
- }
- Button {
- id: mdButton
- width: top.width/3*0.9
- text: "Minimal Discovery"
- onClicked: btModel.discoveryMode = BluetoothDiscoveryModel.MinimalServiceDiscovery
- }
- Button {
- id: devButton
- width: top.width/3*0.9
- //mdButton has longest text
- height: mdButton.height
- text: "Device Discovery"
- onClicked: btModel.discoveryMode = BluetoothDiscoveryModel.DeviceDiscovery
- }
- }
-
-}
diff --git a/examples/bluetooth/scanner/scanner.qrc b/examples/bluetooth/scanner/scanner.qrc
deleted file mode 100644
index 46232c8a..00000000
--- a/examples/bluetooth/scanner/scanner.qrc
+++ /dev/null
@@ -1,7 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>scanner.qml</file>
- <file>default.png</file>
- <file>Button.qml</file>
- </qresource>
-</RCC>
diff --git a/examples/bluetooth/shared/Info.cmake.ios.plist b/examples/bluetooth/shared/Info.cmake.ios.plist
new file mode 100644
index 00000000..be5a2bac
--- /dev/null
+++ b/examples/bluetooth/shared/Info.cmake.ios.plist
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+ <key>CFBundleVersion</key>
+ <string>0.0.1</string>
+ <key>CFBundleShortVersionString</key>
+ <string>0.0.1</string>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>NSHumanReadableCopyright</key>
+ <string></string>
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>NSBluetoothAlwaysUsageDescription</key>
+ <string>Qt BT Example wants to access your Bluetooth adapter</string>
+</dict>
+</plist>
diff --git a/examples/bluetooth/shared/Info.cmake.macos.plist b/examples/bluetooth/shared/Info.cmake.macos.plist
new file mode 100644
index 00000000..77c8db19
--- /dev/null
+++ b/examples/bluetooth/shared/Info.cmake.macos.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+ <key>NSBluetoothAlwaysUsageDescription</key>
+ <string>Qt BT Example wants to access your Bluetooth adapter</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/examples/bluetooth/shared/Info.qmake.ios.plist b/examples/bluetooth/shared/Info.qmake.ios.plist
new file mode 100644
index 00000000..1a3885b5
--- /dev/null
+++ b/examples/bluetooth/shared/Info.qmake.ios.plist
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleIdentifier</key>
+ <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleVersion</key>
+ <string>0.0.1</string>
+ <key>CFBundleShortVersionString</key>
+ <string>0.0.1</string>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>NSHumanReadableCopyright</key>
+ <string></string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>NSBluetoothAlwaysUsageDescription</key>
+ <string>Qt BT Example wants to access your Bluetooth adapter</string>
+</dict>
+</plist>
diff --git a/examples/bluetooth/shared/Info.qmake.macos.plist b/examples/bluetooth/shared/Info.qmake.macos.plist
new file mode 100644
index 00000000..80b3630b
--- /dev/null
+++ b/examples/bluetooth/shared/Info.qmake.macos.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+ <key>NSBluetoothAlwaysUsageDescription</key>
+ <string>Qt BT Example wants to access your Bluetooth adapter</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/examples/nfc/CMakeLists.txt b/examples/nfc/CMakeLists.txt
new file mode 100644
index 00000000..96cd6112
--- /dev/null
+++ b/examples/nfc/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+if(TARGET Qt6::Widgets)
+ qt_internal_add_example(annotatedurl)
+endif()
+if(TARGET Qt6::QuickControls2)
+ qt_internal_add_example(ndefeditor)
+endif()
diff --git a/examples/nfc/annotatedurl/CMakeLists.txt b/examples/nfc/annotatedurl/CMakeLists.txt
new file mode 100644
index 00000000..a51a2052
--- /dev/null
+++ b/examples/nfc/annotatedurl/CMakeLists.txt
@@ -0,0 +1,55 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(annotatedurl LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/nfc/annotatedurl")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Nfc Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(annotatedurl
+ MANUAL_FINALIZATION
+ annotatedurl.cpp annotatedurl.h
+ main.cpp
+ mainwindow.cpp mainwindow.h
+)
+
+set_target_properties(annotatedurl PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+if(IOS)
+ set_target_properties(annotatedurl PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist"
+ )
+endif()
+
+target_link_libraries(annotatedurl PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Nfc
+ Qt6::Widgets
+)
+
+if(ANDROID)
+ set_property(TARGET annotatedurl
+ APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/android
+ )
+endif()
+
+qt_finalize_target(annotatedurl)
+
+install(TARGETS annotatedurl
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/nfc/annotatedurl/Info.plist b/examples/nfc/annotatedurl/Info.plist
new file mode 100644
index 00000000..7813167f
--- /dev/null
+++ b/examples/nfc/annotatedurl/Info.plist
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>${ASSETCATALOG_COMPILER_APPICON_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${QMAKE_SHORT_VERSION}</string>
+ <key>CFBundleSignature</key>
+ <string>${QMAKE_PKGINFO_TYPEINFO}</string>
+ <key>CFBundleVersion</key>
+ <string>${QMAKE_FULL_VERSION}</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>MinimumOSVersion</key>
+ <string>${IPHONEOS_DEPLOYMENT_TARGET}</string>
+ <key>NFCReaderUsageDescription</key>
+ <string>Qt's annotatedurl wants to access your NFC hardware</string>
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
diff --git a/examples/nfc/annotatedurl/android/AndroidManifest.xml b/examples/nfc/annotatedurl/android/AndroidManifest.xml
new file mode 100644
index 00000000..3378612d
--- /dev/null
+++ b/examples/nfc/annotatedurl/android/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<manifest package="org.qtproject.example.annotatedurl" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="-- %%INSERT_VERSION_NAME%% --" android:versionCode="-- %%INSERT_VERSION_CODE%% --" android:installLocation="auto">
+ <!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
+ Remove the comment if you do not require these default permissions. -->
+ <!-- %%INSERT_PERMISSIONS -->
+
+ <!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
+ Remove the comment if you do not require these default features. -->
+ <!-- %%INSERT_FEATURES -->
+
+ <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
+ <application android:hardwareAccelerated="true" android:name="org.qtproject.qt.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:extractNativeLibs="true" android:requestLegacyExternalStorage="true" android:allowBackup="true" android:fullBackupOnly="false">
+ <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTask" android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:mimeType="text/plain"/>
+ </intent-filter>
+
+ <!-- Application arguments -->
+ <meta-data android:name="android.app.arguments" android:value="-- %%INSERT_APP_ARGUMENTS%% --"/>
+ <!-- Application arguments -->
+
+ <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
+
+ <!-- Background running -->
+ <!-- Warning: changing this value to true may cause unexpected crashes if the
+ application still try to draw after
+ "applicationStateChanged(Qt::ApplicationSuspended)"
+ signal is sent! -->
+ <meta-data android:name="android.app.background_running" android:value="false"/>
+ <!-- Background running -->
+
+ <!-- extract android style -->
+ <!-- available android:values :
+ * default - In most cases this will be the same as "full", but it can also be something else if needed, e.g., for compatibility reasons
+ * full - useful QWidget & Quick Controls 1 apps
+ * minimal - useful for Quick Controls 2 apps, it is much faster than "full"
+ * none - useful for apps that don't use any of the above Qt modules
+ -->
+ <meta-data android:name="android.app.extract_android_style" android:value="default"/>
+ <!-- extract android style -->
+ </activity>
+
+ <!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
+
+ </application>
+
+</manifest>
diff --git a/examples/nfc/annotatedurl/annotatedurl.cpp b/examples/nfc/annotatedurl/annotatedurl.cpp
index acd401f2..33d5109e 100644
--- a/examples/nfc/annotatedurl/annotatedurl.cpp
+++ b/examples/nfc/annotatedurl/annotatedurl.cpp
@@ -1,98 +1,41 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module.
-**
-** $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) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "annotatedurl.h"
-#include <QtNfc/qnearfieldmanager.h>
-#include <QtNfc/qnearfieldtarget.h>
-#include <QtNfc/qndefmessage.h>
-#include <QtNfc/qndefrecord.h>
-#include <QtNfc/qndefnfctextrecord.h>
-#include <QtNfc/qndefnfcurirecord.h>
-
-#include <QtWidgets/QGridLayout>
-#include <QtWidgets/QLabel>
-#include <QtGui/QMouseEvent>
-#include <QtGui/QDesktopServices>
-#include <QtCore/QDebug>
-#include <QtCore/QLocale>
-#include <QtCore/QUrl>
+#include <QDebug>
+#include <QLocale>
+#include <QUrl>
-AnnotatedUrl::AnnotatedUrl(QObject *parent)
-: QObject(parent)
-{
- //! [QNearFieldManager register handler]
- manager = new QNearFieldManager(this);
- if (!manager->isAvailable()) {
- qWarning() << "NFC not available";
- return;
- }
+#include <QDesktopServices>
+#include <QEvent>
- QNdefFilter filter;
- filter.setOrderMatch(false);
- filter.appendRecord<QNdefNfcTextRecord>(1, UINT_MAX);
- filter.appendRecord<QNdefNfcUriRecord>();
- // type parameter cannot specify substring so filter for "image/" below
- filter.appendRecord(QNdefRecord::Mime, QByteArray(), 0, 1);
+#include <QNdefMessage>
+#include <QNdefNfcTextRecord>
+#include <QNdefNfcUriRecord>
+#include <QNdefRecord>
+#include <QNearFieldManager>
+#include <QNearFieldTarget>
- int result = manager->registerNdefMessageHandler(filter, this,
- SLOT(handleMessage(QNdefMessage,QNearFieldTarget*)));
- //! [QNearFieldManager register handler]
+#include <QGridLayout>
+#include <QLabel>
- if (result < 0)
- qWarning() << "Platform does not support NDEF message handler registration";
-
- manager->startTargetDetection();
+AnnotatedUrl::AnnotatedUrl(QObject *parent)
+ : QObject(parent),
+ manager(new QNearFieldManager(this))
+{
connect(manager, &QNearFieldManager::targetDetected,
this, &AnnotatedUrl::targetDetected);
connect(manager, &QNearFieldManager::targetLost,
this, &AnnotatedUrl::targetLost);
+ connect(manager, &QNearFieldManager::adapterStateChanged,
+ this, &AnnotatedUrl::handleAdapterStateChange);
+
+//! [populateFilter]
+ messageFilter.setOrderMatch(false);
+ messageFilter.appendRecord<QNdefNfcTextRecord>(1, 100);
+ messageFilter.appendRecord<QNdefNfcUriRecord>(1, 1);
+ messageFilter.appendRecord(QNdefRecord::Mime, "", 0, 1);
+//! [populateFilter]
}
AnnotatedUrl::~AnnotatedUrl()
@@ -100,6 +43,18 @@ AnnotatedUrl::~AnnotatedUrl()
}
+void AnnotatedUrl::startDetection()
+{
+ if (!manager->isEnabled()) {
+ qWarning() << "NFC not enabled";
+ emit nfcStateChanged(false);
+ return;
+ }
+
+ if (manager->startTargetDetection(QNearFieldTarget::NdefAccess))
+ emit nfcStateChanged(true);
+}
+
void AnnotatedUrl::targetDetected(QNearFieldTarget *target)
{
if (!target)
@@ -107,6 +62,8 @@ void AnnotatedUrl::targetDetected(QNearFieldTarget *target)
connect(target, &QNearFieldTarget::ndefMessageRead,
this, &AnnotatedUrl::handlePolledNdefMessage);
+ connect(target, &QNearFieldTarget::error, this,
+ [this]() { emit tagError("Tag read error"); });
target->readNdefMessages();
}
@@ -122,12 +79,31 @@ void AnnotatedUrl::handlePolledNdefMessage(QNdefMessage message)
handleMessage(message, target);
}
+//! [handleAdapterState]
+void AnnotatedUrl::handleAdapterStateChange(QNearFieldManager::AdapterState state)
+{
+ if (state == QNearFieldManager::AdapterState::Online) {
+ startDetection();
+ } else if (state == QNearFieldManager::AdapterState::Offline) {
+ manager->stopTargetDetection();
+ emit nfcStateChanged(false);
+ }
+}
+//! [handleAdapterState]
+
//! [handleMessage 1]
void AnnotatedUrl::handleMessage(const QNdefMessage &message, QNearFieldTarget *target)
{
//! [handleMessage 1]
Q_UNUSED(target);
+//! [handleMessage 2]
+ if (!messageFilter.match(message)) {
+ emit tagError("Invalid message format");
+ return;
+ }
+//! [handleMessage 2]
+
enum {
MatchedNone,
MatchedFirst,
@@ -142,14 +118,14 @@ void AnnotatedUrl::handleMessage(const QNdefMessage &message, QNearFieldTarget *
QUrl url;
QPixmap pixmap;
-//! [handleMessage 2]
+//! [handleMessage 3]
for (const QNdefRecord &record : message) {
if (record.isRecordType<QNdefNfcTextRecord>()) {
QNdefNfcTextRecord textRecord(record);
title = textRecord.text();
QLocale locale(textRecord.locale());
-//! [handleMessage 2]
+//! [handleMessage 3]
// already found best match
if (bestMatch == MatchedLanguageAndCountry) {
// do nothing
@@ -163,7 +139,7 @@ void AnnotatedUrl::handleMessage(const QNdefMessage &message, QNearFieldTarget *
} else if (bestMatch == MatchedNone) {
bestMatch = MatchedFirst;
}
-//! [handleMessage 3]
+//! [handleMessage 4]
} else if (record.isRecordType<QNdefNfcUriRecord>()) {
QNdefNfcUriRecord uriRecord(record);
@@ -172,10 +148,10 @@ void AnnotatedUrl::handleMessage(const QNdefMessage &message, QNearFieldTarget *
record.type().startsWith("image/")) {
pixmap = QPixmap::fromImage(QImage::fromData(record.payload()));
}
-//! [handleMessage 3]
//! [handleMessage 4]
+//! [handleMessage 5]
}
emit annotatedUrl(url, title, pixmap);
}
-//! [handleMessage 4]
+//! [handleMessage 5]
diff --git a/examples/nfc/annotatedurl/annotatedurl.h b/examples/nfc/annotatedurl/annotatedurl.h
index 204bed5f..95404e55 100644
--- a/examples/nfc/annotatedurl/annotatedurl.h
+++ b/examples/nfc/annotatedurl/annotatedurl.h
@@ -1,64 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module.
-**
-** $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) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef ANNOTATEDURL_H
#define ANNOTATEDURL_H
-#include <QtNfc/QNdefMessage>
+#include <QNdefFilter>
+#include <QNdefMessage>
+#include <QNearFieldManager>
-#include <QtCore/QObject>
+#include <QObject>
-QT_FORWARD_DECLARE_CLASS(QUrl)
-QT_FORWARD_DECLARE_CLASS(QPixmap)
-QT_FORWARD_DECLARE_CLASS(QNearFieldManager)
QT_FORWARD_DECLARE_CLASS(QNearFieldTarget)
+QT_FORWARD_DECLARE_CLASS(QPixmap)
+QT_FORWARD_DECLARE_CLASS(QUrl)
//! [0]
class AnnotatedUrl : public QObject
@@ -69,16 +23,23 @@ public:
explicit AnnotatedUrl(QObject *parent = 0);
~AnnotatedUrl();
+ void startDetection();
+
signals:
void annotatedUrl(const QUrl &url, const QString &title, const QPixmap &pixmap);
+ void nfcStateChanged(bool enabled);
+ void tagError(const QString &error);
public slots:
void targetDetected(QNearFieldTarget *target);
void targetLost(QNearFieldTarget *target);
void handleMessage(const QNdefMessage &message, QNearFieldTarget *target);
void handlePolledNdefMessage(QNdefMessage message);
+ void handleAdapterStateChange(QNearFieldManager::AdapterState state);
+
private:
QNearFieldManager *manager;
+ QNdefFilter messageFilter;
};
//! [0]
diff --git a/examples/nfc/annotatedurl/annotatedurl.pro b/examples/nfc/annotatedurl/annotatedurl.pro
index e2bb7c06..a9ecf769 100644
--- a/examples/nfc/annotatedurl/annotatedurl.pro
+++ b/examples/nfc/annotatedurl/annotatedurl.pro
@@ -11,7 +11,14 @@ SOURCES += main.cpp \
HEADERS += mainwindow.h \
annotatedurl.h
-FORMS += mainwindow.ui
+ios: QMAKE_INFO_PLIST = Info.plist
+
+android {
+ ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
+
+ DISTFILES += \
+ android/AndroidManifest.xml
+}
target.path = $$[QT_INSTALL_EXAMPLES]/nfc/annotatedurl
INSTALLS += target
diff --git a/examples/nfc/annotatedurl/doc/images/annotatedurl.png b/examples/nfc/annotatedurl/doc/images/annotatedurl.png
index 01130ecd..39f2c66e 100644
--- a/examples/nfc/annotatedurl/doc/images/annotatedurl.png
+++ b/examples/nfc/annotatedurl/doc/images/annotatedurl.png
Binary files differ
diff --git a/examples/nfc/annotatedurl/doc/images/annotatedurl2.png b/examples/nfc/annotatedurl/doc/images/annotatedurl2.png
index 2ea6f12f..bb6208e9 100644
--- a/examples/nfc/annotatedurl/doc/images/annotatedurl2.png
+++ b/examples/nfc/annotatedurl/doc/images/annotatedurl2.png
Binary files differ
diff --git a/examples/nfc/annotatedurl/doc/images/annotatedurl3.png b/examples/nfc/annotatedurl/doc/images/annotatedurl3.png
new file mode 100644
index 00000000..363b7687
--- /dev/null
+++ b/examples/nfc/annotatedurl/doc/images/annotatedurl3.png
Binary files differ
diff --git a/examples/nfc/annotatedurl/doc/src/annotatedurl.qdoc b/examples/nfc/annotatedurl/doc/src/annotatedurl.qdoc
index 7fda040f..b76c349f 100644
--- a/examples/nfc/annotatedurl/doc/src/annotatedurl.qdoc
+++ b/examples/nfc/annotatedurl/doc/src/annotatedurl.qdoc
@@ -1,36 +1,14 @@
-/****************************************************************************
-**
-** 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) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example annotatedurl
-\title Annotated URL Example
-\brief An example showing reading from formatted NFC Data Exchange Format (NDEF) messages.
+\title Annotated URL
+\examplecategory {Connectivity}
+\meta tags {nfc, ndef, widgets}
+\brief Reads formatted NFC Data Exchange Format (NDEF) messages.
-The Annotated URL example displays the contents of specifically
+The Annotated URL example uses \l{Qt NFC} to display the contents of specifically
formatted NFC Data Exchange Format (NDEF) messages read from an NFC
Tag. The NDEF message should contain a URI record, an optional \c
image/* MIME record, and one or more localized Text records.
@@ -38,44 +16,115 @@ image/* MIME record, and one or more localized Text records.
This is the initial state of the example:
\image annotatedurl.png
-In this example the NFC Tag used contains a text record. The UI
-gets updated accordingly to:
+If a tag is touched, its NDEF content will be shown. Here is the UI
+for a tag that contains a text record and URI record:
\image annotatedurl2.png
+When the screen is tapped, the URL will be opened in the browser.
+
\section1 AnnotatedUrl Class Definition
-The \c AnnotatedUrl class wraps the \c QNearFieldManager, the class
-providing the NFC Tag detection functionality. NDEF messages are read
-by the QNearFieldManager and forwarded to a handler contained in the
+The \c AnnotatedUrl class wraps \l QNearFieldManager, the class providing
+the NFC Tag detection functionality. NDEF messages are read by
+\l QNearFieldManager and forwarded to a handler contained in the
\c AnnotatedUrl class. After parsing the NDEF message the class emits
-the signal AnnotatedUrl::annotatedUrl(const QUrl &url, const QString
-&title, const QPixmap &pixmap). The UI reacts to the signal displaying
+the \c annotatedUrl() signal. The UI reacts to the signal displaying
the contents of the NDEF message.
\snippet annotatedurl/annotatedurl.h 0
+\note The \c startDetection() method is used to defer the actual tag detection
+until all the connections between the UI and NFC-related logic are established.
+This is important when the application is automatically started once an NFC tag
+is touched. Such usecase is currently supported on Android.
+
+\snippet annotatedurl/main.cpp 0
+
+\section1 Message Filtering
+
+As it is mentioned above, the application supports the NDEF messages of a
+specific format. A correct message should contain the following fields:
+
+\list
+ \li \e {At least one} NDEF Text record, which will be used as a header.
+ \li \e {Exactly one} NDEF URI record.
+ \li \e {An optional} MIME record with an icon.
+\endlist
+
+The order of the records is not strictly specified.
+
+An instance of \l QNdefFilter is used to validate the NDEF message. The filter
+is populated as follows:
+
+\snippet annotatedurl/annotatedurl.cpp populateFilter
+
+If the incoming message does not match the filter, an error message is shown:
+
+\image annotatedurl3.png
+
+\note The \l {ndefeditor}{NDEF Editor} example application can be used to create
+the tags with correct or incorrect message structure.
+
\section1 AnnotatedUrl Handler Implementation
-NFC messages read by the \c QNearFieldManager are forwarded to
-AnnotatedUrl::handleMessage. The callback signature details can be
-read in \l{QNearFieldManager::registerNdefMessageHandler}.
+NFC messages read by the \l QNearFieldManager are forwarded to
+\c {AnnotatedUrl::handleMessage}.
\snippet annotatedurl/annotatedurl.cpp handleMessage 1
+At first the messages are validated using the \l QNdefFilter::match() method:
+
+\snippet annotatedurl/annotatedurl.cpp handleMessage 2
+
+If the messages have the correct format, the parsing continues.
+
Because NFC messages are composed of several NDEF records, looping
through all of the records allows the extraction of the 3 parameters
to be displayed in the UI: the Uri, the Title and the Pixmap:
-
-\snippet annotatedurl/annotatedurl.cpp handleMessage 2
\snippet annotatedurl/annotatedurl.cpp handleMessage 3
+\snippet annotatedurl/annotatedurl.cpp handleMessage 4
Finally after having extracted the parameters of the NFC message the
corresponding signal is emitted so that the UI can handle it.
-\snippet annotatedurl/annotatedurl.cpp handleMessage 4
+\snippet annotatedurl/annotatedurl.cpp handleMessage 5
+
+\section1 Adapter State Handling
+
+On Android the adapter state changes can be detected by connecting to the
+\l QNearFieldManager::adapterStateChanged() signal. This allows stopping the
+detection when the NFC adapter is disabled, and restarting it when the adapter
+is enabled again. This approach is implemented in the
+\c {AnnotatedUrl::handleAdapterStateChange} slot.
+
+\snippet annotatedurl/annotatedurl.cpp handleAdapterState
+
+\section1 Automatic Application Startup
+
+Android supports automatic application startup when the NDEF tag is touched.
+See \l {Qt NFC on Android} for the required changes to the Android manifest
+file.
+
+Introduction of a custom AndroidManifest.xml requires special steps on the
+build system side.
+
+\section2 Building with qmake
+
+When using qmake, the following needs to be added to the \c {.pro} file:
+
+\quotefromfile annotatedurl/annotatedurl.pro
+\skipto android {
+\printuntil }
+
+\section2 Building with CMake
+
+When using CMake, the following needs to be added to the \c CMakeLists.txt:
+\quotefromfile annotatedurl/CMakeLists.txt
+\skipto if(ANDROID)
+\printuntil endif()
\include examples-run.qdocinc
diff --git a/examples/nfc/annotatedurl/main.cpp b/examples/nfc/annotatedurl/main.cpp
index 9ce6c1b9..352a959b 100644
--- a/examples/nfc/annotatedurl/main.cpp
+++ b/examples/nfc/annotatedurl/main.cpp
@@ -1,73 +1,32 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module.
-**
-** $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 "annotatedurl.h"
#include "mainwindow.h"
-#include <QtNfc/qnearfieldmanager.h>
-#include <QtNfc/qndefnfctextrecord.h>
-#include <QtNfc/qndefnfcurirecord.h>
+#include <QNearFieldManager>
+#include <QNdefNfcTextRecord>
+#include <QNdefNfcUriRecord>
-#include <QtWidgets/QApplication>
+#include <QApplication>
+//! [0]
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow mainWindow;
-
AnnotatedUrl annotatedUrl;
QObject::connect(&annotatedUrl, &AnnotatedUrl::annotatedUrl,
&mainWindow, &MainWindow::displayAnnotatedUrl);
+ QObject::connect(&annotatedUrl, &AnnotatedUrl::nfcStateChanged,
+ &mainWindow, &MainWindow::nfcStateChanged);
+ QObject::connect(&annotatedUrl, &AnnotatedUrl::tagError,
+ &mainWindow, &MainWindow::showTagError);
+ annotatedUrl.startDetection();
mainWindow.show();
return a.exec();
}
+//! [0]
diff --git a/examples/nfc/annotatedurl/mainwindow.cpp b/examples/nfc/annotatedurl/mainwindow.cpp
index 707c03eb..7b418360 100644
--- a/examples/nfc/annotatedurl/mainwindow.cpp
+++ b/examples/nfc/annotatedurl/mainwindow.cpp
@@ -1,82 +1,117 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module.
-**
-** $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) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "mainwindow.h"
-#include "ui_mainwindow.h"
-#include <QtGui/QDesktopServices>
-#include <QtGui/QMouseEvent>
-#include <QtCore/QUrl>
+#include <QUrl>
+
+#include <QDesktopServices>
+#include <QScreen>
+
+#include <QLabel>
+#include <QLayout>
MainWindow::MainWindow(QWidget *parent)
-: QMainWindow(parent), ui(new Ui::MainWindow)
+ : QWidget(parent),
+ m_titleLabel(new QLabel(this)),
+ m_infoLabel(new QLabel(tr("Enable NFC"), this)),
+ m_uriLabel(new QLabel(this)),
+ m_landscapeIconLabel(new QLabel(this)),
+ m_portraitIconLabel(new QLabel(this))
{
- ui->setupUi(this);
+ m_titleLabel->setAlignment(Qt::AlignCenter);
+ m_infoLabel->setAlignment(Qt::AlignCenter);
+ m_uriLabel->setAlignment(Qt::AlignCenter);
+ m_landscapeIconLabel->setAlignment(Qt::AlignCenter);
+ m_portraitIconLabel->setAlignment(Qt::AlignCenter);
+
+ QFont f = m_titleLabel->font();
+ f.setBold(true);
+ m_titleLabel->setFont(f);
+
+ QVBoxLayout *verticalLayout = new QVBoxLayout;
+ verticalLayout->addWidget(m_titleLabel);
+ verticalLayout->addWidget(m_infoLabel);
+ verticalLayout->addWidget(m_portraitIconLabel);
+ verticalLayout->addWidget(m_uriLabel);
+
+ QHBoxLayout *horizontalLayout = new QHBoxLayout;
+ horizontalLayout->addWidget(m_landscapeIconLabel);
+ horizontalLayout->addLayout(verticalLayout);
+ horizontalLayout->setSpacing(0);
+
+ setLayout(horizontalLayout);
+
+ handleScreenChange();
}
MainWindow::~MainWindow()
{
- delete ui;
}
void MainWindow::displayAnnotatedUrl(const QUrl &url, const QString &title, const QPixmap &pixmap)
{
- ui->m_help->setHidden(true);
+ m_infoLabel->setHidden(true);
+
+ m_uriLabel->setText(url.toString());
+ m_titleLabel->setText(title);
+
+ m_pixmap = pixmap;
+ updateWidgetLayout(m_screen->orientation());
+}
+
+void MainWindow::nfcStateChanged(bool enabled)
+{
+ const QString text = enabled ? "Touch a tag" : "Enable NFC";
+ m_infoLabel->setText(text);
+}
+
+void MainWindow::showTagError(const QString &message)
+{
+ m_uriLabel->clear();
+ m_titleLabel->clear();
+ m_pixmap = QPixmap();
+ m_landscapeIconLabel->setVisible(false);
+ m_portraitIconLabel->setVisible(false);
- ui->m_url->setText(url.toString());
- ui->m_title->setText(title);
- ui->m_image->setPixmap(pixmap);
+ m_infoLabel->setHidden(false);
+ m_infoLabel->setText(message);
}
-void MainWindow::mouseReleaseEvent(QMouseEvent *event)
+void MainWindow::mouseReleaseEvent(QMouseEvent * /*event*/)
{
- if (ui->centralWidget->rect().contains(event->pos()))
- QDesktopServices::openUrl(QUrl(ui->m_url->text()));
+ QDesktopServices::openUrl(QUrl(m_uriLabel->text()));
+}
+
+void MainWindow::moveEvent(QMoveEvent * /*event*/)
+{
+ if (screen() != m_screen)
+ handleScreenChange();
+}
+
+void MainWindow::updateWidgetLayout(Qt::ScreenOrientation orientation)
+{
+ m_landscapeIconLabel->setVisible(false);
+ m_portraitIconLabel->setVisible(false);
+ if (!m_pixmap.isNull()) {
+ const bool landscapeMode = (orientation == Qt::LandscapeOrientation)
+ || (orientation == Qt::InvertedLandscapeOrientation);
+ QLabel *imageLabel = landscapeMode ? m_landscapeIconLabel : m_portraitIconLabel;
+ imageLabel->setVisible(true);
+ if (m_pixmap.width() > imageLabel->width() || m_pixmap.height() > imageLabel->height())
+ imageLabel->setPixmap(m_pixmap.scaled(imageLabel->size(), Qt::KeepAspectRatio));
+ else
+ imageLabel->setPixmap(m_pixmap);
+ }
+}
+
+void MainWindow::handleScreenChange()
+{
+ if (m_screen)
+ disconnect(m_screen, &QScreen::orientationChanged, this, &MainWindow::updateWidgetLayout);
+
+ m_screen = screen();
+ connect(m_screen, &QScreen::orientationChanged, this, &MainWindow::updateWidgetLayout);
+
+ updateWidgetLayout(m_screen->orientation());
}
diff --git a/examples/nfc/annotatedurl/mainwindow.h b/examples/nfc/annotatedurl/mainwindow.h
index 9cfb6e7f..059c7038 100644
--- a/examples/nfc/annotatedurl/mainwindow.h
+++ b/examples/nfc/annotatedurl/mainwindow.h
@@ -1,71 +1,20 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module.
-**
-** $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) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
-#include <QtWidgets/QMainWindow>
+#include <QPixmap>
+
+#include <QWidget>
QT_FORWARD_DECLARE_CLASS(QMouseEvent)
QT_FORWARD_DECLARE_CLASS(QUrl)
-QT_FORWARD_DECLARE_CLASS(QPixmap)
QT_FORWARD_DECLARE_CLASS(QString)
-QT_FORWARD_DECLARE_CLASS(QWidget)
-
-QT_BEGIN_NAMESPACE
-namespace Ui {
- class MainWindow;
-}
-QT_END_NAMESPACE
+QT_FORWARD_DECLARE_CLASS(QLabel)
+QT_FORWARD_DECLARE_CLASS(QScreen)
-class MainWindow : public QMainWindow
+class MainWindow : public QWidget
{
Q_OBJECT
@@ -75,12 +24,26 @@ public:
public slots:
void displayAnnotatedUrl(const QUrl &url, const QString &title, const QPixmap &pixmap);
+ void nfcStateChanged(bool enabled);
+ void showTagError(const QString &message);
protected:
- void mouseReleaseEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void moveEvent(QMoveEvent *event) override;
+
+private slots:
+ void updateWidgetLayout(Qt::ScreenOrientation orientation);
private:
- Ui::MainWindow *ui;
+ void handleScreenChange();
+
+ QLabel *m_titleLabel;
+ QLabel *m_infoLabel;
+ QLabel *m_uriLabel;
+ QLabel *m_landscapeIconLabel;
+ QLabel *m_portraitIconLabel;
+ QScreen *m_screen = nullptr;
+ QPixmap m_pixmap;
};
#endif // MAINWINDOW_H
diff --git a/examples/nfc/annotatedurl/mainwindow.ui b/examples/nfc/annotatedurl/mainwindow.ui
deleted file mode 100644
index 26e3b302..00000000
--- a/examples/nfc/annotatedurl/mainwindow.ui
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>590</width>
- <height>420</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>MainWindow</string>
- </property>
- <widget class="QWidget" name="centralWidget">
- <layout class="QGridLayout" name="gridLayout" rowstretch="1,0,1" columnstretch="0,0,0">
- <item row="0" column="1" colspan="2">
- <widget class="QLabel" name="m_title">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="0" column="0" rowspan="3">
- <widget class="QLabel" name="m_image">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="m_help">
- <property name="text">
- <string>Touch a tag</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- <item row="2" column="1" colspan="2">
- <widget class="QLabel" name="m_url">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </widget>
- <layoutdefault spacing="6" margin="11"/>
- <resources/>
- <connections/>
-</ui>
diff --git a/examples/nfc/corkboard/Mode.qml b/examples/nfc/corkboard/Mode.qml
deleted file mode 100644
index 0d427cf5..00000000
--- a/examples/nfc/corkboard/Mode.qml
+++ /dev/null
@@ -1,159 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtNfc module.
-**
-** $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 QtQuick 2.4
-
-Item {
- id: page
- width: ListView.view.width;
- height: ListView.view.height
-
- Image {
- source: "qrc:/cork.jpg"
- anchors.centerIn: parent
- width: parent.width - 20
- height: parent.height - 20
- fillMode: Image.PreserveAspectCrop
-
- Text {
- anchors { horizontalCenter: parent.horizontalCenter; top: parent.top; topMargin: 10}
- text: name;
- font { pixelSize: 30; bold: true }
- color: "white"
- style: Text.Outline; styleColor: "black"
- }
-
- Repeater {
- model: notes
- Item {
- id: stickyPage
-
- x: ListView.width * (0.7 * Math.random() + 0.1)
- y: ListView.height * (0.7 * Math.random() + 0.1)
-
- rotation: -listView.horizontalVelocity / 200;
- Behavior on rotation {
- SpringAnimation { spring: 2.0; damping: 0.15 }
- }
-
- Item {
- id: sticky
- scale: mouse.pressed ? 1 : 0.7
- rotation: mouse.pressed ? 8 : 0
- Behavior on rotation{
- NumberAnimation {duration: 200 }
- }
- Behavior on scale{
- NumberAnimation { duration: 200 }
- }
-
- Image {
- id: stickyImage
- x: 8 + -width * 0.6 / 2; y: -20
- source: "qrc:/note-yellow.png"
- scale: 0.6; transformOrigin: Item.TopLeft
- smooth: true
- }
-
- TextEdit {
- id: myText
- text: noteText
- x: -104; y: 36; width: 215; height: 200
- smooth: true
- font.pixelSize: 24
- readOnly: false
- rotation: -8
- wrapMode: TextEdit.Wrap
- }
-
- Item {
- id: interactionItem
- x: stickyImage.x; y: -20
- width: stickyImage.width * stickyImage.scale
- height: stickyImage.height * stickyImage.scale
-
- MouseArea {
- id: mouse
- anchors.fill: parent
- drag.target: stickyPage
- drag.axis: Drag.XandYAxis
- }
- Image {
- id: writeButton
- source: "qrc:/NfcFlag.png"
- rotation: -8 // Note image itself is rotated
- anchors { bottom: parent.bottom; right:parent.right }
- scale: flagMouse.pressed ? 1.3 : 1
- MouseArea {
- id: flagMouse
- anchors.fill: parent
- }
- }
- }
- }
-
- Image {
- x: -width / 2; y: -height * 0.5 / 2
- source: "qrc:/tack.png"
- scale: 0.7; transformOrigin: Item.TopLeft
- }
- }
- }
- }
-}
-
-
-
-
-
-
-
-
diff --git a/examples/nfc/corkboard/NfcFlag.png b/examples/nfc/corkboard/NfcFlag.png
deleted file mode 100644
index 6d2b9f89..00000000
--- a/examples/nfc/corkboard/NfcFlag.png
+++ /dev/null
Binary files differ
diff --git a/examples/nfc/corkboard/android/AndroidManifest.xml b/examples/nfc/corkboard/android/AndroidManifest.xml
deleted file mode 100644
index 3aec51ae..00000000
--- a/examples/nfc/corkboard/android/AndroidManifest.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<manifest package="org.qtproject.example" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto" android:extractNativeLibs="true">
- <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --">
- <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation"
- android:name="org.qtproject.qt5.android.bindings.QtActivity"
- android:label="-- %%INSERT_APP_NAME%% --"
- android:screenOrientation="unspecified"
- android:launchMode="singleTop">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- <intent-filter>
- <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <data android:mimeType="text/plain"/>
- </intent-filter>
-
- <!-- Application arguments -->
- <!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
- <!-- Application arguments -->
-
- <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
- <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
- <meta-data android:name="android.app.repository" android:value="default"/>
- <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
- <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
- <!-- Deploy Qt libs as part of package -->
- <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
- <!-- Run with local libs -->
- <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
- <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
- <meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/>
- <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
- <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
- <!-- Messages maps -->
- <meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
- <meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
- <meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
- <!-- Messages maps -->
-
- <!-- Splash screen -->
- <!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
- <!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
- <!-- Splash screen -->
-
- <!-- Background running -->
- <!-- Warning: changing this value to true may cause unexpected crashes if the
- application still try to draw after
- "applicationStateChanged(Qt::ApplicationSuspended)"
- signal is sent! -->
- <meta-data android:name="android.app.background_running" android:value="false"/>
- <!-- Background running -->
-
- <!-- auto screen scale factor -->
- <meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
- <!-- auto screen scale factor -->
-
- <!-- extract android style -->
- <!-- available android:values :
- * full - useful QWidget & Quick Controls 1 apps
- * minimal - useful for Quick Controls 2 apps, it is much faster than "full"
- * none - useful for apps that don't use any of the above Qt modules
- -->
- <meta-data android:name="android.app.extract_android_style" android:value="full"/>
- <!-- extract android style -->
- </activity>
-
- <!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
-
- </application>
-
- <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21"/>
- <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
-
- <!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
- Remove the comment if you do not require these default permissions. -->
- <!-- %%INSERT_PERMISSIONS -->
-
- <!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
- Remove the comment if you do not require these default features. -->
- <!-- %%INSERT_FEATURES -->
-
-</manifest>
diff --git a/examples/nfc/corkboard/cork.jpg b/examples/nfc/corkboard/cork.jpg
deleted file mode 100644
index 160bc002..00000000
--- a/examples/nfc/corkboard/cork.jpg
+++ /dev/null
Binary files differ
diff --git a/examples/nfc/corkboard/corkboard.pro b/examples/nfc/corkboard/corkboard.pro
deleted file mode 100644
index 858ac65d..00000000
--- a/examples/nfc/corkboard/corkboard.pro
+++ /dev/null
@@ -1,24 +0,0 @@
-QT += quick nfc
-
-SOURCES += \
- main.cpp
-
-TARGET = qml_corkboard
-TEMPLATE = app
-
-RESOURCES += \
- corkboard.qrc
-
-OTHER_FILES += \
- corkboards.qml \
- Mode.qml
-
-!android-embedded {
-ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
-}
-
-target.path = $$[QT_INSTALL_EXAMPLES]/nfc/corkboard
-INSTALLS += target
-
-EXAMPLE_FILES += \
- icon.png
diff --git a/examples/nfc/corkboard/corkboard.qrc b/examples/nfc/corkboard/corkboard.qrc
deleted file mode 100644
index 10d80ce3..00000000
--- a/examples/nfc/corkboard/corkboard.qrc
+++ /dev/null
@@ -1,10 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>corkboards.qml</file>
- <file>NfcFlag.png</file>
- <file>tack.png</file>
- <file>note-yellow.png</file>
- <file>cork.jpg</file>
- <file>Mode.qml</file>
- </qresource>
-</RCC>
diff --git a/examples/nfc/corkboard/corkboards.qml b/examples/nfc/corkboard/corkboards.qml
deleted file mode 100644
index 92cb6616..00000000
--- a/examples/nfc/corkboard/corkboards.qml
+++ /dev/null
@@ -1,128 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtNfc module.
-**
-** $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 QtQuick 2.3
-import QtNfc 5.5
-
-Rectangle {
- width: 800; height: 480
- color: "darkred"
-
- NearField {
- property bool requiresManualPolling: false
- orderMatch: false
-
- onMessageRecordsChanged: {
- var i;
- for (i = 0; i < messageRecords.length; ++i) {
- var data = "";
- if (messageRecords[i].typeNameFormat === NdefRecord.NfcRtd) {
- if (messageRecords[i].type === "T") {
- data = messageRecords[i].text;
- } else if (messageRecords[i].type === "U") {
- data = messageRecords[i].uri;
- }
- }
- if (!data)
- data = "Unknown content";
-
- list.get(listView.currentIndex).notes.append( {
- "noteText":data
- })
- }
- }
-
- onPollingChanged: {
- if (!polling && requiresManualPolling)
- polling = true; //restart polling
- }
-
- Component.onCompleted: {
- // Polling should be true if
- // QNearFieldManager::registerNdefMessageHandler() was successful;
- // otherwise the platform requires manual polling mode.
- if (!polling) {
- requiresManualPolling = true;
- polling = true;
- }
- }
- }
-
- ListModel {
- id: list
-
- ListElement {
- name: "Personal"
- notes: [
- ListElement { noteText: "Near Field Communication" },
- ListElement { noteText: "Touch a tag and its contents will appear as a new note" }
- ]
- }
-
- ListElement {
- name: "Work"
- notes: [
- ListElement { noteText: "https://www.qt.io" },
- ListElement { noteText: "To write a tag, click the red flag of a note and then touch a tag" }
- ]
- }
- }
-
- ListView {
- id: listView
- anchors.fill: parent
- orientation: ListView.Horizontal
- snapMode: ListView.SnapOneItem
- model: list
- highlightRangeMode: ListView.StrictlyEnforceRange
- delegate: Mode {}
- }
-}
diff --git a/examples/nfc/corkboard/doc/images/corkboard.png b/examples/nfc/corkboard/doc/images/corkboard.png
deleted file mode 100644
index 3f54ea18..00000000
--- a/examples/nfc/corkboard/doc/images/corkboard.png
+++ /dev/null
Binary files differ
diff --git a/examples/nfc/corkboard/doc/src/corkboard.qdoc b/examples/nfc/corkboard/doc/src/corkboard.qdoc
deleted file mode 100644
index ac21187b..00000000
--- a/examples/nfc/corkboard/doc/src/corkboard.qdoc
+++ /dev/null
@@ -1,137 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtNfc module.
-**
-** $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$
-**
-****************************************************************************/
-
-/*!
-\example corkboard
-\title QML CorkBoard Example
-\brief A QML example about displaying NFC Data Exchange Format (NDEF) messages.
-
-The QML corkboard example displays the contents of NDEF messages read
-from an NFC Tag. Each newly detected NDEF message is added to the
-corkboard and can be dragged into an arbitrary position on the
-board. The corkboard has a \e Personal and \e Work space. The
-workspace can be changed by sliding left or right.
-
-
-\image corkboard.png
-
-\section1 Implementation details
-In the corkboard example, we use the following .qml files:
- \list
- \li corkboards.qml
- \li Mode.qml
- \endlist
-
-The main.cpp holds the application logic to load the main view stored
-in the corkboards.qml file.
-
-\snippet corkboard/main.cpp 0
-
-\section1 corkboards.qml details
-There are two basic QML components in this file:
- \list
- \li NearField
- \li ListView
- \endlist
-
-The first time the NearField QML type is instantiated, the
-Component.onCompleted handler will start the NFC polling process. The
-\l [Qml] {NearField} {onMessageRecordsChanged} handler parses NFC
-Messages that are detected by the NearField component and builds up a
-data model that is passed into the ListView. Additionally, every time the
-NearField manager stops the polling process, the onPollingChanged
-handler restarts it.
-
-\quotefromfile corkboard/corkboards.qml
-\skipto NearField
-\printuntil onMessageRecordsChanged
-\dots 8
-\skipuntil }
-\skipto onPollingChanged
-\printuntil onPollingChanged
-\dots 8
-\skipuntil }
-\skipto Component
-\printuntil Component
-\dots 8
-\skipuntil }
-\printline }
-\skipto ListModel
-\printto ListModel
-
-The ListView component takes a ListModel as parameter (built from the
-NFC records). The view of each of the items of the model is defined by
-the Mode component (its implementation details can be found in the
-file Mode.qml). The data model consists of a list of corkboards. Each
-corkboard can display multiple NFC text message records.
-
-\quotefromfile corkboard/corkboards.qml
-\skipto ListView
-\printuntil id
-\dots 8
-\skipto model
-\printuntil model
-\dots 8
-\skipto delegate
-\printuntil delegate
-\skipto }
-\printline }
-
-\section1 Mode.qml details
-
-A corkboard title is displayed for each of the items that form part
-of the data model:
-
-\quotefromfile corkboard/Mode.qml
-\skipto Text
-\printuntil }
-\printuntil }
-
-Every text record that was read from an NFC message, is represented by
-a sticky note with its own position on the display. Initially the
-position is set randomly. The text on the sticky note is set on a
-TextField.
-
-\quotefromfile corkboard/Mode.qml
-\skipto Repeater
-\printuntil y:
-\skipto Item
-\dots 16
-\printuntil sticky
-\dots 20
-\skipto TextEdit
-\printuntil noteText
-\dots 24
-\skipto }
-\printuntil }
-\dots 20
-
-\include examples-run.qdocinc
-
-\sa {Qt NFC}
-
-*/
diff --git a/examples/nfc/corkboard/icon.png b/examples/nfc/corkboard/icon.png
deleted file mode 100644
index b115f836..00000000
--- a/examples/nfc/corkboard/icon.png
+++ /dev/null
Binary files differ
diff --git a/examples/nfc/corkboard/main.cpp b/examples/nfc/corkboard/main.cpp
deleted file mode 100644
index 74fad72f..00000000
--- a/examples/nfc/corkboard/main.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the QtNfc module.
-**
-** $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$
-**
-****************************************************************************/
-
-#include <QtGui/QGuiApplication>
-#include <QtQml/QQmlEngine>
-#include <QtQuick/QQuickView>
-
-//! [0]
-int main(int argc, char *argv[])
-{
- QGuiApplication application(argc, argv);
- QQuickView view;
- view.setSource(QUrl("qrc:/corkboards.qml"));
- view.setResizeMode(QQuickView::SizeRootObjectToView);
- view.show();
- return application.exec();
-}
-//! [0]
diff --git a/examples/nfc/corkboard/note-yellow.png b/examples/nfc/corkboard/note-yellow.png
deleted file mode 100644
index 3195952a..00000000
--- a/examples/nfc/corkboard/note-yellow.png
+++ /dev/null
Binary files differ
diff --git a/examples/nfc/corkboard/tack.png b/examples/nfc/corkboard/tack.png
deleted file mode 100644
index cef2d1cd..00000000
--- a/examples/nfc/corkboard/tack.png
+++ /dev/null
Binary files differ
diff --git a/examples/nfc/ndefeditor/CMakeLists.txt b/examples/nfc/ndefeditor/CMakeLists.txt
new file mode 100644
index 00000000..2e295c20
--- /dev/null
+++ b/examples/nfc/ndefeditor/CMakeLists.txt
@@ -0,0 +1,69 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(ndefeditor LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/nfc/ndefeditor")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Nfc Quick QuickControls2)
+
+qt_standard_project_setup(REQUIRES 6.5)
+
+qt_add_executable(ndefeditor
+ main.cpp
+)
+
+set(icon_files)
+foreach(icon IN ITEMS add arrow_back file_download file_upload link text_snippet)
+ foreach(scale IN ITEMS "" "@2" "@3" "@4")
+ list(APPEND icon_files "icons/ndefeditor/20x20${scale}/${icon}.png")
+ endforeach()
+endforeach()
+
+qt_add_resources(ndefeditor "theme" FILES
+ ${icon_files}
+ icons/ndefeditor/index.theme
+)
+
+qt_add_qml_module(ndefeditor
+ URI NdefEditor
+ VERSION 1.0
+ QML_FILES
+ Main.qml
+ MainWindow.qml
+ NdefRecordDelegate.qml
+ SOURCES
+ nfcmanager.h nfcmanager.cpp
+ nfctarget.h nfctarget.cpp
+ ndefmessagemodel.h ndefmessagemodel.cpp
+)
+
+set_target_properties(ndefeditor PROPERTIES
+ MACOSX_BUNDLE TRUE
+ WIN32_EXECUTABLE TRUE
+)
+
+if(IOS)
+ set_target_properties(ndefeditor PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.cmake.plist"
+ )
+endif()
+
+target_link_libraries(ndefeditor PRIVATE
+ Qt6::Core
+ Qt6::Nfc
+ Qt6::Quick
+)
+
+install(TARGETS ndefeditor
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/nfc/ndefeditor/Info.cmake.plist b/examples/nfc/ndefeditor/Info.cmake.plist
new file mode 100644
index 00000000..ee87b3b2
--- /dev/null
+++ b/examples/nfc/ndefeditor/Info.cmake.plist
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+
+ <key>CFBundleDisplayName</key>
+ <string>NDEF Editor</string>
+
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleAllowMixedLocalizations</key>
+ <true/>
+
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+
+ <key>NFCReaderUsageDescription</key>
+ <string>Qt's ndefeditor wants to access your NFC hardware</string>
+
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
diff --git a/examples/nfc/ndefeditor/Info.qmake.plist b/examples/nfc/ndefeditor/Info.qmake.plist
new file mode 100644
index 00000000..079533e6
--- /dev/null
+++ b/examples/nfc/ndefeditor/Info.qmake.plist
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+
+ <key>CFBundleDisplayName</key>
+ <string>NDEF Editor</string>
+
+ <key>CFBundleIdentifier</key>
+ <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+
+ <key>CFBundleVersion</key>
+ <string>${QMAKE_FULL_VERSION}</string>
+
+ <key>CFBundleShortVersionString</key>
+ <string>${QMAKE_SHORT_VERSION}</string>
+
+ <key>CFBundleIconFile</key>
+ <string>${ASSETCATALOG_COMPILER_APPICON_NAME}</string>
+
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+
+ <key>NFCReaderUsageDescription</key>
+ <string>Qt's ndefeditor wants to access your NFC hardware</string>
+
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
diff --git a/examples/nfc/ndefeditor/Main.qml b/examples/nfc/ndefeditor/Main.qml
new file mode 100644
index 00000000..c5435e26
--- /dev/null
+++ b/examples/nfc/ndefeditor/Main.qml
@@ -0,0 +1,9 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+MainWindow {
+ width: 480
+ height: 640
+ visible: true
+ title: qsTr("NDEF Editor")
+}
diff --git a/examples/nfc/ndefeditor/MainWindow.qml b/examples/nfc/ndefeditor/MainWindow.qml
new file mode 100644
index 00000000..d32540fb
--- /dev/null
+++ b/examples/nfc/ndefeditor/MainWindow.qml
@@ -0,0 +1,384 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Dialogs
+import QtQuick.Layouts
+
+import NdefEditor
+
+ApplicationWindow {
+ id: window
+
+ enum TargetDetectedAction {
+ NoAction,
+ ReadMessage,
+ WriteMessage
+ }
+
+ StackView {
+ id: stack
+ initialItem: mainView
+ anchors.fill: parent
+ }
+
+ property int targetDetectedAction: MainWindow.NoAction
+
+ Component {
+ id: mainView
+
+ ColumnLayout {
+ ToolBar {
+ Layout.fillWidth: true
+
+ RowLayout {
+ anchors.fill: parent
+ Label {
+ text: qsTr("NDEF Editor")
+ elide: Label.ElideRight
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+ Layout.fillWidth: true
+ }
+ }
+ }
+
+ Pane {
+ id: writeTab
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Flickable {
+ anchors.fill: parent
+ contentHeight: contentItem.childrenRect.height
+
+ ColumnLayout {
+ width: parent.width
+
+ ItemDelegate {
+ icon.name: "file_download"
+ text: qsTr("Read Tag")
+ Layout.fillWidth: true
+
+ onClicked: window.readTag()
+ }
+
+ ItemDelegate {
+ icon.name: "file_upload"
+ text: qsTr("Write to Tag")
+ Layout.fillWidth: true
+
+ onClicked: window.writeTag()
+ }
+
+ ItemDelegate {
+ icon.name: "add"
+ text: qsTr("Add a Record")
+ Layout.fillWidth: true
+
+ onClicked: addRecordMenu.open()
+
+ Menu {
+ id: addRecordMenu
+ title: qsTr("Add record")
+
+ MenuItem {
+ icon.name: "text_snippet"
+ text: qsTr("Text record")
+ onTriggered: stack.push(textRecordDialog)
+ }
+ MenuItem {
+ icon.name: "link"
+ text: qsTr("URI record")
+ onTriggered: stack.push(uriRecordDialog)
+ }
+ }
+ }
+
+ Item {
+ implicitHeight: 20
+ }
+
+ Label {
+ text: qsTr(
+ "Use buttons above to read an NFC tag or add records manually.\n\n"
+ + "Once added, swipe to the right to access options for each record.")
+ wrapMode: Text.Wrap
+ visible: messages.count === 0
+ Layout.fillWidth: true
+ }
+
+ Repeater {
+ id: messages
+ model: messageModel
+
+ delegate: NdefRecordDelegate {
+ Layout.fillWidth: true
+
+ onDeleteClicked: messageModel.removeRow(index)
+
+ onClicked: {
+ if (recordType === NdefMessageModel.TextRecord) {
+ stack.push(textRecordDialog, {
+ text: recordText,
+ modelIndex: index
+ })
+ } else if (recordType === NdefMessageModel.UriRecord) {
+ stack.push(uriRecordDialog, {
+ uri: recordText,
+ modelIndex: index
+ })
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ NdefMessageModel {
+ id: messageModel
+ }
+
+ NfcManager {
+ id: nfcManager
+ onTargetDetected: (target) => { window.handleTargetDetected(target) }
+ }
+
+ Connections {
+ id: targetConnections
+ target: null
+
+ function onNdefMessageRead(message) {
+ messageModel.message = message
+ }
+
+ function onRequestCompleted() {
+ communicationOverlay.close()
+ window.targetDetectedAction = MainWindow.NoAction
+ releaseTarget()
+ }
+
+ function onError(code) {
+ communicationOverlay.close()
+ errorNotification.errorMessage = window.describeError(code)
+ errorNotification.open()
+ window.targetDetectedAction = MainWindow.NoAction
+ releaseTarget()
+ }
+
+ function releaseTarget() {
+ target?.destroy()
+ }
+ }
+
+ function handleTargetDetected(target: NfcTarget) {
+ targetConnections.releaseTarget()
+
+ let ok = true
+
+ if (targetDetectedAction === MainWindow.ReadMessage) {
+ targetConnections.target = target
+ communicationOverlay.message = qsTr("Target detected. Reading messages...")
+ errorNotification.errorMessage = qsTr("NDEF read error")
+ ok = target.readNdefMessages()
+ } else if (targetDetectedAction === MainWindow.WriteMessage) {
+ targetConnections.target = target
+ communicationOverlay.message = qsTr("Target detected. Writing the message...")
+ errorNotification.errorMessage = qsTr("NDEF write error")
+ ok = target.writeNdefMessage(messageModel.message)
+ } else {
+ target.destroy()
+ return
+ }
+
+ if (!ok) {
+ communicationOverlay.close()
+ errorNotification.open()
+ targetConnections.releaseTarget()
+ }
+ }
+
+ function readTag() {
+ window.targetDetectedAction = MainWindow.ReadMessage
+ nfcManager.startTargetDetection()
+ communicationOverlay.title = qsTr("Read Tag")
+ communicationOverlay.message = qsTr("Approach an NFC tag.")
+ communicationOverlay.open()
+ }
+
+ function writeTag() {
+ window.targetDetectedAction = MainWindow.WriteMessage
+ nfcManager.startTargetDetection()
+ communicationOverlay.title = qsTr("Write to Tag")
+ communicationOverlay.message = qsTr("Approach an NFC tag.")
+ communicationOverlay.open()
+ }
+
+ function describeError(error) {
+ switch (error) {
+ case 2: return qsTr("Usupported feature")
+ case 3: return qsTr("Target out of range")
+ case 4: return qsTr("No response")
+ case 5: return qsTr("Checksum mismatch")
+ case 6: return qsTr("Invalid parameters")
+ case 7: return qsTr("Connection error")
+ case 8: return qsTr("NDEF read error")
+ case 9: return qsTr("NDEF write error")
+ case 10: return qsTr("Command error")
+ case 11: return qsTr("Timeout")
+ }
+
+ return qsTr("Unknown error")
+ }
+
+ Dialog {
+ id: communicationOverlay
+
+ property alias message: messageLabel.text
+
+ anchors.centerIn: Overlay.overlay
+
+ modal: true
+ standardButtons: Dialog.Cancel
+
+ ColumnLayout {
+ Label {
+ id: messageLabel
+ }
+
+ BusyIndicator {
+ Layout.fillWidth: true
+ }
+ }
+
+ onClosed: nfcManager.stopTargetDetection()
+ }
+
+ MessageDialog {
+ property alias errorMessage: errorNotification.text
+
+ id: errorNotification
+
+ buttons: MessageDialog.Close
+ title: qsTr("Error")
+
+ onButtonClicked: errorNotification.close()
+ }
+
+ Component {
+ id: uriRecordDialog
+
+ ColumnLayout {
+ property alias uri: uriEditor.text
+ property int modelIndex: -1
+
+ ToolBar {
+ Layout.fillWidth: true
+
+ RowLayout {
+ anchors.fill: parent
+ ToolButton {
+ icon.name: "arrow_back"
+ onClicked: stack.pop()
+ }
+ Label {
+ text: qsTr("URI Record")
+ elide: Label.ElideRight
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+ Layout.fillWidth: true
+ }
+ ToolButton {
+ text: qsTr("Save")
+ onClicked: {
+ if (modelIndex < 0) {
+ messageModel.addUriRecord(uri)
+ } else {
+ messageModel.setTextData(modelIndex, uri)
+ }
+ stack.pop()
+ }
+ }
+ }
+ }
+
+ Pane {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ TextField {
+ id: uriEditor
+ Layout.fillWidth: true
+ placeholderText: qsTr("https://qt.io")
+ inputMethodHints: Qt.ImhUrlCharactersOnly
+ }
+ Item {
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+ }
+
+ Component {
+ id: textRecordDialog
+
+ ColumnLayout {
+ property alias text: textEditor.text
+ property int modelIndex: -1
+
+ ToolBar {
+ Layout.fillWidth: true
+
+ RowLayout {
+ anchors.fill: parent
+ ToolButton {
+ icon.name: "arrow_back"
+ onClicked: stack.pop()
+ }
+ Label {
+ text: qsTr("Text Record")
+ elide: Label.ElideRight
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+ Layout.fillWidth: true
+ }
+ ToolButton {
+ text: qsTr("Save")
+ onClicked: {
+ if (modelIndex < 0) {
+ messageModel.addTextRecord(textEditor.text)
+ } else {
+ messageModel.setTextData(modelIndex, textEditor.text)
+ }
+ stack.pop()
+ }
+ }
+ }
+ }
+
+ Pane {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ ScrollView {
+ anchors.fill: parent
+
+ TextArea {
+ id: textEditor
+ placeholderText: qsTr("Enter some text...")
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/examples/nfc/ndefeditor/NdefRecordDelegate.qml b/examples/nfc/ndefeditor/NdefRecordDelegate.qml
new file mode 100644
index 00000000..f01aff05
--- /dev/null
+++ b/examples/nfc/ndefeditor/NdefRecordDelegate.qml
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import NdefEditor
+
+SwipeDelegate {
+ required property int index
+ required property int recordType
+ required property string recordText
+
+ id: delegate
+
+ contentItem: ColumnLayout {
+ Label {
+ text: qsTr("Record %L1 - %2").arg(delegate.index + 1).arg(
+ delegate.describeRecordType(delegate.recordType))
+ font.bold: true
+ }
+
+ Label {
+ text: delegate.recordText
+ elide: Text.ElideRight
+ maximumLineCount: 1
+ Layout.fillWidth: true
+ }
+ }
+
+ swipe.left: Button {
+ text: qsTr("Delete")
+ padding: 12
+ height: delegate.height
+ anchors.left: delegate.left
+ SwipeDelegate.onClicked: delegate.deleteClicked()
+ }
+
+ function describeRecordType(type) {
+ switch (type) {
+ case NdefMessageModel.TextRecord: return qsTr("Text")
+ case NdefMessageModel.UriRecord: return qsTr("URI")
+ default: return qsTr("Other")
+ }
+ }
+
+ signal deleteClicked()
+}
diff --git a/examples/nfc/ndefeditor/doc/images/ndefeditor.png b/examples/nfc/ndefeditor/doc/images/ndefeditor.png
index d203e474..2be32f60 100644
--- a/examples/nfc/ndefeditor/doc/images/ndefeditor.png
+++ b/examples/nfc/ndefeditor/doc/images/ndefeditor.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/doc/src/ndefeditor.qdoc b/examples/nfc/ndefeditor/doc/src/ndefeditor.qdoc
index eb638200..0c7a0841 100644
--- a/examples/nfc/ndefeditor/doc/src/ndefeditor.qdoc
+++ b/examples/nfc/ndefeditor/doc/src/ndefeditor.qdoc
@@ -1,112 +1,25 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt local connectivity 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) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example ndefeditor
-\title NDEF Editor Example
-\brief An example about reading and writing NFC Data Exchange Format (NDEF) messages to NFC Forum Tags.
+\title NDEF Editor
+\examplecategory {Connectivity}
+\meta tags {nfc, ndef}
+\brief Reads and writes NFC Data Exchange Format (NDEF) messages to NFC Forum Tags.
-The NDEF Editor example reads and writes NFC Data Exchange Format
+The NDEF Editor example uses \l{Qt NFC} to read and write NFC Data Exchange Format
(NDEF) messages to NFC Forum Tags. NDEF messages can be composed by
-adding records of supported types. Additionally, NDEF messages can be
-loaded/saved from/into a file located in the file system of the
-machine where the application is running.
+adding text and URI records. Records can be deleted by swiping them to the left.
-\image ndefeditor.png
-
-\section1 NFC Tag detection
-
-The MainWindow class is able to detect if a NFC Tag is in the range
-for read/write operations. It can also detect if connectivity has been
-lost. This is achieved by connecting the MainWindow class private
-handlers to the signals QNearFieldManager::targetDetected and
-QNearFieldManager::targetLost.
-
-\snippet ndefeditor/mainwindow.cpp QNearFieldManager init
-
-Through the UI a user requests when to start the detection of a NFC
-Tag by calling the method QNearFieldManager::startTargetDetection.
-
-\snippet ndefeditor/mainwindow.cpp QNearFieldManager start detection
-
-Once the target is detected the MainWindow connects the following
-signals to its internal private slots:
-QNearFieldTarget::ndefMessageRead, QNearFieldTarget::NdefReadError,
-QNearFieldTarget::ndefMessagesWritten,
-QNearFieldTarget::NdefWriteError and QNearFieldTarget::error
-
-\snippet ndefeditor/mainwindow.cpp QNearFieldTarget detected
-
-If during the process of reading or writing to a NFC Tag the
-connection is lost, the MainWindow reacts to this event by
-scheduling the target deletion (QObject::deleteLater).
-
-\snippet ndefeditor/mainwindow.cpp QNearFieldTarget lost
-
-\section1 Record creation
-
-The main window of the ndefeditor example manages the composition and
-creation of NFC records. The UI contains a QScrollArea where
-RecordEditors are added dynamically on a user requests basis. The
-following methods of the MainWindow class provide an interface towards
-each of the record editing classes managing the different types of
-records.
+Press \b {Write to Tag} to write the records to an NFC tag.
-\snippet ndefeditor/mainwindow.h 0
+Press \b {Read Tag} to read the contents of an NFC tag. A successful read of an
+NFC tag replaces the manually added records with the NDEF message from the tag.
+If the read operation was cancelled or failed, the NDEF message remains
+unchanged.
-The following sections explain each of the record editing classes.
-\section1 Record editing classes
-
-\section2 TextRecordEditor
-
-The TextRecordEditor is a QWidget that can handle editing the values
-of text record that has been requested by the user. For each text
-record, there is a new instance of this class.
-
-\snippet ndefeditor/textrecordeditor.h 0
-
-\section2 UriRecordEditor
-
-The UriRecordEditor is a QWidget that can handle editing the values of
-Uri record that has been requested by the user. For each new Uri
-record there is a new instance of this class.
-
-\snippet ndefeditor/urirecordeditor.h 0
-
-\section2 MimeImageRecordEditor
-
-The UriRecordEditor is a QWidget that can handle editing the values of
-a Mime Image record that has been requested by the user. For each Mime
-Image record there is a new instance of this class.
-
-\snippet ndefeditor/mimeimagerecordeditor.h 0
-
-
-\include examples-run.qdocinc
+\image ndefeditor.png
\sa {Qt NFC}
*/
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20/add.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20/add.png
new file mode 100644
index 00000000..49659bf3
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20/add.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20/arrow_back.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20/arrow_back.png
new file mode 100644
index 00000000..8d39f677
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20/arrow_back.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20/file_download.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20/file_download.png
new file mode 100644
index 00000000..405a67b0
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20/file_download.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20/file_upload.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20/file_upload.png
new file mode 100644
index 00000000..7a13c507
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20/file_upload.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20/link.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20/link.png
new file mode 100644
index 00000000..6d663387
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20/link.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20/text_snippet.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20/text_snippet.png
new file mode 100644
index 00000000..bada4338
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20/text_snippet.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/add.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/add.png
new file mode 100644
index 00000000..8114d615
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/add.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/arrow_back.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/arrow_back.png
new file mode 100644
index 00000000..843444e2
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/arrow_back.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/file_download.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/file_download.png
new file mode 100644
index 00000000..d848b217
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/file_download.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/file_upload.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/file_upload.png
new file mode 100644
index 00000000..22364309
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/file_upload.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/link.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/link.png
new file mode 100644
index 00000000..0567312a
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/link.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/text_snippet.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/text_snippet.png
new file mode 100644
index 00000000..96ab459a
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@2/text_snippet.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/add.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/add.png
new file mode 100644
index 00000000..c55d4144
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/add.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/arrow_back.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/arrow_back.png
new file mode 100644
index 00000000..bb620d68
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/arrow_back.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/file_download.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/file_download.png
new file mode 100644
index 00000000..db8e7b13
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/file_download.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/file_upload.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/file_upload.png
new file mode 100644
index 00000000..1b240284
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/file_upload.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/link.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/link.png
new file mode 100644
index 00000000..e0569cbb
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/link.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/text_snippet.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/text_snippet.png
new file mode 100644
index 00000000..9dc6683f
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@3/text_snippet.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/add.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/add.png
new file mode 100644
index 00000000..4813a26f
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/add.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/arrow_back.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/arrow_back.png
new file mode 100644
index 00000000..54354ddd
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/arrow_back.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/file_download.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/file_download.png
new file mode 100644
index 00000000..20148b92
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/file_download.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/file_upload.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/file_upload.png
new file mode 100644
index 00000000..22a98cc2
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/file_upload.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/link.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/link.png
new file mode 100644
index 00000000..f8bedeef
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/link.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/text_snippet.png b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/text_snippet.png
new file mode 100644
index 00000000..74a5f7fe
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/20x20@4/text_snippet.png
Binary files differ
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/index.theme b/examples/nfc/ndefeditor/icons/ndefeditor/index.theme
new file mode 100644
index 00000000..756b1232
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/index.theme
@@ -0,0 +1,22 @@
+[Icon Theme]
+Name=ndefeditor
+Directories=20x20,20x20@2,20x20@3,20x20@4
+
+[20x20]
+Size=20
+Type=Fixed
+
+[20x20@2]
+Size=20
+Scale=2
+Type=Fixed
+
+[20x20@3]
+Size=20
+Scale=3
+Type=Fixed
+
+[20x20@4]
+Size=20
+Scale=4
+Type=Fixed
diff --git a/examples/nfc/ndefeditor/icons/ndefeditor/qt_attribution.json b/examples/nfc/ndefeditor/icons/ndefeditor/qt_attribution.json
new file mode 100644
index 00000000..b9ee69b4
--- /dev/null
+++ b/examples/nfc/ndefeditor/icons/ndefeditor/qt_attribution.json
@@ -0,0 +1,14 @@
+{
+ "Id": "ndefeditor",
+ "Name": "Selected Material Icons",
+ "QDocModule": "qtnfc",
+ "QtUsage": "Used in NDEF Editor example for Qt NFC.",
+ "QtParts": [
+ "examples"
+ ],
+ "Files": "20x20 20x20@2 20x20@3 20x20@4",
+ "Homepage": "https://fonts.google.com/icons",
+ "License": "Apache License Version 2.0",
+ "LicenseId": "Apache-2.0",
+ "Copyright": "Copyright 2018 Google, Inc. All Rights Reserved."
+}
diff --git a/examples/nfc/ndefeditor/main.cpp b/examples/nfc/ndefeditor/main.cpp
index 6ea32a57..a9e5218d 100644
--- a/examples/nfc/ndefeditor/main.cpp
+++ b/examples/nfc/ndefeditor/main.cpp
@@ -1,62 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module 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) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-#include <QApplication>
-#include "mainwindow.h"
+#include <QGuiApplication>
+#include <QIcon>
+#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
- QApplication a(argc, argv);
- MainWindow w;
+ QGuiApplication app(argc, argv);
- w.show();
+ QIcon::setThemeName("ndefeditor");
- return a.exec();
+ QQmlApplicationEngine engine;
+
+ QObject::connect(
+ &engine, &QQmlApplicationEngine::objectCreationFailed, &app,
+ []() { QCoreApplication::exit(1); }, Qt::QueuedConnection);
+ engine.loadFromModule("NdefEditor", "Main");
+
+ return app.exec();
}
diff --git a/examples/nfc/ndefeditor/mainwindow.cpp b/examples/nfc/ndefeditor/mainwindow.cpp
deleted file mode 100644
index 869f1790..00000000
--- a/examples/nfc/ndefeditor/mainwindow.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module 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$
-**
-****************************************************************************/
-
-#include "mainwindow.h"
-#include "ui_mainwindow.h"
-
-#include "textrecordeditor.h"
-#include "urirecordeditor.h"
-#include "mimeimagerecordeditor.h"
-
-#include <QtNfc/qndefnfcurirecord.h>
-#include <QtNfc/qndefnfctextrecord.h>
-#include <QtNfc/qndefrecord.h>
-#include <QtNfc/qndefmessage.h>
-#include <QtNfc/qnearfieldmanager.h>
-#include <QtNfc/qnearfieldtarget.h>
-
-#include <QtWidgets/QMenu>
-#include <QtWidgets/QVBoxLayout>
-#include <QtWidgets/QFrame>
-#include <QtWidgets/QLabel>
-#include <QtWidgets/QFileDialog>
-
-class EmptyRecordLabel : public QLabel
-{
- Q_OBJECT
-
-public:
- EmptyRecordLabel() : QLabel(tr("Empty Record")) { }
- ~EmptyRecordLabel() { }
-
- void setRecord(const QNdefRecord &record)
- {
- Q_UNUSED(record);
- }
-
- QNdefRecord record() const
- {
- return QNdefRecord();
- }
-};
-
-class UnknownRecordLabel : public QLabel
-{
- Q_OBJECT
-
-public:
- UnknownRecordLabel() : QLabel(tr("Unknown Record Type")) { }
- ~UnknownRecordLabel() { }
-
- void setRecord(const QNdefRecord &record) { m_record = record; }
- QNdefRecord record() const { return m_record; }
-
-private:
- QNdefRecord m_record;
-};
-
-template <typename T>
-void addRecord(Ui::MainWindow *ui, const QNdefRecord &record = QNdefRecord())
-{
- QVBoxLayout *vbox = qobject_cast<QVBoxLayout *>(ui->scrollAreaWidgetContents->layout());
- if (!vbox)
- return;
-
- if (!vbox->isEmpty()) {
- QFrame *hline = new QFrame;
- hline->setFrameShape(QFrame::HLine);
- hline->setObjectName(QStringLiteral("line-spacer"));
-
- vbox->addWidget(hline);
- }
-
- T *recordEditor = new T;
- recordEditor->setObjectName(QStringLiteral("record-editor"));
-
- if (!record.isEmpty())
- recordEditor->setRecord(record);
-
- vbox->addWidget(recordEditor);
-}
-
-MainWindow::MainWindow(QWidget *parent)
-: QMainWindow(parent), ui(new Ui::MainWindow), m_touchAction(NoAction)
-{
- ui->setupUi(this);
-
- QMenu *addRecordMenu = new QMenu(this);
- addRecordMenu->addAction(tr("NFC Text Record"), this, SLOT(addNfcTextRecord()));
- addRecordMenu->addAction(tr("NFC URI Record"), this, SLOT(addNfcUriRecord()));
- addRecordMenu->addAction(tr("MIME Image Record"), this, SLOT(addMimeImageRecord()));
- addRecordMenu->addAction(tr("Empty Record"), this, SLOT(addEmptyRecord()));
- ui->addRecord->setMenu(addRecordMenu);
-
- QVBoxLayout *vbox = new QVBoxLayout;
- ui->scrollAreaWidgetContents->setLayout(vbox);
-
- //! [QNearFieldManager init]
- m_manager = new QNearFieldManager(this);
- connect(m_manager, &QNearFieldManager::targetDetected,
- this, &MainWindow::targetDetected);
- connect(m_manager, &QNearFieldManager::targetLost,
- this, &MainWindow::targetLost);
- //! [QNearFieldManager init]
-}
-
-MainWindow::~MainWindow()
-{
- delete ui;
-}
-
-void MainWindow::addNfcTextRecord()
-{
- addRecord<TextRecordEditor>(ui);
-}
-
-void MainWindow::addNfcUriRecord()
-{
- addRecord<UriRecordEditor>(ui);
-}
-
-void MainWindow::addMimeImageRecord()
-{
- addRecord<MimeImageRecordEditor>(ui);
-}
-
-void MainWindow::addEmptyRecord()
-{
- addRecord<EmptyRecordLabel>(ui);
-}
-
-void MainWindow::loadMessage()
-{
- QString filename = QFileDialog::getOpenFileName(this, tr("Select NDEF Message"));
- if (filename.isEmpty())
- return;
-
- QFile file(filename);
- if (!file.open(QIODevice::ReadOnly))
- return;
-
- QByteArray ndef = file.readAll();
-
- ndefMessageRead(QNdefMessage::fromByteArray(ndef));
-
- file.close();
-}
-
-void MainWindow::saveMessage()
-{
- QString filename = QFileDialog::getSaveFileName(this, tr("Select NDEF Message"));
- if (filename.isEmpty())
- return;
-
- QFile file(filename);
- if (!file.open(QIODevice::WriteOnly))
- return;
-
- file.write(ndefMessage().toByteArray());
-
- file.close();
-}
-
-void MainWindow::touchReceive()
-{
- ui->status->setStyleSheet(QStringLiteral("background: blue"));
-
- m_touchAction = ReadNdef;
-
- m_manager->setTargetAccessModes(QNearFieldManager::NdefReadTargetAccess);
- //! [QNearFieldManager start detection]
- m_manager->startTargetDetection();
- //! [QNearFieldManager start detection]
-}
-
-void MainWindow::touchStore()
-{
- ui->status->setStyleSheet(QStringLiteral("background: yellow"));
-
- m_touchAction = WriteNdef;
-
- m_manager->setTargetAccessModes(QNearFieldManager::NdefWriteTargetAccess);
- m_manager->startTargetDetection();
-}
-
-//! [QNearFieldTarget detected]
-void MainWindow::targetDetected(QNearFieldTarget *target)
-{
- switch (m_touchAction) {
- case NoAction:
- break;
- case ReadNdef:
- connect(target, &QNearFieldTarget::ndefMessageRead, this, &MainWindow::ndefMessageRead);
- connect(target, &QNearFieldTarget::error, this, &MainWindow::targetError);
-
- m_request = target->readNdefMessages();
- if (!m_request.isValid()) // cannot read messages
- targetError(QNearFieldTarget::NdefReadError, m_request);
- break;
- case WriteNdef:
- connect(target, &QNearFieldTarget::ndefMessagesWritten, this, &MainWindow::ndefMessageWritten);
- connect(target, &QNearFieldTarget::error, this, &MainWindow::targetError);
-
- m_request = target->writeNdefMessages(QList<QNdefMessage>() << ndefMessage());
- if (!m_request.isValid()) // cannot write messages
- targetError(QNearFieldTarget::NdefWriteError, m_request);
- break;
- }
-}
-//! [QNearFieldTarget detected]
-
-//! [QNearFieldTarget lost]
-void MainWindow::targetLost(QNearFieldTarget *target)
-{
- target->deleteLater();
-}
-//! [QNearFieldTarget lost]
-
-void MainWindow::ndefMessageRead(const QNdefMessage &message)
-{
- clearMessage();
-
- for (const QNdefRecord &record : message) {
- if (record.isRecordType<QNdefNfcTextRecord>()) {
- addRecord<TextRecordEditor>(ui, record);
- } else if (record.isRecordType<QNdefNfcUriRecord>()) {
- addRecord<UriRecordEditor>(ui, record);
- } else if (record.typeNameFormat() == QNdefRecord::Mime &&
- record.type().startsWith("image/")) {
- addRecord<MimeImageRecordEditor>(ui, record);
- } else if (record.isEmpty()) {
- addRecord<EmptyRecordLabel>(ui);
- } else {
- addRecord<UnknownRecordLabel>(ui, record);
- }
- }
-
- ui->status->setStyleSheet(QString());
- m_manager->setTargetAccessModes(QNearFieldManager::NoTargetAccess);
- //! [QNearFieldManager stop detection]
- m_manager->stopTargetDetection();
- //! [QNearFieldManager stop detection]
- m_request = QNearFieldTarget::RequestId();
- ui->statusBar->clearMessage();
-}
-
-void MainWindow::ndefMessageWritten()
-{
- ui->status->setStyleSheet(QString());
- m_manager->setTargetAccessModes(QNearFieldManager::NoTargetAccess);
- m_manager->stopTargetDetection();
- m_request = QNearFieldTarget::RequestId();
- ui->statusBar->clearMessage();
-}
-
-void MainWindow::targetError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id)
-{
- Q_UNUSED(error);
- Q_UNUSED(id);
-
- if (m_request == id) {
- switch (error) {
- case QNearFieldTarget::NoError:
- ui->statusBar->clearMessage();
- break;
- case QNearFieldTarget::UnsupportedError:
- ui->statusBar->showMessage(tr("Unsupported tag"));
- break;
- case QNearFieldTarget::TargetOutOfRangeError:
- ui->statusBar->showMessage(tr("Tag removed from field"));
- break;
- case QNearFieldTarget::NoResponseError:
- ui->statusBar->showMessage(tr("No response from tag"));
- break;
- case QNearFieldTarget::ChecksumMismatchError:
- ui->statusBar->showMessage(tr("Checksum mismatch"));
- break;
- case QNearFieldTarget::InvalidParametersError:
- ui->statusBar->showMessage(tr("Invalid parameters"));
- break;
- case QNearFieldTarget::NdefReadError:
- ui->statusBar->showMessage(tr("NDEF read error"));
- break;
- case QNearFieldTarget::NdefWriteError:
- ui->statusBar->showMessage(tr("NDEF write error"));
- break;
- default:
- ui->statusBar->showMessage(tr("Unknown error"));
- }
-
- ui->status->setStyleSheet(QString());
- m_manager->setTargetAccessModes(QNearFieldManager::NoTargetAccess);
- m_manager->stopTargetDetection();
- m_request = QNearFieldTarget::RequestId();
- }
-}
-
-void MainWindow::clearMessage()
-{
- QWidget *scrollArea = ui->scrollAreaWidgetContents;
-
- qDeleteAll(scrollArea->findChildren<QWidget *>(QStringLiteral("line-spacer")));
- qDeleteAll(scrollArea->findChildren<QWidget *>(QStringLiteral("record-editor")));
-}
-
-QNdefMessage MainWindow::ndefMessage() const
-{
- QVBoxLayout *vbox = qobject_cast<QVBoxLayout *>(ui->scrollAreaWidgetContents->layout());
- if (!vbox)
- return QNdefMessage();
-
- QNdefMessage message;
-
- for (int i = 0; i < vbox->count(); ++i) {
- QWidget *widget = vbox->itemAt(i)->widget();
-
- if (TextRecordEditor *editor = qobject_cast<TextRecordEditor *>(widget)) {
- message.append(editor->record());
- } else if (UriRecordEditor *editor = qobject_cast<UriRecordEditor *>(widget)) {
- message.append(editor->record());
- } else if (MimeImageRecordEditor *editor = qobject_cast<MimeImageRecordEditor *>(widget)) {
- message.append(editor->record());
- } else if (qobject_cast<EmptyRecordLabel *>(widget)) {
- message.append(QNdefRecord());
- } else if (UnknownRecordLabel *label = qobject_cast<UnknownRecordLabel *>(widget)) {
- message.append(label->record());
- }
- }
-
- return message;
-}
-
-#include "mainwindow.moc"
diff --git a/examples/nfc/ndefeditor/mainwindow.h b/examples/nfc/ndefeditor/mainwindow.h
deleted file mode 100644
index 234efcd2..00000000
--- a/examples/nfc/ndefeditor/mainwindow.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module 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$
-**
-****************************************************************************/
-
-#ifndef MAINWINDOW_H
-#define MAINWINDOW_H
-
-#include <QtNfc/qnearfieldtarget.h>
-
-#include <QtWidgets/QMainWindow>
-
-QT_FORWARD_DECLARE_CLASS(QNearFieldManager)
-QT_FORWARD_DECLARE_CLASS(QNdefMessage)
-
-QT_BEGIN_NAMESPACE
-namespace Ui {
- class MainWindow;
-}
-QT_END_NAMESPACE
-
-class MainWindow : public QMainWindow
-{
- Q_OBJECT
-
-public:
- explicit MainWindow(QWidget *parent = 0);
- ~MainWindow();
-
-private slots:
- //! [0]
- void addNfcTextRecord();
- void addNfcUriRecord();
- void addMimeImageRecord();
- void addEmptyRecord();
- //! [0]
- void clearMessage();
-
- void loadMessage();
- void saveMessage();
-
- void touchReceive();
- void touchStore();
-
- void targetDetected(QNearFieldTarget *target);
- void targetLost(QNearFieldTarget *target);
-
- void ndefMessageRead(const QNdefMessage &message);
- void ndefMessageWritten();
- void targetError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id);
-
-private:
- enum TouchAction {
- NoAction,
- ReadNdef,
- WriteNdef
- };
-
- QNdefMessage ndefMessage() const;
-
-private:
- Ui::MainWindow *ui;
-
- QNearFieldManager *m_manager;
- TouchAction m_touchAction;
- QNearFieldTarget::RequestId m_request;
-};
-
-#endif // MAINWINDOW_H
diff --git a/examples/nfc/ndefeditor/mainwindow.ui b/examples/nfc/ndefeditor/mainwindow.ui
deleted file mode 100644
index adffa331..00000000
--- a/examples/nfc/ndefeditor/mainwindow.ui
+++ /dev/null
@@ -1,225 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>553</width>
- <height>397</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>NDEF Message Editor</string>
- </property>
- <widget class="QWidget" name="centralWidget">
- <layout class="QVBoxLayout" name="verticalLayout">
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="rightMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <property name="leftMargin">
- <number>9</number>
- </property>
- <property name="rightMargin">
- <number>9</number>
- </property>
- <item>
- <widget class="QWidget" name="status" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>25</width>
- <height>25</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>25</width>
- <height>25</height>
- </size>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="touchRetrieve">
- <property name="text">
- <string>Retrieve</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="touchStore">
- <property name="text">
- <string>Store</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="loadMessage">
- <property name="text">
- <string>Load</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="saveMessage">
- <property name="text">
- <string>Save</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="clearMessage">
- <property name="text">
- <string>Clear</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="addRecord">
- <property name="text">
- <string>Add</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QScrollArea" name="scrollArea">
- <property name="frameShape">
- <enum>QFrame::NoFrame</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Plain</enum>
- </property>
- <property name="verticalScrollBarPolicy">
- <enum>Qt::ScrollBarAsNeeded</enum>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="widgetResizable">
- <bool>true</bool>
- </property>
- <widget class="QWidget" name="scrollAreaWidgetContents">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>553</width>
- <height>335</height>
- </rect>
- </property>
- </widget>
- </widget>
- </item>
- </layout>
- </widget>
- <widget class="QStatusBar" name="statusBar"/>
- </widget>
- <layoutdefault spacing="6" margin="11"/>
- <resources/>
- <connections>
- <connection>
- <sender>saveMessage</sender>
- <signal>clicked()</signal>
- <receiver>MainWindow</receiver>
- <slot>saveMessage()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>419</x>
- <y>47</y>
- </hint>
- <hint type="destinationlabel">
- <x>275</x>
- <y>198</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>touchRetrieve</sender>
- <signal>clicked()</signal>
- <receiver>MainWindow</receiver>
- <slot>touchReceive()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>142</x>
- <y>47</y>
- </hint>
- <hint type="destinationlabel">
- <x>275</x>
- <y>198</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>touchStore</sender>
- <signal>clicked()</signal>
- <receiver>MainWindow</receiver>
- <slot>touchStore()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>244</x>
- <y>47</y>
- </hint>
- <hint type="destinationlabel">
- <x>275</x>
- <y>198</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>loadMessage</sender>
- <signal>clicked()</signal>
- <receiver>MainWindow</receiver>
- <slot>loadMessage()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>334</x>
- <y>47</y>
- </hint>
- <hint type="destinationlabel">
- <x>275</x>
- <y>198</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>clearMessage</sender>
- <signal>clicked()</signal>
- <receiver>MainWindow</receiver>
- <slot>clearMessage()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>419</x>
- <y>22</y>
- </hint>
- <hint type="destinationlabel">
- <x>275</x>
- <y>198</y>
- </hint>
- </hints>
- </connection>
- </connections>
- <slots>
- <slot>saveMessage()</slot>
- <slot>loadMessage()</slot>
- <slot>touchReceive()</slot>
- <slot>touchStore()</slot>
- <slot>clearMessage()</slot>
- </slots>
-</ui>
diff --git a/examples/nfc/ndefeditor/mimeimagerecordeditor.cpp b/examples/nfc/ndefeditor/mimeimagerecordeditor.cpp
deleted file mode 100644
index 8044e8a6..00000000
--- a/examples/nfc/ndefeditor/mimeimagerecordeditor.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module 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$
-**
-****************************************************************************/
-
-#include "mimeimagerecordeditor.h"
-#include "ui_mimeimagerecordeditor.h"
-
-#include <QtGui/QImageReader>
-#include <QtWidgets/QFileDialog>
-#include <QtCore/QBuffer>
-
-static QString imageFormatToMimeType(const QByteArray &format)
-{
- if (format == "bmp")
- return QStringLiteral("image/bmp");
- else if (format == "gif")
- return QStringLiteral("image/gif");
- else if (format == "jpg" || format == "jpeg")
- return QStringLiteral("image/jpeg");
- else if (format == "mng")
- return QStringLiteral("video/x-mng");
- else if (format == "png")
- return QStringLiteral("image/png");
- else if (format == "pbm")
- return QStringLiteral("image/x-portable-bitmap");
- else if (format == "pgm")
- return QStringLiteral("image/x-portable-graymap");
- else if (format == "ppm")
- return QStringLiteral("image/x-portable-pixmap");
- else if (format == "tiff")
- return QStringLiteral("image/tiff");
- else if (format == "xbm")
- return QStringLiteral("image/x-xbitmap");
- else if (format == "xpm")
- return QStringLiteral("image/x-xpixmap");
- else if (format == "svg")
- return QStringLiteral("image/svg+xml");
- else
- return QString();
-}
-
-MimeImageRecordEditor::MimeImageRecordEditor(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::MimeImageRecordEditor)
-{
- ui->setupUi(this);
-}
-
-MimeImageRecordEditor::~MimeImageRecordEditor()
-{
- delete ui;
-}
-
-void MimeImageRecordEditor::setRecord(const QNdefRecord &record)
-{
- m_record = record;
-
- QByteArray data = record.payload();
- QBuffer buffer(&data);
- buffer.open(QIODevice::ReadOnly);
-
- QImageReader reader(&buffer);
-
- ui->mimeImageType->setText(imageFormatToMimeType(reader.format()));
-
- ui->mimeImageImage->setPixmap(QPixmap::fromImage(reader.read()));
- ui->mimeImageFile->clear();
-}
-
-QNdefRecord MimeImageRecordEditor::record() const
-{
- return m_record;
-}
-
-void MimeImageRecordEditor::on_mimeImageOpen_clicked()
-{
- QString mimeDataFile = QFileDialog::getOpenFileName(this, tr("Select Image File"));
- if (mimeDataFile.isEmpty())
- return;
-
- QFile imageFile(mimeDataFile);
- if (!imageFile.open(QIODevice::ReadOnly)) {
- ui->mimeImageFile->clear();
- ui->mimeImageImage->clear();
- }
-
- QByteArray imageData = imageFile.readAll();
-
- QBuffer buffer(&imageData);
- buffer.open(QIODevice::ReadOnly);
-
- QImageReader reader(&buffer);
- QString mimeType = imageFormatToMimeType(reader.format());
- ui->mimeImageType->setText(mimeType);
-
- QImage image = reader.read();
-
- ui->mimeImageFile->setText(mimeDataFile);
- ui->mimeImageImage->setPixmap(QPixmap::fromImage(image));
-
- m_record.setTypeNameFormat(QNdefRecord::Mime);
- m_record.setType(mimeType.toLatin1());
- m_record.setPayload(imageData);
-}
diff --git a/examples/nfc/ndefeditor/mimeimagerecordeditor.h b/examples/nfc/ndefeditor/mimeimagerecordeditor.h
deleted file mode 100644
index 44cd084b..00000000
--- a/examples/nfc/ndefeditor/mimeimagerecordeditor.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module 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$
-**
-****************************************************************************/
-
-
-#ifndef MIMEIMAGERECORDEDITOR_H
-#define MIMEIMAGERECORDEDITOR_H
-
-#include <QtNfc/qndefrecord.h>
-
-#include <QtWidgets/QWidget>
-
-QT_USE_NAMESPACE
-
-QT_BEGIN_NAMESPACE
-namespace Ui {
- class MimeImageRecordEditor;
-}
-QT_END_NAMESPACE
-
-//! [0]
-class MimeImageRecordEditor : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit MimeImageRecordEditor(QWidget *parent = 0);
- ~MimeImageRecordEditor();
-
- void setRecord(const QNdefRecord &record);
- QNdefRecord record() const;
-
-private:
- Ui::MimeImageRecordEditor *ui;
- QNdefRecord m_record;
-
-private slots:
- void on_mimeImageOpen_clicked();
-};
-//! [0]
-#endif // MIMEIMAGERECORDEDITOR_H
diff --git a/examples/nfc/ndefeditor/mimeimagerecordeditor.ui b/examples/nfc/ndefeditor/mimeimagerecordeditor.ui
deleted file mode 100644
index 4cde216f..00000000
--- a/examples/nfc/ndefeditor/mimeimagerecordeditor.ui
+++ /dev/null
@@ -1,83 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MimeImageRecordEditor</class>
- <widget class="QWidget" name="MimeImageRecordEditor">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>403</width>
- <height>106</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <item row="0" column="0" colspan="2">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>MIME Record &lt;image/*&gt;</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_11">
- <property name="text">
- <string>Type:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="mimeImageType">
- <property name="sizePolicy">
- <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>image/</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_12">
- <property name="text">
- <string>File:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QLineEdit" name="mimeImageFile">
- <property name="sizePolicy">
- <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QToolButton" name="mimeImageOpen">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="3" column="1">
- <widget class="QLabel" name="mimeImageImage">
- <property name="text">
- <string>TextLabel</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/examples/nfc/ndefeditor/ndefeditor.pro b/examples/nfc/ndefeditor/ndefeditor.pro
index 4b81c17c..f6c270de 100644
--- a/examples/nfc/ndefeditor/ndefeditor.pro
+++ b/examples/nfc/ndefeditor/ndefeditor.pro
@@ -1,27 +1,66 @@
-QT += nfc widgets
-requires(qtConfig(filedialog))
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+QT += nfc quick quickcontrols2
+
+CONFIG += qmltypes
+QML_IMPORT_NAME = NdefEditor
+QML_IMPORT_MAJOR_VERSION = 1
TARGET = ndefeditor
TEMPLATE = app
SOURCES += \
main.cpp \
- mainwindow.cpp \
- textrecordeditor.cpp \
- urirecordeditor.cpp \
- mimeimagerecordeditor.cpp
+ nfcmanager.cpp \
+ nfctarget.cpp \
+ ndefmessagemodel.cpp
HEADERS += \
- mainwindow.h \
- textrecordeditor.h \
- urirecordeditor.h \
- mimeimagerecordeditor.h
-
-FORMS += \
- mainwindow.ui \
- textrecordeditor.ui \
- urirecordeditor.ui \
- mimeimagerecordeditor.ui
+ nfcmanager.h \
+ nfctarget.h \
+ ndefmessagemodel.h
+
+qml_resources.files = \
+ qmldir \
+ Main.qml \
+ MainWindow.qml \
+ NdefRecordDelegate.qml
+
+qml_resources.prefix = /qt/qml/NdefEditor
+
+theme_resources.files = \
+ icons/ndefeditor/20x20@2/add.png \
+ icons/ndefeditor/20x20@2/arrow_back.png \
+ icons/ndefeditor/20x20@2/file_download.png \
+ icons/ndefeditor/20x20@2/file_upload.png \
+ icons/ndefeditor/20x20@2/link.png \
+ icons/ndefeditor/20x20@2/text_snippet.png \
+ icons/ndefeditor/20x20@3/add.png \
+ icons/ndefeditor/20x20@3/arrow_back.png \
+ icons/ndefeditor/20x20@3/file_download.png \
+ icons/ndefeditor/20x20@3/file_upload.png \
+ icons/ndefeditor/20x20@3/link.png \
+ icons/ndefeditor/20x20@3/text_snippet.png \
+ icons/ndefeditor/20x20@4/add.png \
+ icons/ndefeditor/20x20@4/arrow_back.png \
+ icons/ndefeditor/20x20@4/file_download.png \
+ icons/ndefeditor/20x20@4/file_upload.png \
+ icons/ndefeditor/20x20@4/link.png \
+ icons/ndefeditor/20x20@4/text_snippet.png \
+ icons/ndefeditor/20x20/add.png \
+ icons/ndefeditor/20x20/arrow_back.png \
+ icons/ndefeditor/20x20/file_download.png \
+ icons/ndefeditor/20x20/file_upload.png \
+ icons/ndefeditor/20x20/link.png \
+ icons/ndefeditor/20x20/text_snippet.png \
+ icons/ndefeditor/index.theme
+
+theme_resources.prefix = /
+
+RESOURCES += qml_resources theme_resources
+
+ios: QMAKE_INFO_PLIST = Info.qmake.plist
target.path = $$[QT_INSTALL_EXAMPLES]/nfc/ndefeditor
INSTALLS += target
diff --git a/examples/nfc/ndefeditor/ndefmessagemodel.cpp b/examples/nfc/ndefeditor/ndefmessagemodel.cpp
new file mode 100644
index 00000000..177d21dc
--- /dev/null
+++ b/examples/nfc/ndefeditor/ndefmessagemodel.cpp
@@ -0,0 +1,156 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "ndefmessagemodel.h"
+
+#include <QNdefNfcTextRecord>
+#include <QNdefNfcUriRecord>
+
+NdefMessageModel::NdefMessageModel(QObject *parent) : QAbstractListModel(parent) { }
+
+int NdefMessageModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return m_message.size();
+}
+
+static NdefMessageModel::RecordType getRecordType(const QNdefRecord &record)
+{
+ if (record.isRecordType<QNdefNfcTextRecord>()) {
+ return NdefMessageModel::TextRecord;
+ } else if (record.isRecordType<QNdefNfcUriRecord>()) {
+ return NdefMessageModel::UriRecord;
+ }
+ return NdefMessageModel::OtherRecord;
+}
+
+static QString getText(const QNdefRecord &record)
+{
+ if (record.isRecordType<QNdefNfcTextRecord>()) {
+ QNdefNfcTextRecord r(record);
+ return r.text();
+ } else if (record.isRecordType<QNdefNfcUriRecord>()) {
+ QNdefNfcUriRecord r(record);
+ return r.uri().toString();
+ }
+ return record.payload().toHex(':');
+}
+
+QVariant NdefMessageModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return {};
+
+ if (index.row() < 0 || index.row() >= m_message.size())
+ return {};
+
+ const auto &record = m_message.at(index.row());
+
+ switch (role) {
+ case RecordTypeRole:
+ return getRecordType(record);
+ case RecordTextRole:
+ return getText(record);
+ default:
+ return {};
+ }
+}
+
+QHash<int, QByteArray> NdefMessageModel::roleNames() const
+{
+ QHash<int, QByteArray> names;
+ names[RecordTypeRole] = "recordType";
+ names[RecordTextRole] = "recordText";
+ return names;
+}
+
+bool NdefMessageModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (parent.isValid())
+ return false;
+ if (row < 0 || count <= 0)
+ return false;
+ if (row >= m_message.size() || (m_message.size() - row) < count)
+ return false;
+
+ beginRemoveRows(parent, row, row + count - 1);
+ m_message.remove(row, count);
+ endRemoveRows();
+ Q_EMIT messageChanged();
+
+ return true;
+}
+
+QNdefMessage NdefMessageModel::message() const
+{
+ return m_message;
+}
+
+void NdefMessageModel::setMessage(const QNdefMessage &newMessage)
+{
+ if (m_message == newMessage)
+ return;
+
+ beginResetModel();
+ m_message = newMessage;
+ endResetModel();
+
+ Q_EMIT messageChanged();
+}
+
+void NdefMessageModel::clearMessage()
+{
+ if (m_message.isEmpty())
+ return;
+ removeRows(0, m_message.size(), {});
+}
+
+void NdefMessageModel::addTextRecord(const QString &text)
+{
+ QNdefNfcTextRecord record;
+ record.setText(text);
+
+ const auto newRow = m_message.size();
+ beginInsertRows({}, newRow, newRow);
+ m_message.append(std::move(record));
+ endInsertRows();
+ Q_EMIT messageChanged();
+}
+
+void NdefMessageModel::addUriRecord(const QString &uri)
+{
+ QNdefNfcUriRecord record;
+ record.setUri(QUrl(uri));
+
+ const auto newRow = m_message.size();
+ beginInsertRows({}, newRow, newRow);
+ m_message.append(std::move(record));
+ endInsertRows();
+ Q_EMIT messageChanged();
+}
+
+void NdefMessageModel::setTextData(int row, const QString &text)
+{
+ if (row < 0 || row >= m_message.size())
+ return;
+
+ const auto &record = m_message.at(row);
+
+ if (record.isRecordType<QNdefNfcTextRecord>()) {
+ QNdefNfcTextRecord r(record);
+ r.setText(text);
+ m_message[row] = r;
+ } else if (record.isRecordType<QNdefNfcUriRecord>()) {
+ QNdefNfcUriRecord r(record);
+ r.setUri(text);
+ m_message[row] = r;
+ } else {
+ return;
+ }
+
+ const auto idx = index(row);
+ Q_EMIT dataChanged(idx, idx, { RecordTextRole });
+ Q_EMIT messageChanged();
+}
diff --git a/examples/nfc/ndefeditor/ndefmessagemodel.h b/examples/nfc/ndefeditor/ndefmessagemodel.h
new file mode 100644
index 00000000..5f9ddf24
--- /dev/null
+++ b/examples/nfc/ndefeditor/ndefmessagemodel.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef NDEFMESSAGEMODEL_H
+#define NDEFMESSAGEMODEL_H
+
+#include <QAbstractListModel>
+
+#include <QNdefMessage>
+#include <QQmlEngine>
+
+class NdefMessageModel : public QAbstractListModel
+{
+ Q_OBJECT
+ QML_ELEMENT
+ Q_PROPERTY(QNdefMessage message READ message WRITE setMessage NOTIFY messageChanged)
+
+public:
+ explicit NdefMessageModel(QObject *parent = nullptr);
+
+ enum Role {
+ RecordTypeRole,
+ RecordTextRole,
+ };
+
+ enum RecordType {
+ OtherRecord,
+ TextRecord,
+ UriRecord,
+ };
+ Q_ENUM(RecordType)
+
+ int rowCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ QHash<int, QByteArray> roleNames() const override;
+ bool removeRows(int row, int count, const QModelIndex &parent) override;
+
+ QNdefMessage message() const;
+ void setMessage(const QNdefMessage &newMessage);
+
+ Q_INVOKABLE void clearMessage();
+ Q_INVOKABLE void addTextRecord(const QString &text);
+ Q_INVOKABLE void addUriRecord(const QString &uri);
+ Q_INVOKABLE void setTextData(int row, const QString &text);
+
+Q_SIGNALS:
+ void messageChanged();
+
+private:
+ QNdefMessage m_message;
+};
+
+#endif // NDEFMESSAGEMODEL_H
diff --git a/examples/nfc/ndefeditor/nfcmanager.cpp b/examples/nfc/ndefeditor/nfcmanager.cpp
new file mode 100644
index 00000000..bc09b89e
--- /dev/null
+++ b/examples/nfc/ndefeditor/nfcmanager.cpp
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "nfcmanager.h"
+
+#include <QNearFieldManager>
+
+#include "nfctarget.h"
+
+NfcManager::NfcManager(QObject *parent) : QObject(parent)
+{
+ m_manager = new QNearFieldManager(this);
+
+ connect(m_manager, &QNearFieldManager::targetDetected, this, [this](QNearFieldTarget *target) {
+ auto jsTarget = new NfcTarget(target);
+ QJSEngine::setObjectOwnership(jsTarget, QJSEngine::JavaScriptOwnership);
+ Q_EMIT targetDetected(jsTarget);
+ });
+}
+
+void NfcManager::startTargetDetection()
+{
+ m_manager->startTargetDetection(QNearFieldTarget::NdefAccess);
+}
+
+void NfcManager::stopTargetDetection()
+{
+ m_manager->stopTargetDetection();
+}
diff --git a/examples/nfc/ndefeditor/nfcmanager.h b/examples/nfc/ndefeditor/nfcmanager.h
new file mode 100644
index 00000000..b30f6f36
--- /dev/null
+++ b/examples/nfc/ndefeditor/nfcmanager.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef NFCMANAGER_H
+#define NFCMANAGER_H
+
+#include <QObject>
+
+#include <QQmlEngine>
+
+#include "nfctarget.h"
+
+QT_FORWARD_DECLARE_CLASS(QNearFieldManager);
+
+class NfcManager : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+
+public:
+ explicit NfcManager(QObject *parent = nullptr);
+
+ Q_INVOKABLE void startTargetDetection();
+ Q_INVOKABLE void stopTargetDetection();
+
+Q_SIGNALS:
+ void targetDetected(NfcTarget *target);
+
+private:
+ QNearFieldManager *m_manager;
+};
+
+#endif // NFCMANAGER_H
diff --git a/examples/nfc/ndefeditor/nfctarget.cpp b/examples/nfc/ndefeditor/nfctarget.cpp
new file mode 100644
index 00000000..68b26df5
--- /dev/null
+++ b/examples/nfc/ndefeditor/nfctarget.cpp
@@ -0,0 +1,31 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "nfctarget.h"
+
+NfcTarget::NfcTarget(QNearFieldTarget *target, QObject *parent) : QObject(parent), m_target(target)
+{
+ target->setParent(this);
+
+ connect(target, &QNearFieldTarget::ndefMessageRead, this, &NfcTarget::ndefMessageRead);
+ connect(target, &QNearFieldTarget::requestCompleted, this, &NfcTarget::requestCompleted);
+ connect(target, &QNearFieldTarget::error, this, &NfcTarget::error);
+}
+
+bool NfcTarget::readNdefMessages()
+{
+ if (m_target.isNull())
+ return false;
+
+ auto req = m_target->readNdefMessages();
+ return req.isValid();
+}
+
+bool NfcTarget::writeNdefMessage(const QNdefMessage &message)
+{
+ if (m_target.isNull())
+ return false;
+
+ auto req = m_target->writeNdefMessages({ message });
+ return req.isValid();
+}
diff --git a/examples/nfc/ndefeditor/nfctarget.h b/examples/nfc/ndefeditor/nfctarget.h
new file mode 100644
index 00000000..fbe3183c
--- /dev/null
+++ b/examples/nfc/ndefeditor/nfctarget.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef NFCTARGET_H
+#define NFCTARGET_H
+
+#include <QObject>
+
+#include <QNdefMessage>
+#include <QNearFieldTarget>
+#include <QPointer>
+#include <QQmlEngine>
+
+class NfcTarget : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("Created by NfcManager")
+
+public:
+ explicit NfcTarget(QNearFieldTarget *target, QObject *parent = nullptr);
+
+ Q_INVOKABLE bool readNdefMessages();
+ Q_INVOKABLE bool writeNdefMessage(const QNdefMessage &message);
+
+Q_SIGNALS:
+ void ndefMessageRead(const QNdefMessage &message);
+ void requestCompleted();
+ void error(QNearFieldTarget::Error error);
+
+private:
+ QPointer<QNearFieldTarget> m_target;
+};
+
+#endif // NFCTARGET_H
diff --git a/examples/nfc/ndefeditor/qmldir b/examples/nfc/ndefeditor/qmldir
new file mode 100644
index 00000000..0a77d792
--- /dev/null
+++ b/examples/nfc/ndefeditor/qmldir
@@ -0,0 +1,5 @@
+module NdefEditor
+prefer :/qt/qml/NdefEditor/
+Main 1.0 Main.qml
+MainWindow 1.0 MainWindow.qml
+NdefRecordDelegate 1.0 NdefRecordDelegate.qml
diff --git a/examples/nfc/ndefeditor/textrecordeditor.cpp b/examples/nfc/ndefeditor/textrecordeditor.cpp
deleted file mode 100644
index 381ff88f..00000000
--- a/examples/nfc/ndefeditor/textrecordeditor.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module 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$
-**
-****************************************************************************/
-
-#include "textrecordeditor.h"
-#include "ui_textrecordeditor.h"
-
-TextRecordEditor::TextRecordEditor(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::TextRecordEditor)
-{
- ui->setupUi(this);
-}
-
-TextRecordEditor::~TextRecordEditor()
-{
- delete ui;
-}
-
-void TextRecordEditor::setRecord(const QNdefNfcTextRecord &textRecord)
-{
- ui->text->setText(textRecord.text());
- ui->locale->setText(textRecord.locale());
-
- if (textRecord.encoding() == QNdefNfcTextRecord::Utf8)
- ui->encoding->setCurrentIndex(0);
- else if (textRecord.encoding() == QNdefNfcTextRecord::Utf16)
- ui->encoding->setCurrentIndex(1);
-}
-
-QNdefNfcTextRecord TextRecordEditor::record() const
-{
- QNdefNfcTextRecord record;
-
- if (ui->encoding->currentIndex() == 0)
- record.setEncoding(QNdefNfcTextRecord::Utf8);
- else if (ui->encoding->currentIndex() == 1)
- record.setEncoding(QNdefNfcTextRecord::Utf16);
-
- record.setLocale(ui->locale->text());
-
- record.setText(ui->text->text());
-
- return record;
-}
diff --git a/examples/nfc/ndefeditor/textrecordeditor.h b/examples/nfc/ndefeditor/textrecordeditor.h
deleted file mode 100644
index df3a872c..00000000
--- a/examples/nfc/ndefeditor/textrecordeditor.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module 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$
-**
-****************************************************************************/
-
-#ifndef TEXTRECORDEDITOR_H
-#define TEXTRECORDEDITOR_H
-
-#include <QtNfc/qndefnfctextrecord.h>
-
-#include <QtWidgets/QWidget>
-
-QT_BEGIN_NAMESPACE
-namespace Ui {
- class TextRecordEditor;
-}
-QT_END_NAMESPACE
-
-//! [0]
-class TextRecordEditor : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit TextRecordEditor(QWidget *parent = 0);
- ~TextRecordEditor();
-
- void setRecord(const QNdefNfcTextRecord &textRecord);
- QNdefNfcTextRecord record() const;
-
-private:
- Ui::TextRecordEditor *ui;
-};
-//! [0]
-
-#endif // TEXTRECORDEDITOR_H
diff --git a/examples/nfc/ndefeditor/textrecordeditor.ui b/examples/nfc/ndefeditor/textrecordeditor.ui
deleted file mode 100644
index 41950e7d..00000000
--- a/examples/nfc/ndefeditor/textrecordeditor.ui
+++ /dev/null
@@ -1,101 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>TextRecordEditor</class>
- <widget class="QWidget" name="TextRecordEditor">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>344</width>
- <height>115</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <property name="rowWrapPolicy">
- <enum>QFormLayout::WrapLongRows</enum>
- </property>
- <item row="0" column="0" colspan="2">
- <widget class="QLabel" name="label_5">
- <property name="text">
- <string>NFC Text Record</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_7">
- <property name="text">
- <string>Text:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="text">
- <property name="sizePolicy">
- <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_6">
- <property name="text">
- <string>Locale:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLineEdit" name="locale">
- <property name="sizePolicy">
- <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Encoding:</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QComboBox" name="encoding">
- <property name="sizePolicy">
- <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <item>
- <property name="text">
- <string>UTF-8</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>UTF-16</string>
- </property>
- </item>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/examples/nfc/ndefeditor/urirecordeditor.cpp b/examples/nfc/ndefeditor/urirecordeditor.cpp
deleted file mode 100644
index 4088aece..00000000
--- a/examples/nfc/ndefeditor/urirecordeditor.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module 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$
-**
-****************************************************************************/
-
-#include "urirecordeditor.h"
-#include "ui_urirecordeditor.h"
-
-#include <QtCore/QUrl>
-
-UriRecordEditor::UriRecordEditor(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::UriRecordEditor)
-{
- ui->setupUi(this);
-}
-
-UriRecordEditor::~UriRecordEditor()
-{
- delete ui;
-}
-
-void UriRecordEditor::setRecord(const QNdefNfcUriRecord &uriRecord)
-{
- ui->uri->setText(uriRecord.uri().toString());
-}
-
-QNdefNfcUriRecord UriRecordEditor::record() const
-{
- QNdefNfcUriRecord record;
-
- record.setUri(ui->uri->text());
-
- return record;
-}
diff --git a/examples/nfc/ndefeditor/urirecordeditor.h b/examples/nfc/ndefeditor/urirecordeditor.h
deleted file mode 100644
index aa3f4dfc..00000000
--- a/examples/nfc/ndefeditor/urirecordeditor.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module 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$
-**
-****************************************************************************/
-
-#ifndef URIRECORDEDITOR_H
-#define URIRECORDEDITOR_H
-
-#include <QtNfc/qndefnfcurirecord.h>
-
-#include <QtWidgets/QWidget>
-
-QT_BEGIN_NAMESPACE
-namespace Ui {
- class UriRecordEditor;
-}
-QT_END_NAMESPACE
-
-//! [0]
-class UriRecordEditor : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit UriRecordEditor(QWidget *parent = 0);
- ~UriRecordEditor();
-
- void setRecord(const QNdefNfcUriRecord &uriRecord);
- QNdefNfcUriRecord record() const;
-
-private:
- Ui::UriRecordEditor *ui;
-};
-//! [0]
-#endif // URIRECORDEDITOR_H
diff --git a/examples/nfc/ndefeditor/urirecordeditor.ui b/examples/nfc/ndefeditor/urirecordeditor.ui
deleted file mode 100644
index 929c1eb4..00000000
--- a/examples/nfc/ndefeditor/urirecordeditor.ui
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>UriRecordEditor</class>
- <widget class="QWidget" name="UriRecordEditor">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>439</width>
- <height>59</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
- <layout class="QFormLayout" name="formLayout">
- <item row="0" column="0" colspan="2">
- <widget class="QLabel" name="label_8">
- <property name="text">
- <string>NFC URI Record</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_9">
- <property name="text">
- <string>Uri:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="uri">
- <property name="sizePolicy">
- <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/examples/nfc/nfc.pro b/examples/nfc/nfc.pro
index 0076a711..49d54525 100644
--- a/examples/nfc/nfc.pro
+++ b/examples/nfc/nfc.pro
@@ -1,12 +1,7 @@
TEMPLATE = subdirs
qtHaveModule(widgets) {
- SUBDIRS += \
- annotatedurl \
- ndefeditor
+ SUBDIRS += annotatedurl
}
-qtHaveModule(quick) {
- SUBDIRS += \
- poster
+qtHaveModule(quickcontrols2) {
+ SUBDIRS += ndefeditor
}
-
-qtHaveModule(quick): SUBDIRS += corkboard
diff --git a/examples/nfc/poster/doc/images/qml-poster-example.png b/examples/nfc/poster/doc/images/qml-poster-example.png
deleted file mode 100644
index 8ed2292c..00000000
--- a/examples/nfc/poster/doc/images/qml-poster-example.png
+++ /dev/null
Binary files differ
diff --git a/examples/nfc/poster/doc/src/poster.qdoc b/examples/nfc/poster/doc/src/poster.qdoc
deleted file mode 100644
index b94bcca8..00000000
--- a/examples/nfc/poster/doc/src/poster.qdoc
+++ /dev/null
@@ -1,62 +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$
-**
-****************************************************************************/
-
-/*!
-\example poster
-\title QML Poster Example
-\brief A QML example about reading and displaying NFC Data Exchange Format (NDEF) messages.
-
-The QML Poster example displays the contents of specifically formatted NFC Data
-Exchange Format (NDEF) messages read from an NFC Tag. The NDEF message must
-contain a URI record, an optional \c image/* MIME record, and one or more
-localized Text records.
-
-\image qml-poster-example.png
-
-\include examples-run.qdocinc
-
-\section1 Applying NDEF Filters
-
-The example is designed to display the content of a very specific type of NFC tag.
-The tag must contain at least one URI record and one text record. If those two
-record types do not exist, nothing will happen. Such filtering is applied via the
-\l NearField type's filter property. The property accepts a list of \l NdefFilter objects.
-
-\snippet poster/poster.qml QML NDEF filtering
-
-\section1 Processing Found NDEF Messages
-
-Once an appropriate tag is found, the \l NearField::messageRecords property reflects the content.
-It transports the list of found NDEF records. The QML snippet below
-demonstrates how these records can be accessed:
-
-\snippet poster/poster.qml messageRecordsChanged 1
-\snippet poster/poster.qml messageRecordsChanged 2
-\snippet poster/poster.qml messageRecordsChanged 3
-
-\sa {Qt NFC}
-*/
diff --git a/examples/nfc/poster/poster.pro b/examples/nfc/poster/poster.pro
deleted file mode 100644
index b6e87ed6..00000000
--- a/examples/nfc/poster/poster.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-QT += qml quick network nfc
-
-SOURCES += \
- qmlposter.cpp
-
-TARGET = qml_poster
-TEMPLATE = app
-
-RESOURCES += \
- poster.qrc
-
-OTHER_FILES += \
- poster.qml
-
-target.path = $$[QT_INSTALL_EXAMPLES]/nfc/poster
-INSTALLS += target
diff --git a/examples/nfc/poster/poster.qml b/examples/nfc/poster/poster.qml
deleted file mode 100644
index 3e2a1eda..00000000
--- a/examples/nfc/poster/poster.qml
+++ /dev/null
@@ -1,218 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module 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 QtQuick 2.3
-import QtNfc 5.5
-
-Rectangle {
- id: root
- width: 640
- height: 360
-
- NearField {
- id: nearfield
- property bool requiresManualPolling: false
-
- onPollingChanged: {
- if (!polling && requiresManualPolling)
- polling = true; //restart polling
- }
-
- Component.onCompleted: {
- if (!polling) {
- requiresManualPolling = true;
- polling = true;
- }
- }
-
- //! [QML NDEF filtering]
- filter: [
- NdefFilter { type: "U"; typeNameFormat: NdefRecord.NfcRtd; maximum: 1 },
- NdefFilter { type: "T"; typeNameFormat: NdefRecord.NfcRtd },
- NdefFilter { typeNameFormat: NdefRecord.Mime; minimum: 0; maximum: 1 }
- ]
-
- //! [QML NDEF filtering]
-
- //! [messageRecordsChanged 1]
- onMessageRecordsChanged: {
- //! [messageRecordsChanged 1]
- posterText.text = "";
- posterImage.source = "";
- posterUrl.text = "";
-
- var currentLocaleMatch = NdefTextRecord.LocaleMatchedNone;
- var i;
- var found = false;
- //! [messageRecordsChanged 2]
- for (i = 0; i < messageRecords.length; ++i) {
- switch (messageRecords[i].typeNameFormat) {
- case NdefRecord.NfcRtd:
- if (messageRecords[i].type === "T") {
- if (messageRecords[i].localeMatch > currentLocaleMatch) {
- currentLocaleMatch = messageRecords[i].localeMatch;
- posterText.text = messageRecords[i].text;
- found = true;
- }
-
- } else if (messageRecords[i].type === "U") {
- posterUrl.text = messageRecords[i].uri;
- found = true;
- }
- break;
- case NdefRecord.Mime:
- if (messageRecords[i].type.indexOf("image/") === 0 ) {
- posterImage.source = messageRecords[i].uri;
- found = true;
- }
- break;
- }
-
- if (!found)
- console.warn("Unknown NFC tag detected. Cannot display content.")
- }
- //! [messageRecordsChanged 2]
-
- root.state = "show";
- //! [messageRecordsChanged 3]
- }
- //! [messageRecordsChanged 3]
- }
-
- Text {
- id: touchText
- anchors { horizontalCenter: parent.horizontalCenter; horizontalCenterOffset: parent.verticalCenter }
- text: "Touch an NFC tag with at least one Text and one URI record."
- font { italic: true; pointSize: 18 }
- wrapMode: Text.WordWrap
- width: root.width*0.75
- horizontalAlignment: Text.AlignHCenter
- }
-
- Image {
- id: posterImage
- scale: Image.PreserveAspectFit
- height: parent.height * 0.8
- width: height * sourceSize.width / sourceSize.height
- anchors.verticalCenter: parent.verticalCenter
- x: -width
- smooth: true
- }
-
- Text {
- id: posterText
- y: -height
- anchors { horizontalCenter: parent.right; horizontalCenterOffset: - parent.width / 4 }
- font { italic: true; pointSize: 18 }
- }
-
- Text {
- id: posterUrl
- y: parent.height
- anchors { horizontalCenter: parent.right; horizontalCenterOffset: - parent.width / 4 }
- font { italic: true; pointSize: 14 }
- }
-
- MouseArea {
- id: openMouseArea
- anchors.fill: parent
- enabled: root.state == "show"
- onClicked: Qt.openUrlExternally(posterUrl.text)
-
- Rectangle {
- id: testTouch
- width: 50
- height: 50
- color: "lightsteelblue"
- opacity: 0.3
- anchors { top: parent.top; right: close.left; rightMargin: 10 }
- MouseArea {
- id: touchMouseArea
- anchors.fill: parent
- onClicked: {
- if (root.state == "") {
- root.state = "show";
- } else {
- root.state = "";
- }
- }
- }
- }
-
- Rectangle {
- id: close
- width: 50
- height: 50
- color: "black"
- radius: 0
- opacity: 0.3
- anchors { top: parent.top; topMargin: 0; right: parent.right; rightMargin: 0 }
- MouseArea {
- id: closeMouseArea
- anchors.fill: parent
- onClicked: Qt.quit();
- }
- }
- }
-
- states: State {
- name: "show"
- PropertyChanges { target: posterText; y: root.height / 3 }
- PropertyChanges { target: posterUrl; y: 2 * root.height / 3 }
- PropertyChanges { target: posterImage; x: root.width / 20 }
- PropertyChanges { target: touchText; opacity: 0 }
- }
-
-
- transitions: Transition {
- PropertyAnimation { easing.type: Easing.OutQuad; properties: "x,y" }
- PropertyAnimation { property: "opacity"; duration: 125 }
- }
-}
diff --git a/examples/nfc/poster/poster.qrc b/examples/nfc/poster/poster.qrc
deleted file mode 100644
index 7bb30667..00000000
--- a/examples/nfc/poster/poster.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>poster.qml</file>
- </qresource>
-</RCC>
diff --git a/examples/nfc/poster/qmlposter.cpp b/examples/nfc/poster/qmlposter.cpp
deleted file mode 100644
index a4f98de3..00000000
--- a/examples/nfc/poster/qmlposter.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module 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$
-**
-****************************************************************************/
-
-#include <QtGui/QGuiApplication>
-#include <QtQml/QQmlEngine>
-#include <QtQuick/QQuickView>
-
-int main(int argc, char *argv[])
-{
- QGuiApplication application(argc, argv);
- const QString mainQmlApp(QStringLiteral("qrc:/poster.qml"));
- QQuickView view;
- view.setSource(QUrl(mainQmlApp));
- view.setResizeMode(QQuickView::SizeRootObjectToView);
- // Qt.quit() called in embedded .qml by default only emits
- // quit() signal, so do this (optionally use Qt.exit()).
- QObject::connect(view.engine(), &QQmlEngine::quit, qApp, &QGuiApplication::quit);
- view.setGeometry(QRect(100, 100, 640, 360));
- view.show();
- return application.exec();
-}
diff --git a/licenseRule.json b/licenseRule.json
new file mode 100644
index 00000000..7a96fb25
--- /dev/null
+++ b/licenseRule.json
@@ -0,0 +1,94 @@
+[
+ {
+ "comment" : ["file_pattern_ending: strings matched against the end of a file name.",
+ "location keys: regular expression matched against the beginning of",
+ "the file path (relative to the git submodule root).",
+ "spdx: list of SPDX-License-Expression's allowed in the matching files.",
+ "-------------------------------------------------------",
+ "Files with the following endings are Build System licensed,",
+ "unless they are examples",
+ "Files with other endings can also be build system files"
+ ],
+ "file_pattern_ending" : ["CMakeLists.txt", ".cmake", ".pro", ".pri", ".prf",
+ "configure", "configure.bat", "cmake.in", "plist.in", "CMakeLists.txt.in"],
+ "location" : {
+ "" : {
+ "comment" : "Default",
+ "file type" : "build system",
+ "spdx" : ["BSD-3-Clause"]
+ },
+ "(.*)(examples/|snippets/)" : {
+ "comment" : "Example takes precedent",
+ "file type" : "examples and snippets",
+ "spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
+ }
+ }
+ },
+ {
+ "comments" : ["Files with the following endings are Tool licensed,",
+ "unless they are examples.",
+ "Files with other endings can also be tool files."],
+ "file_pattern_ending" : [".sh", ".py", ".pl", ".bat", ".ps1"],
+ "location" :{
+ "" : {
+ "comment" : "Default",
+ "file type" : "tools and utils",
+ "spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0"]
+ },
+ "(.*)(examples/|snippets/)" : {
+ "comment" : "Example takes precedent",
+ "file type" : "examples and snippets",
+ "spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
+ }
+ }
+ },
+ {
+ "comment" : "Files with the following endings are Documentation licensed.",
+ "file_pattern_ending" : [".qdoc", ".qdocinc" , ".qdocconf", ".txt", "README", "qt_attribution.json"],
+ "location" :{
+ "" : {
+ "comment" : "",
+ "file type" : "documentation",
+ "spdx" : ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"]
+ }
+ }
+ },
+ {
+ "comment" : ["All other files",
+ "The licensing is defined only by the file location in the Qt module repository.",
+ "NO <file_pattern_ending> key for this case!",
+ "This needs to be the last entry of the file."],
+ "location" : {
+ "" : {
+ "comment" : "Default",
+ "file type" : "module and plugin",
+ "spdx" : ["LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only"]
+ },
+ "src/" : {
+ "comment" : "Default",
+ "file type" : "module and plugin",
+ "spdx" : ["LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only"]
+ },
+ "src/tools/" : {
+ "comment" : "Default",
+ "file type" : "tools and utils",
+ "spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0"]
+ },
+ "tests/" : {
+ "comment" : "Default",
+ "file type" : "test",
+ "spdx" : ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
+ },
+ "(.*)(examples/|snippets/)" : {
+ "comment" : "Default",
+ "file type" : "examples and snippets",
+ "spdx" : ["LicenseRef-Qt-Commercial OR BSD-3-Clause"]
+ },
+ "config\\.tests/" : {
+ "comment" : "Default",
+ "file type" : "build system",
+ "spdx" : ["BSD-3-Clause"]
+ }
+ }
+ }
+]
diff --git a/qtconnectivity.pro b/qtconnectivity.pro
deleted file mode 100644
index 6e590928..00000000
--- a/qtconnectivity.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-requires(qtHaveModule(network))
-requires(!android|qtHaveModule(androidextras))
-
-
-load(qt_parts)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 00000000..e23f22dd
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+add_subdirectory(bluetooth)
+add_subdirectory(nfc)
+if(ANDROID)
+ add_subdirectory(android)
+endif()
+
+if(QT_FEATURE_bluez)
+ add_subdirectory(tools/sdpscanner)
+endif()
diff --git a/src/android/CMakeLists.txt b/src/android/CMakeLists.txt
new file mode 100644
index 00000000..a8b61270
--- /dev/null
+++ b/src/android/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(TARGET Qt::Bluetooth)
+ add_subdirectory(bluetooth)
+endif()
+if(TARGET Qt::Nfc)
+ add_subdirectory(nfc)
+endif()
diff --git a/src/android/android.pro b/src/android/android.pro
deleted file mode 100644
index f8f5c05e..00000000
--- a/src/android/android.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-TEMPLATE = subdirs
-qtHaveModule(bluetooth): SUBDIRS += bluetooth
-qtHaveModule(nfc): SUBDIRS += nfc
diff --git a/src/android/bluetooth/AndroidManifest.xml b/src/android/bluetooth/AndroidManifest.xml
index 9148e171..27355299 100644
--- a/src/android/bluetooth/AndroidManifest.xml
+++ b/src/android/bluetooth/AndroidManifest.xml
@@ -2,6 +2,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
- package="org.qtproject.qt5.android.bluetooth">
+ package="org.qtproject.qt.android.bluetooth">
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
</manifest>
diff --git a/src/android/bluetooth/CMakeLists.txt b/src/android/bluetooth/CMakeLists.txt
new file mode 100644
index 00000000..f8692576
--- /dev/null
+++ b/src/android/bluetooth/CMakeLists.txt
@@ -0,0 +1,27 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+set(java_sources
+ src/org/qtproject/qt/android/bluetooth/QtBluetoothBroadcastReceiver.java
+ src/org/qtproject/qt/android/bluetooth/QtBluetoothInputStreamThread.java
+ src/org/qtproject/qt/android/bluetooth/QtBluetoothLE.java
+ src/org/qtproject/qt/android/bluetooth/QtBluetoothLEServer.java
+ src/org/qtproject/qt/android/bluetooth/QtBluetoothSocketServer.java
+ src/org/qtproject/qt/android/bluetooth/QtBluetoothGattCharacteristic.java
+ src/org/qtproject/qt/android/bluetooth/QtBluetoothGattDescriptor.java
+)
+
+qt_internal_add_jar(Qt${QtConnectivity_VERSION_MAJOR}AndroidBluetooth
+ INCLUDE_JARS ${QT_ANDROID_JAR}
+ SOURCES ${java_sources}
+ OUTPUT_DIR "${QT_BUILD_DIR}/jar"
+)
+
+qt_path_join(destination ${INSTALL_DATADIR} "jar")
+
+install_jar(Qt${QtConnectivity_VERSION_MAJOR}AndroidBluetooth
+ DESTINATION ${destination}
+ COMPONENT Devel
+)
+
+add_dependencies(Bluetooth Qt${QtConnectivity_VERSION_MAJOR}AndroidBluetooth)
diff --git a/src/android/bluetooth/bluetooth.pro b/src/android/bluetooth/bluetooth.pro
deleted file mode 100644
index b76b392c..00000000
--- a/src/android/bluetooth/bluetooth.pro
+++ /dev/null
@@ -1,19 +0,0 @@
-TARGET = QtAndroidBluetooth
-
-CONFIG += java
-DESTDIR = $$[QT_INSTALL_PREFIX/get]/jar
-API_VERSION = android-21
-
-PATHPREFIX = $$PWD/src/org/qtproject/qt5/android/bluetooth
-
-JAVACLASSPATH += $$PWD/src/
-JAVASOURCES += \
- $$PATHPREFIX/QtBluetoothBroadcastReceiver.java \
- $$PATHPREFIX/QtBluetoothSocketServer.java \
- $$PATHPREFIX/QtBluetoothInputStreamThread.java \
- $$PATHPREFIX/QtBluetoothLE.java \
- $$PATHPREFIX/QtBluetoothLEServer.java
-
-# install
-target.path = $$[QT_INSTALL_PREFIX]/jar
-INSTALLS += target
diff --git a/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothBroadcastReceiver.java b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothBroadcastReceiver.java
new file mode 100644
index 00000000..6c74c3e3
--- /dev/null
+++ b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothBroadcastReceiver.java
@@ -0,0 +1,187 @@
+// 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
+
+package org.qtproject.qt.android.bluetooth;
+
+import android.app.Activity;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.List;
+
+public class QtBluetoothBroadcastReceiver extends BroadcastReceiver
+{
+ /* Pointer to the Qt object that "owns" the Java object */
+ @SuppressWarnings("WeakerAccess")
+ long qtObject = 0;
+ @SuppressWarnings("WeakerAccess")
+ static Context qtContext = null;
+
+ // These are opaque tokens that could be used to match the completed action
+ private static final int TURN_BT_ENABLED = 3330;
+ private static final int TURN_BT_DISCOVERABLE = 3331;
+ private static final int TURN_BT_DISABLED = 3332;
+
+ // The 'Disable' action identifier is hidden in the public APIs so we define it here
+ public static final String ACTION_REQUEST_DISABLE =
+ "android.bluetooth.adapter.action.REQUEST_DISABLE";
+
+ private static final String TAG = "QtBluetoothBroadcastReceiver";
+
+ public void onReceive(Context context, Intent intent)
+ {
+ synchronized (qtContext) {
+ if (qtObject == 0)
+ return;
+
+ jniOnReceive(qtObject, context, intent);
+ }
+ }
+
+ public void unregisterReceiver()
+ {
+ synchronized (qtContext) {
+ qtObject = 0;
+ try {
+ qtContext.unregisterReceiver(this);
+ } catch (Exception ex) {
+ Log.d(TAG, "Trying to unregister a BroadcastReceiver which is not yet registered");
+ }
+ }
+ }
+
+ public native void jniOnReceive(long qtObject, Context context, Intent intent);
+
+ static public void setContext(Context context)
+ {
+ qtContext = context;
+ }
+
+ static public boolean setDisabled()
+ {
+ if (!(qtContext instanceof android.app.Activity)) {
+ Log.w(TAG, "Bluetooth cannot be disabled from a service.");
+ return false;
+ }
+ // The 'disable' is hidden in the public API and as such
+ // there are no availability guarantees; may throw an "ActivityNotFoundException"
+ Intent intent = new Intent(ACTION_REQUEST_DISABLE);
+
+ try {
+ ((Activity)qtContext).startActivityForResult(intent, TURN_BT_DISABLED);
+ } catch (Exception ex) {
+ Log.w(TAG, "setDisabled() failed to initiate Bluetooth disablement");
+ ex.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ static public boolean setDiscoverable()
+ {
+ if (!(qtContext instanceof android.app.Activity)) {
+ Log.w(TAG, "Discovery mode cannot be enabled from a service.");
+ return false;
+ }
+
+ Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
+ intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
+ try {
+ ((Activity)qtContext).startActivityForResult(intent, TURN_BT_DISCOVERABLE);
+ } catch (Exception ex) {
+ Log.w(TAG, "setDiscoverable() failed to initiate Bluetooth discoverability change");
+ ex.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ static public boolean setEnabled()
+ {
+ if (!(qtContext instanceof android.app.Activity)) {
+ Log.w(TAG, "Bluetooth cannot be enabled from a service.");
+ return false;
+ }
+
+ Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+ try {
+ ((Activity)qtContext).startActivityForResult(intent, TURN_BT_ENABLED);
+ } catch (Exception ex) {
+ Log.w(TAG, "setEnabled() failed to initiate Bluetooth enablement");
+ ex.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ static public boolean setPairingMode(String address, boolean isPairing)
+ {
+ BluetoothManager manager =
+ (BluetoothManager)qtContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ if (manager == null)
+ return false;
+
+ BluetoothAdapter adapter = manager.getAdapter();
+ if (adapter == null)
+ return false;
+
+ // Uses reflection as the removeBond() is not part of public API
+ try {
+ BluetoothDevice device = adapter.getRemoteDevice(address);
+ String methodName = "createBond";
+ if (!isPairing)
+ methodName = "removeBond";
+
+ Method m = device.getClass()
+ .getMethod(methodName, (Class[]) null);
+ m.invoke(device, (Object[]) null);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return false;
+ }
+
+ return true;
+ }
+
+ /*
+ * Returns a list of remote devices confirmed to be connected.
+ *
+ * This list is not complete as it only detects GATT/BtLE related connections.
+ * Unfortunately there is no API that provides the complete list.
+ *
+ */
+ static public String[] getConnectedDevices()
+ {
+ BluetoothManager bluetoothManager =
+ (BluetoothManager) qtContext.getSystemService(Context.BLUETOOTH_SERVICE);
+
+ if (bluetoothManager == null) {
+ Log.w(TAG, "Failed to retrieve connected devices");
+ return new String[0];
+ }
+
+ List<BluetoothDevice> gattConnections =
+ bluetoothManager.getConnectedDevices(BluetoothProfile.GATT);
+ List<BluetoothDevice> gattServerConnections =
+ bluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER);
+
+ // Process found remote connections but avoid duplications
+ HashSet<String> set = new HashSet<String>();
+ for (Object gattConnection : gattConnections)
+ set.add(gattConnection.toString());
+
+ for (Object gattServerConnection : gattServerConnections)
+ set.add(gattServerConnection.toString());
+
+ return set.toArray(new String[set.size()]);
+ }
+}
diff --git a/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothGattCharacteristic.java b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothGattCharacteristic.java
new file mode 100644
index 00000000..375aebb5
--- /dev/null
+++ b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothGattCharacteristic.java
@@ -0,0 +1,44 @@
+// 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
+
+package org.qtproject.qt.android.bluetooth;
+
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.os.Build;
+
+import java.util.UUID;
+
+public class QtBluetoothGattCharacteristic extends BluetoothGattCharacteristic {
+ public QtBluetoothGattCharacteristic(UUID uuid, int properties, int permissions,
+ int minimumValueLength, int maximumValueLength) {
+ super(uuid, properties, permissions);
+ minValueLength = minimumValueLength;
+ maxValueLength = maximumValueLength;
+ }
+ public int minValueLength;
+ public int maxValueLength;
+ // Starting from API 33 Android Bluetooth deprecates characteristic local value caching by
+ // deprecating the getValue() and setValue() accessors. For peripheral role we store the value
+ // locally in the characteristic as a convenience - looking up the value on the C++ side would
+ // be somewhat complicated. This should be safe as all accesses to this class are synchronized.
+ // For clarity: For API levels below 33 we still need to use the setValue() of the base class
+ // because Android internally uses getValue() with APIs below 33.
+ public boolean setLocalValue(byte[] value) {
+ if (Build.VERSION.SDK_INT >= 33) {
+ m_localValue = value;
+ return true;
+ } else {
+ return setValue(value);
+ }
+ }
+
+ public byte[] getLocalValue()
+ {
+ if (Build.VERSION.SDK_INT >= 33)
+ return m_localValue;
+ else
+ return getValue();
+ }
+
+ private byte[] m_localValue = null;
+}
diff --git a/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothGattDescriptor.java b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothGattDescriptor.java
new file mode 100644
index 00000000..10194ea4
--- /dev/null
+++ b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothGattDescriptor.java
@@ -0,0 +1,39 @@
+// 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
+
+package org.qtproject.qt.android.bluetooth;
+
+import android.bluetooth.BluetoothGattDescriptor;
+import android.os.Build;
+
+import java.util.UUID;
+
+public class QtBluetoothGattDescriptor extends BluetoothGattDescriptor {
+ public QtBluetoothGattDescriptor(UUID uuid, int permissions) {
+ super(uuid, permissions);
+ }
+ // Starting from API 33 Android Bluetooth deprecates descriptor local value caching by
+ // deprecating the getValue() and setValue() accessors. For peripheral role we store the value
+ // locally in the descriptor as a convenience - looking up the value on the C++ side would
+ // be somewhat complicated. This should be safe as all accesses to this class are synchronized.
+ // For clarity: For API levels below 33 we still need to use the setValue() of the base class
+ // because Android internally uses getValue() with APIs below 33.
+ public boolean setLocalValue(byte[] value) {
+ if (Build.VERSION.SDK_INT >= 33) {
+ m_localValue = value;
+ return true;
+ } else {
+ return setValue(value);
+ }
+ }
+
+ public byte[] getLocalValue()
+ {
+ if (Build.VERSION.SDK_INT >= 33)
+ return m_localValue;
+ else
+ return getValue();
+ }
+
+ private byte[] m_localValue = null;
+}
diff --git a/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothInputStreamThread.java b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothInputStreamThread.java
new file mode 100644
index 00000000..0fd6f292
--- /dev/null
+++ b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothInputStreamThread.java
@@ -0,0 +1,68 @@
+// 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
+
+package org.qtproject.qt.android.bluetooth;
+
+import java.io.InputStream;
+import java.io.IOException;
+import android.util.Log;
+
+@SuppressWarnings("WeakerAccess")
+public class QtBluetoothInputStreamThread extends Thread
+{
+ /* Pointer to the Qt object that "owns" the Java object */
+ @SuppressWarnings("CanBeFinal")
+ long qtObject = 0;
+ @SuppressWarnings("CanBeFinal")
+ public boolean logEnabled = false;
+ private static final String TAG = "QtBluetooth";
+ private InputStream m_inputStream = null;
+
+ //error codes
+ public static final int QT_MISSING_INPUT_STREAM = 0;
+ public static final int QT_READ_FAILED = 1;
+ public static final int QT_THREAD_INTERRUPTED = 2;
+
+ public QtBluetoothInputStreamThread()
+ {
+ setName("QtBtInputStreamThread");
+ }
+
+ public void setInputStream(InputStream stream)
+ {
+ m_inputStream = stream;
+ }
+
+ public void run()
+ {
+ if (m_inputStream == null) {
+ errorOccurred(qtObject, QT_MISSING_INPUT_STREAM);
+ return;
+ }
+
+ byte[] buffer = new byte[1000];
+ int bytesRead;
+
+ try {
+ while (!isInterrupted()) {
+ //this blocks until we see incoming data
+ //or close() on related BluetoothSocket is called
+ bytesRead = m_inputStream.read(buffer);
+ readyData(qtObject, buffer, bytesRead);
+ }
+
+ errorOccurred(qtObject, QT_THREAD_INTERRUPTED);
+ } catch (IOException ex) {
+ if (logEnabled)
+ Log.d(TAG, "InputStream.read() failed:" + ex.toString());
+ ex.printStackTrace();
+ errorOccurred(qtObject, QT_READ_FAILED);
+ }
+
+ if (logEnabled)
+ Log.d(TAG, "Leaving input stream thread");
+ }
+
+ public static native void errorOccurred(long qtObject, int errorCode);
+ public static native void readyData(long qtObject, byte[] buffer, int bufferLength);
+}
diff --git a/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLE.java b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLE.java
new file mode 100644
index 00000000..0e612add
--- /dev/null
+++ b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLE.java
@@ -0,0 +1,1837 @@
+// 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
+
+package org.qtproject.qt.android.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallback;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
+import android.bluetooth.BluetoothStatusCodes;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.util.Log;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.UUID;
+
+
+public class QtBluetoothLE {
+ private static final String TAG = "QtBluetoothGatt";
+ private BluetoothAdapter mBluetoothAdapter = null;
+ private boolean mLeScanRunning = false;
+
+ private BluetoothGatt mBluetoothGatt = null;
+ private HandlerThread mHandlerThread = null;
+ private Handler mHandler = null;
+ private Constructor mCharacteristicConstructor = null;
+ private String mRemoteGattAddress;
+ private final UUID clientCharacteristicUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
+ private final int MAX_MTU = 512;
+ private final int DEFAULT_MTU = 23;
+ private int mSupportedMtu = -1;
+
+ /*
+ * The atomic synchronizes the timeoutRunnable thread and the response thread for the pending
+ * I/O job. Whichever thread comes first will pass the atomic gate. The other thread is
+ * cut short.
+ */
+ // handle values above zero are for regular handle specific read/write requests
+ // handle values below zero are reserved for handle-independent requests
+ private int HANDLE_FOR_RESET = -1;
+ private int HANDLE_FOR_MTU_EXCHANGE = -2;
+ private int HANDLE_FOR_RSSI_READ = -3;
+ private AtomicInteger handleForTimeout = new AtomicInteger(HANDLE_FOR_RESET); // implies not running by default
+
+ private final int RUNNABLE_TIMEOUT = 3000; // 3 seconds
+ private final Handler timeoutHandler = new Handler(Looper.getMainLooper());
+
+ private BluetoothLeScanner mBluetoothLeScanner = null;
+
+ private class TimeoutRunnable implements Runnable {
+ public TimeoutRunnable(int handle) { pendingJobHandle = handle; }
+ @Override
+ public void run() {
+ boolean timeoutStillValid = handleForTimeout.compareAndSet(pendingJobHandle, HANDLE_FOR_RESET);
+ if (timeoutStillValid) {
+ Log.w(TAG, "****** Timeout for request on handle " + (pendingJobHandle & 0xffff));
+ Log.w(TAG, "****** Looks like the peripheral does NOT act in " +
+ "accordance to Bluetooth 4.x spec.");
+ Log.w(TAG, "****** Please check server implementation. Continuing under " +
+ "reservation.");
+
+ if (pendingJobHandle > HANDLE_FOR_RESET)
+ interruptCurrentIO(pendingJobHandle & 0xffff);
+ else if (pendingJobHandle < HANDLE_FOR_RESET)
+ interruptCurrentIO(pendingJobHandle);
+ }
+ }
+
+ // contains handle (0xffff) and top 2 byte contain the job type (0xffff0000)
+ private int pendingJobHandle = -1;
+ };
+
+ // The handleOn* functions in this class are callback handlers which are synchronized
+ // to "this" client object. This protects the member variables which could be
+ // concurrently accessed from Qt (JNI) thread and different Java threads *)
+ // *) The newer Android API (starting Android 8.1) synchronizes callbacks to one
+ // Java thread, but this is not true for the earlier API which we still support.
+ //
+ // In case bond state has been changed due to access to a restricted handle,
+ // Android never completes the operation which triggered the devices to bind
+ // and thus never fires on(Characteristic|Descriptor)(Read|Write) callback,
+ // causing TimeoutRunnable to interrupt pending job,
+ // albeit the read/write job hasn't been actually executed by the peripheral;
+ // re-add the currently pending job to the queue's head and re-run it.
+ // If, by some reason, bonding process has been interrupted, either
+ // re-add the currently pending job to the queue's head and re-run it.
+ private synchronized void handleOnReceive(Context context, Intent intent)
+ {
+ if (mBluetoothGatt == null)
+ return;
+
+ final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (device == null || !device.getAddress().equals(mBluetoothGatt.getDevice().getAddress()))
+ return;
+
+ final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
+ final int previousBondState =
+ intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);
+
+ if (bondState == BluetoothDevice.BOND_BONDING) {
+ if (pendingJob == null
+ || pendingJob.jobType == IoJobType.Mtu || pendingJob.jobType == IoJobType.Rssi) {
+ return;
+ }
+
+ timeoutHandler.removeCallbacksAndMessages(null);
+ handleForTimeout.set(HANDLE_FOR_RESET);
+ } else if (previousBondState == BluetoothDevice.BOND_BONDING &&
+ (bondState == BluetoothDevice.BOND_BONDED || bondState == BluetoothDevice.BOND_NONE)) {
+ if (pendingJob == null
+ || pendingJob.jobType == IoJobType.Mtu || pendingJob.jobType == IoJobType.Rssi) {
+ return;
+ }
+
+ readWriteQueue.addFirst(pendingJob);
+ pendingJob = null;
+
+ performNextIO();
+ } else if (previousBondState == BluetoothDevice.BOND_BONDED
+ && bondState == BluetoothDevice.BOND_NONE) {
+ // peripheral or central removed the bond information;
+ // if it was peripheral, the connection attempt would fail with PIN_OR_KEY_MISSING,
+ // which is handled by Android by broadcasting ACTION_BOND_STATE_CHANGED
+ // with new state BOND_NONE, without actually deleting the bond information :facepalm:
+ // if we get there, it is safer to delete it now, by invoking the undocumented API call
+ try {
+ device.getClass().getMethod("removeBond").invoke(device);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ private class BondStateBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ handleOnReceive(context, intent);
+ }
+ };
+ private BroadcastReceiver bondStateBroadcastReceiver = null;
+
+ /* Pointer to the Qt object that "owns" the Java object */
+ @SuppressWarnings({"CanBeFinal", "WeakerAccess"})
+ long qtObject = 0;
+ @SuppressWarnings("WeakerAccess")
+ Context qtContext = null;
+
+ @SuppressWarnings("WeakerAccess")
+ public QtBluetoothLE(Context context) {
+ qtContext = context;
+
+ BluetoothManager manager =
+ (BluetoothManager)qtContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ if (manager == null)
+ return;
+
+ mBluetoothAdapter = manager.getAdapter();
+ if (mBluetoothAdapter == null)
+ return;
+
+ mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
+ }
+
+ public QtBluetoothLE(final String remoteAddress, Context context) {
+ this(context);
+ mRemoteGattAddress = remoteAddress;
+ }
+
+ /*************************************************************/
+ /* Device scan */
+ /* Returns true, if request was successfully completed */
+ /* This function is called from Qt thread, but only accesses */
+ /* variables that are not accessed from Java threads */
+ /*************************************************************/
+
+ public boolean scanForLeDevice(final boolean isEnabled) {
+ if (isEnabled == mLeScanRunning)
+ return true;
+
+ if (mBluetoothLeScanner == null) {
+ Log.w(TAG, "Cannot start LE scan, no bluetooth scanner");
+ return false;
+ }
+
+ if (isEnabled) {
+ Log.d(TAG, "Attempting to start BTLE scan");
+ ScanSettings.Builder settingsBuilder = new ScanSettings.Builder();
+ settingsBuilder = settingsBuilder.setScanMode(ScanSettings.SCAN_MODE_BALANCED);
+ ScanSettings settings = settingsBuilder.build();
+
+ List<ScanFilter> filterList = new ArrayList<ScanFilter>();
+
+ mBluetoothLeScanner.startScan(filterList, settings, leScanCallback);
+ mLeScanRunning = true;
+ } else {
+ Log.d(TAG, "Attempting to stop BTLE scan");
+ try {
+ mBluetoothLeScanner.stopScan(leScanCallback);
+ } catch (IllegalStateException isex) {
+ // when trying to stop a scan while bluetooth is offline
+ // java.lang.IllegalStateException: BT Adapter is not turned ON
+ Log.d(TAG, "Stopping LE scan not possible: " + isex.getMessage());
+ }
+ mLeScanRunning = false;
+ }
+
+ return (mLeScanRunning == isEnabled);
+ }
+
+ private final ScanCallback leScanCallback = new ScanCallback() {
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ super.onScanResult(callbackType, result);
+ leScanResult(qtObject, result.getDevice(), result.getRssi(), result.getScanRecord().getBytes());
+ }
+
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ super.onBatchScanResults(results);
+ for (ScanResult result : results)
+ leScanResult(qtObject, result.getDevice(), result.getRssi(), result.getScanRecord().getBytes());
+
+ }
+
+ @Override
+ public void onScanFailed(int errorCode) {
+ super.onScanFailed(errorCode);
+ Log.d(TAG, "BTLE device scan failed with " + errorCode);
+ }
+ };
+
+ public native void leScanResult(long qtObject, BluetoothDevice device, int rssi, byte[] scanRecord);
+
+ private synchronized void handleOnConnectionStateChange(BluetoothGatt gatt,
+ int status, int newState) {
+
+ Log.d(TAG, "Connection state changes to: " + newState + ", status: " + status
+ + ", qtObject: " + (qtObject != 0));
+ if (qtObject == 0)
+ return;
+
+ int qLowEnergyController_State = 0;
+ //This must be in sync with QLowEnergyController::ControllerState
+ switch (newState) {
+ case BluetoothProfile.STATE_DISCONNECTED:
+ if (bondStateBroadcastReceiver != null) {
+ qtContext.unregisterReceiver(bondStateBroadcastReceiver);
+ bondStateBroadcastReceiver = null;
+ }
+
+ qLowEnergyController_State = 0;
+ // we disconnected -> get rid of data from previous run
+ resetData();
+ // reset mBluetoothGatt, reusing same object is not very reliable
+ // sometimes it reconnects and sometimes it does not.
+ if (mBluetoothGatt != null) {
+ mBluetoothGatt.close();
+ if (mHandler != null) {
+ mHandler.getLooper().quitSafely();
+ mHandler = null;
+ }
+ }
+ mBluetoothGatt = null;
+ break;
+ case BluetoothProfile.STATE_CONNECTED:
+ if (bondStateBroadcastReceiver == null) {
+ bondStateBroadcastReceiver = new BondStateBroadcastReceiver();
+ qtContext.registerReceiver(bondStateBroadcastReceiver,
+ new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
+ }
+ qLowEnergyController_State = 2;
+ }
+
+ //This must be in sync with QLowEnergyController::Error
+ int errorCode;
+ switch (status) {
+ case BluetoothGatt.GATT_SUCCESS:
+ errorCode = 0; //QLowEnergyController::NoError
+ break;
+ case BluetoothGatt.GATT_FAILURE: // Android's equivalent of "do not know what error"
+ errorCode = 1; //QLowEnergyController::UnknownError
+ break;
+ case 8: // BLE_HCI_CONNECTION_TIMEOUT
+ Log.w(TAG, "Connection Error: Try to delay connect() call after previous activity");
+ errorCode = 5; //QLowEnergyController::ConnectionError
+ break;
+ case 19: // BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION
+ case 20: // BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES
+ case 21: // BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF
+ Log.w(TAG, "The remote host closed the connection");
+ errorCode = 7; //QLowEnergyController::RemoteHostClosedError
+ break;
+ case 22: // BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION
+ // Internally, Android maps PIN_OR_KEY_MISSING to GATT_CONN_TERMINATE_LOCAL_HOST
+ errorCode = 8; //QLowEnergyController::AuthorizationError
+ break;
+ default:
+ Log.w(TAG, "Unhandled error code on connectionStateChanged: "
+ + status + " " + newState);
+ errorCode = status;
+ break; //TODO deal with all errors
+ }
+ leConnectionStateChange(qtObject, errorCode, qLowEnergyController_State);
+ }
+
+ private synchronized void handleOnServicesDiscovered(BluetoothGatt gatt, int status) {
+ //This must be in sync with QLowEnergyController::Error
+ int errorCode;
+ StringBuilder builder = new StringBuilder();
+ switch (status) {
+ case BluetoothGatt.GATT_SUCCESS:
+ errorCode = 0; //QLowEnergyController::NoError
+ final List<BluetoothGattService> services = mBluetoothGatt.getServices();
+ for (BluetoothGattService service: services) {
+ builder.append(service.getUuid().toString()).append(" "); //space is separator
+ }
+ break;
+ default:
+ Log.w(TAG, "Unhandled error code on onServicesDiscovered: " + status);
+ errorCode = status; break; //TODO deal with all errors
+ }
+ leServicesDiscovered(qtObject, errorCode, builder.toString());
+ if (status == BluetoothGatt.GATT_SUCCESS)
+ scheduleMtuExchange();
+ }
+
+ private synchronized void handleOnCharacteristicRead(BluetoothGatt gatt,
+ BluetoothGattCharacteristic characteristic,
+ byte[] value,
+ int status)
+ {
+ int foundHandle = handleForCharacteristic(characteristic);
+ if (foundHandle == -1 || foundHandle >= entries.size() ) {
+ Log.w(TAG, "Cannot find characteristic read request for read notification - handle: " +
+ foundHandle + " size: " + entries.size());
+
+ //unlock the queue for next item
+ pendingJob = null;
+
+ performNextIO();
+ return;
+ }
+
+ boolean requestTimedOut = !handleForTimeout.compareAndSet(
+ modifiedReadWriteHandle(foundHandle, IoJobType.Read),
+ HANDLE_FOR_RESET);
+ if (requestTimedOut) {
+ Log.w(TAG, "Late char read reply after timeout was hit for handle " + foundHandle);
+ // Timeout has hit before this response -> ignore the response
+ // no need to unlock pendingJob -> the timeout has done that already
+ return;
+ }
+
+ GattEntry entry = entries.get(foundHandle);
+ final boolean isServiceDiscoveryRun = !entry.valueKnown;
+ entry.valueKnown = true;
+
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ // Qt manages handles starting at 1, in Java we use a system starting with 0
+ //TODO avoid sending service uuid -> service handle should be sufficient
+ leCharacteristicRead(qtObject,
+ characteristic.getService().getUuid().toString(),
+ foundHandle + 1, characteristic.getUuid().toString(),
+ characteristic.getProperties(), value);
+ } else {
+ if (isServiceDiscoveryRun) {
+ Log.w(TAG, "onCharacteristicRead during discovery error: " + status);
+
+ Log.d(TAG, "Non-readable characteristic " + characteristic.getUuid() +
+ " for service " + characteristic.getService().getUuid());
+ leCharacteristicRead(qtObject, characteristic.getService().getUuid().toString(),
+ foundHandle + 1, characteristic.getUuid().toString(),
+ characteristic.getProperties(), value);
+ } else {
+ // This must be in sync with QLowEnergyService::CharacteristicReadError
+ final int characteristicReadError = 5;
+ leServiceError(qtObject, foundHandle + 1, characteristicReadError);
+ }
+ }
+
+ if (isServiceDiscoveryRun) {
+
+ // last entry of pending service discovery run -> send discovery finished state update
+ GattEntry serviceEntry = entries.get(entry.associatedServiceHandle);
+ if (serviceEntry.endHandle == foundHandle)
+ finishCurrentServiceDiscovery(entry.associatedServiceHandle);
+ }
+
+ //unlock the queue for next item
+ pendingJob = null;
+
+ performNextIO();
+ }
+
+ private synchronized void handleOnCharacteristicChanged(android.bluetooth.BluetoothGatt gatt,
+ android.bluetooth.BluetoothGattCharacteristic characteristic,
+ byte[] value)
+ {
+ int handle = handleForCharacteristic(characteristic);
+ if (handle == -1) {
+ Log.w(TAG,"onCharacteristicChanged: cannot find handle");
+ return;
+ }
+
+ leCharacteristicChanged(qtObject, handle+1, value);
+ }
+
+ private synchronized void handleOnCharacteristicWrite(android.bluetooth.BluetoothGatt gatt,
+ android.bluetooth.BluetoothGattCharacteristic characteristic,
+ int status)
+ {
+ if (status != BluetoothGatt.GATT_SUCCESS)
+ Log.w(TAG, "onCharacteristicWrite: error " + status);
+
+ int handle = handleForCharacteristic(characteristic);
+ if (handle == -1) {
+ Log.w(TAG,"onCharacteristicWrite: cannot find handle");
+ return;
+ }
+
+ boolean requestTimedOut = !handleForTimeout.compareAndSet(
+ modifiedReadWriteHandle(handle, IoJobType.Write),
+ HANDLE_FOR_RESET);
+ if (requestTimedOut) {
+ Log.w(TAG, "Late char write reply after timeout was hit for handle " + handle);
+ // Timeout has hit before this response -> ignore the response
+ // no need to unlock pendingJob -> the timeout has done that already
+ return;
+ }
+
+ int errorCode;
+ //This must be in sync with QLowEnergyService::ServiceError
+ switch (status) {
+ case BluetoothGatt.GATT_SUCCESS:
+ errorCode = 0;
+ break; // NoError
+ default:
+ errorCode = 2;
+ break; // CharacteristicWriteError
+ }
+
+ byte[] value;
+ value = pendingJob.newValue;
+ pendingJob = null;
+
+ leCharacteristicWritten(qtObject, handle+1, value, errorCode);
+ performNextIO();
+ }
+
+ private synchronized void handleOnDescriptorRead(android.bluetooth.BluetoothGatt gatt,
+ android.bluetooth.BluetoothGattDescriptor descriptor,
+ int status, byte[] newValue)
+ {
+ int foundHandle = handleForDescriptor(descriptor);
+ if (foundHandle == -1 || foundHandle >= entries.size() ) {
+ Log.w(TAG, "Cannot find descriptor read request for read notification - handle: " +
+ foundHandle + " size: " + entries.size());
+
+ //unlock the queue for next item
+ pendingJob = null;
+
+ performNextIO();
+ return;
+ }
+
+ boolean requestTimedOut = !handleForTimeout.compareAndSet(
+ modifiedReadWriteHandle(foundHandle, IoJobType.Read),
+ HANDLE_FOR_RESET);
+ if (requestTimedOut) {
+ Log.w(TAG, "Late descriptor read reply after timeout was hit for handle " +
+ foundHandle);
+ // Timeout has hit before this response -> ignore the response
+ // no need to unlock pendingJob -> the timeout has done that already
+ return;
+ }
+
+ GattEntry entry = entries.get(foundHandle);
+ final boolean isServiceDiscoveryRun = !entry.valueKnown;
+ entry.valueKnown = true;
+
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ //TODO avoid sending service and characteristic uuid -> handles should be sufficient
+ leDescriptorRead(qtObject,
+ descriptor.getCharacteristic().getService().getUuid().toString(),
+ descriptor.getCharacteristic().getUuid().toString(), foundHandle + 1,
+ descriptor.getUuid().toString(), newValue);
+ } else {
+ if (isServiceDiscoveryRun) {
+ // Cannot read but still advertise the fact that we found a descriptor
+ // The value will be empty.
+ Log.w(TAG, "onDescriptorRead during discovery error: " + status);
+ Log.d(TAG, "Non-readable descriptor " + descriptor.getUuid() +
+ " for characteristic " + descriptor.getCharacteristic().getUuid() +
+ " for service " + descriptor.getCharacteristic().getService().getUuid());
+ leDescriptorRead(qtObject,
+ descriptor.getCharacteristic().getService().getUuid().toString(),
+ descriptor.getCharacteristic().getUuid().toString(), foundHandle + 1,
+ descriptor.getUuid().toString(), newValue);
+ } else {
+ // This must be in sync with QLowEnergyService::DescriptorReadError
+ final int descriptorReadError = 6;
+ leServiceError(qtObject, foundHandle + 1, descriptorReadError);
+ }
+
+ }
+
+ if (isServiceDiscoveryRun) {
+ // last entry of pending service discovery run? ->send discovery finished state update
+ GattEntry serviceEntry = entries.get(entry.associatedServiceHandle);
+ if (serviceEntry.endHandle == foundHandle) {
+ finishCurrentServiceDiscovery(entry.associatedServiceHandle);
+ }
+
+ /* Some devices preset ClientCharacteristicConfiguration descriptors
+ * to enable notifications out of the box. However the additional
+ * BluetoothGatt.setCharacteristicNotification call prevents
+ * automatic notifications from coming through. Hence we manually set them
+ * up here.
+ */
+ if (descriptor.getUuid().compareTo(clientCharacteristicUuid) == 0) {
+ byte[] bytearray = newValue;
+ final int value = (bytearray != null && bytearray.length > 0) ? bytearray[0] : 0;
+ // notification or indication bit set?
+ if ((value & 0x03) > 0) {
+ Log.d(TAG, "Found descriptor with automatic notifications.");
+ mBluetoothGatt.setCharacteristicNotification(
+ descriptor.getCharacteristic(), true);
+ }
+ }
+ }
+
+ //unlock the queue for next item
+ pendingJob = null;
+
+ performNextIO();
+ }
+
+ private synchronized void handleOnDescriptorWrite(android.bluetooth.BluetoothGatt gatt,
+ android.bluetooth.BluetoothGattDescriptor descriptor,
+ int status)
+ {
+ if (status != BluetoothGatt.GATT_SUCCESS)
+ Log.w(TAG, "onDescriptorWrite: error " + status);
+
+ int handle = handleForDescriptor(descriptor);
+
+ boolean requestTimedOut = !handleForTimeout.compareAndSet(
+ modifiedReadWriteHandle(handle, IoJobType.Write),
+ HANDLE_FOR_RESET);
+ if (requestTimedOut) {
+ Log.w(TAG, "Late descriptor write reply after timeout was hit for handle " +
+ handle);
+ // Timeout has hit before this response -> ignore the response
+ // no need to unlock pendingJob -> the timeout has done that already
+ return;
+ }
+
+ int errorCode;
+ //This must be in sync with QLowEnergyService::ServiceError
+ switch (status) {
+ case BluetoothGatt.GATT_SUCCESS:
+ errorCode = 0; break; // NoError
+ default:
+ errorCode = 3; break; // DescriptorWriteError
+ }
+
+ byte[] value = pendingJob.newValue;
+ pendingJob = null;
+
+ leDescriptorWritten(qtObject, handle+1, value, errorCode);
+ performNextIO();
+ }
+
+ private synchronized void handleOnMtuChanged(android.bluetooth.BluetoothGatt gatt,
+ int mtu, int status)
+ {
+ int previousMtu = mSupportedMtu;
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ Log.w(TAG, "MTU changed to " + mtu);
+ mSupportedMtu = mtu;
+ } else {
+ Log.w(TAG, "MTU change error " + status + ". New MTU " + mtu);
+ mSupportedMtu = DEFAULT_MTU;
+ }
+ if (previousMtu != mSupportedMtu)
+ leMtuChanged(qtObject, mSupportedMtu);
+
+ boolean requestTimedOut = !handleForTimeout.compareAndSet(
+ modifiedReadWriteHandle(HANDLE_FOR_MTU_EXCHANGE, IoJobType.Mtu), HANDLE_FOR_RESET);
+ if (requestTimedOut) {
+ Log.w(TAG, "Late mtu reply after timeout was hit");
+ // Timeout has hit before this response -> ignore the response
+ // no need to unlock pendingJob -> the timeout has done that already
+ return;
+ }
+
+ pendingJob = null;
+
+ performNextIO();
+ }
+
+ private synchronized void handleOnReadRemoteRssi(android.bluetooth.BluetoothGatt gatt,
+ int rssi, int status)
+ {
+ Log.d(TAG, "RSSI read callback, rssi: " + rssi + ", status: " + status);
+ leRemoteRssiRead(qtObject, rssi, status == BluetoothGatt.GATT_SUCCESS);
+
+ boolean requestTimedOut = !handleForTimeout.compareAndSet(
+ modifiedReadWriteHandle(HANDLE_FOR_RSSI_READ, IoJobType.Rssi), HANDLE_FOR_RESET);
+ if (requestTimedOut) {
+ Log.w(TAG, "Late RSSI read reply after timeout was hit");
+ // Timeout has hit before this response -> ignore the response
+ // no need to unlock pendingJob -> the timeout has done that already
+ return;
+ }
+ pendingJob = null;
+ performNextIO();
+ }
+
+ /*************************************************************/
+ /* Service Discovery */
+ /*************************************************************/
+
+ private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
+
+ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
+ super.onConnectionStateChange(gatt, status, newState);
+ handleOnConnectionStateChange(gatt, status, newState);
+ }
+
+ public void onServicesDiscovered(BluetoothGatt gatt, int status) {
+ super.onServicesDiscovered(gatt, status);
+ handleOnServicesDiscovered(gatt, status);
+
+ }
+
+ // API < 33
+ public void onCharacteristicRead(android.bluetooth.BluetoothGatt gatt,
+ android.bluetooth.BluetoothGattCharacteristic characteristic,
+ int status)
+ {
+ super.onCharacteristicRead(gatt, characteristic, status);
+ handleOnCharacteristicRead(gatt, characteristic, characteristic.getValue(), status);
+ }
+
+ // API >= 33
+ public void onCharacteristicRead(android.bluetooth.BluetoothGatt gatt,
+ android.bluetooth.BluetoothGattCharacteristic characteristic,
+ byte[] value,
+ int status)
+ {
+ // Note: here we don't call the super implementation as it calls the old "< API 33"
+ // callback, and the callback would be handled twice
+ handleOnCharacteristicRead(gatt, characteristic, value, status);
+ }
+
+ public void onCharacteristicWrite(android.bluetooth.BluetoothGatt gatt,
+ android.bluetooth.BluetoothGattCharacteristic characteristic,
+ int status)
+ {
+ super.onCharacteristicWrite(gatt, characteristic, status);
+ handleOnCharacteristicWrite(gatt, characteristic, status);
+ }
+
+ // API < 33
+ public void onCharacteristicChanged(android.bluetooth.BluetoothGatt gatt,
+ android.bluetooth.BluetoothGattCharacteristic characteristic)
+ {
+ super.onCharacteristicChanged(gatt, characteristic);
+ handleOnCharacteristicChanged(gatt, characteristic, characteristic.getValue());
+ }
+
+ // API >= 33
+ public void onCharacteristicChanged(android.bluetooth.BluetoothGatt gatt,
+ android.bluetooth.BluetoothGattCharacteristic characteristic,
+ byte[] value)
+ {
+ // Note: here we don't call the super implementation as it calls the old "< API 33"
+ // callback, and the callback would be handled twice
+ handleOnCharacteristicChanged(gatt, characteristic, value);
+ }
+
+ // API < 33
+ public void onDescriptorRead(android.bluetooth.BluetoothGatt gatt,
+ android.bluetooth.BluetoothGattDescriptor descriptor,
+ int status)
+ {
+ super.onDescriptorRead(gatt, descriptor, status);
+ handleOnDescriptorRead(gatt, descriptor, status, descriptor.getValue());
+ }
+
+ // API >= 33
+ public void onDescriptorRead(android.bluetooth.BluetoothGatt gatt,
+ android.bluetooth.BluetoothGattDescriptor descriptor,
+ int status,
+ byte[] value)
+ {
+ // Note: here we don't call the super implementation as it calls the old "< API 33"
+ // callback, and the callback would be handled twice
+ handleOnDescriptorRead(gatt, descriptor, status, value);
+ }
+
+ public void onDescriptorWrite(android.bluetooth.BluetoothGatt gatt,
+ android.bluetooth.BluetoothGattDescriptor descriptor,
+ int status)
+ {
+ super.onDescriptorWrite(gatt, descriptor, status);
+ handleOnDescriptorWrite(gatt, descriptor, status);
+ }
+ //TODO currently not supported
+// public void onReliableWriteCompleted(android.bluetooth.BluetoothGatt gatt,
+// int status) {
+// System.out.println("onReliableWriteCompleted");
+// }
+//
+ public void onReadRemoteRssi(android.bluetooth.BluetoothGatt gatt, int rssi, int status)
+ {
+ super.onReadRemoteRssi(gatt, rssi, status);
+ handleOnReadRemoteRssi(gatt, rssi, status);
+ }
+
+ public void onMtuChanged(android.bluetooth.BluetoothGatt gatt, int mtu, int status)
+ {
+ super.onMtuChanged(gatt, mtu, status);
+ handleOnMtuChanged(gatt, mtu, status);
+ }
+ };
+
+ // This function is called from Qt thread
+ public synchronized int mtu() {
+ if (mSupportedMtu == -1) {
+ return DEFAULT_MTU;
+ } else {
+ return mSupportedMtu;
+ }
+ }
+
+ // This function is called from Qt thread
+ public synchronized boolean readRemoteRssi() {
+ if (mBluetoothGatt == null)
+ return false;
+
+ // Reading of RSSI can sometimes be 'lost' especially if amidst
+ // characteristic reads/writes ('lost' here meaning that there is no callback).
+ // To avoid this schedule the RSSI read in the job queue.
+ ReadWriteJob newJob = new ReadWriteJob();
+ newJob.jobType = IoJobType.Rssi;
+ newJob.entry = null;
+
+ if (!readWriteQueue.add(newJob)) {
+ Log.w(TAG, "Cannot add remote RSSI read to queue" );
+ return false;
+ }
+
+ performNextIOThreaded();
+ return true;
+ }
+
+ // This function is called from Qt thread
+ public synchronized boolean connect() {
+ BluetoothDevice mRemoteGattDevice;
+
+ if (mBluetoothAdapter == null) {
+ Log.w(TAG, "Cannot connect, no bluetooth adapter");
+ return false;
+ }
+
+ try {
+ mRemoteGattDevice = mBluetoothAdapter.getRemoteDevice(mRemoteGattAddress);
+ } catch (IllegalArgumentException ex) {
+ Log.w(TAG, "Remote address is not valid: " + mRemoteGattAddress);
+ return false;
+ }
+
+ /* The required connectGatt function is already available in SDK v26, but Android 8.0
+ * contains a race condition in the Changed callback such that it can return the value that
+ * was written. This is fixed in Android 8.1, which matches SDK v27. */
+ if (Build.VERSION.SDK_INT >= 27) {
+ HandlerThread handlerThread = new HandlerThread("QtBluetoothLEHandlerThread");
+ handlerThread.start();
+ mHandler = new Handler(handlerThread.getLooper());
+
+ Class[] args = new Class[6];
+ args[0] = android.content.Context.class;
+ args[1] = boolean.class;
+ args[2] = android.bluetooth.BluetoothGattCallback.class;
+ args[3] = int.class;
+ args[4] = int.class;
+ args[5] = android.os.Handler.class;
+
+ try {
+ Method connectMethod = mRemoteGattDevice.getClass().getDeclaredMethod("connectGatt", args);
+ if (connectMethod != null) {
+ mBluetoothGatt = (BluetoothGatt) connectMethod.invoke(mRemoteGattDevice, qtContext, false,
+ gattCallback, 2 /* TRANSPORT_LE */, 1 /*BluetoothDevice.PHY_LE_1M*/, mHandler);
+ Log.w(TAG, "Using Android v26 BluetoothDevice.connectGatt()");
+ }
+ } catch (Exception ex) {
+ Log.w(TAG, "connectGatt() v26 not available");
+ ex.printStackTrace();
+ }
+
+ if (mBluetoothGatt == null) {
+ mHandler.getLooper().quitSafely();
+ mHandler = null;
+ }
+ }
+
+ if (mBluetoothGatt == null) {
+ try {
+ //This API element is currently: greylist-max-o (API level 27), reflection, allowed
+ //It may change in the future
+ Class[] constr_args = new Class[5];
+ constr_args[0] = android.bluetooth.BluetoothGattService.class;
+ constr_args[1] = java.util.UUID.class;
+ constr_args[2] = int.class;
+ constr_args[3] = int.class;
+ constr_args[4] = int.class;
+ mCharacteristicConstructor = BluetoothGattCharacteristic.class.getDeclaredConstructor(constr_args);
+ mCharacteristicConstructor.setAccessible(true);
+ } catch (NoSuchMethodException ex) {
+ Log.w(TAG, "Unable get characteristic constructor. Buffer race condition are possible");
+ /* For some reason we don't get the private BluetoothGattCharacteristic ctor.
+ This means that we cannot protect ourselves from issues where concurrent
+ read and write operations on the same char can overwrite each others buffer.
+ Nevertheless we continue with best effort.
+ */
+ }
+ try {
+ mBluetoothGatt =
+ mRemoteGattDevice.connectGatt(qtContext, false,
+ gattCallback, 2 /* TRANSPORT_LE */);
+ } catch (IllegalArgumentException ex) {
+ Log.w(TAG, "Gatt connection failed");
+ ex.printStackTrace();
+ }
+ }
+ return mBluetoothGatt != null;
+ }
+
+ // This function is called from Qt thread
+ public synchronized void disconnect() {
+ if (mBluetoothGatt == null)
+ return;
+
+ mBluetoothGatt.disconnect();
+ }
+
+ // This function is called from Qt thread
+ public synchronized boolean discoverServices()
+ {
+ return mBluetoothGatt != null && mBluetoothGatt.discoverServices();
+ }
+
+ private enum GattEntryType
+ {
+ Service, Characteristic, CharacteristicValue, Descriptor
+ }
+ private class GattEntry
+ {
+ public GattEntryType type;
+ public boolean valueKnown = false;
+ public BluetoothGattService service = null;
+ public BluetoothGattCharacteristic characteristic = null;
+ public BluetoothGattDescriptor descriptor = null;
+ /*
+ * endHandle defined for GattEntryType.Service and GattEntryType.CharacteristicValue
+ * If the type is service this is the value of the last Gatt entry belonging to the very
+ * same service. If the type is a char value it is the entries index inside
+ * the "entries" list.
+ */
+ public int endHandle = -1;
+ // pointer back to the handle that describes the service that this GATT entry belongs to
+ public int associatedServiceHandle;
+ }
+
+ private enum IoJobType
+ {
+ Read, Write, Mtu,
+ SkippedRead, Rssi
+ // a skipped read is a read which is not executed
+ // introduced in Qt 6.2 to skip reads without changing service discovery logic
+ }
+
+ private class ReadWriteJob
+ {
+ public GattEntry entry;
+ public byte[] newValue;
+ public int requestedWriteType;
+ public IoJobType jobType;
+ }
+
+ // service uuid -> service handle mapping (there can be more than one service with same uuid)
+ private final Hashtable<UUID, List<Integer>> uuidToEntry = new Hashtable<UUID, List<Integer>>(100);
+ // index into array is equivalent to handle id
+ private final ArrayList<GattEntry> entries = new ArrayList<GattEntry>(100);
+ //backlog of to be discovered services
+ private final LinkedList<Integer> servicesToBeDiscovered = new LinkedList<Integer>();
+
+
+ private final LinkedList<ReadWriteJob> readWriteQueue = new LinkedList<ReadWriteJob>();
+ private ReadWriteJob pendingJob;
+
+ /*
+ Internal helper function
+ Returns the handle id for the given characteristic; otherwise returns -1.
+
+ Note that this is the Java handle. The Qt handle is the Java handle +1.
+ */
+ private int handleForCharacteristic(BluetoothGattCharacteristic characteristic)
+ {
+ if (characteristic == null)
+ return -1;
+
+ List<Integer> handles = uuidToEntry.get(characteristic.getService().getUuid());
+ if (handles == null || handles.isEmpty())
+ return -1;
+
+ //TODO for now we assume we always want the first service in case of uuid collision
+ int serviceHandle = handles.get(0);
+
+ try {
+ GattEntry entry;
+ for (int i = serviceHandle+1; i < entries.size(); i++) {
+ entry = entries.get(i);
+ if (entry == null)
+ continue;
+
+ switch (entry.type) {
+ case Descriptor:
+ case CharacteristicValue:
+ continue;
+ case Service:
+ break;
+ case Characteristic:
+ if (entry.characteristic == characteristic)
+ return i;
+ break;
+ }
+ }
+ } catch (IndexOutOfBoundsException ex) { /*nothing*/ }
+ return -1;
+ }
+
+ /*
+ Internal helper function
+ Returns the handle id for the given descriptor; otherwise returns -1.
+
+ Note that this is the Java handle. The Qt handle is the Java handle +1.
+ */
+ private int handleForDescriptor(BluetoothGattDescriptor descriptor)
+ {
+ if (descriptor == null)
+ return -1;
+
+ List<Integer> handles = uuidToEntry.get(descriptor.getCharacteristic().getService().getUuid());
+ if (handles == null || handles.isEmpty())
+ return -1;
+
+ //TODO for now we assume we always want the first service in case of uuid collision
+ int serviceHandle = handles.get(0);
+
+ try {
+ GattEntry entry;
+ for (int i = serviceHandle+1; i < entries.size(); i++) {
+ entry = entries.get(i);
+ if (entry == null)
+ continue;
+
+ switch (entry.type) {
+ case Characteristic:
+ case CharacteristicValue:
+ continue;
+ case Service:
+ break;
+ case Descriptor:
+ if (entry.descriptor == descriptor)
+ return i;
+ break;
+ }
+ }
+ } catch (IndexOutOfBoundsException ignored) { }
+ return -1;
+ }
+
+ // This function is called from Qt thread (indirectly)
+ private void populateHandles()
+ {
+ // We introduce the notion of artificial handles. While GATT handles
+ // are not exposed on Android they help to quickly identify GATT attributes
+ // on the C++ side. The Qt Api will not expose the handles
+ GattEntry entry = null;
+ List<BluetoothGattService> services = mBluetoothGatt.getServices();
+ for (BluetoothGattService service: services) {
+ GattEntry serviceEntry = new GattEntry();
+ serviceEntry.type = GattEntryType.Service;
+ serviceEntry.service = service;
+ entries.add(serviceEntry);
+
+ // remember handle for the service for later update
+ int serviceHandle = entries.size() - 1;
+ //point to itself -> mostly done for consistence reasons with other entries
+ serviceEntry.associatedServiceHandle = serviceHandle;
+
+ //some devices may have more than one service with the same uuid
+ List<Integer> old = uuidToEntry.get(service.getUuid());
+ if (old == null)
+ old = new ArrayList<Integer>();
+ old.add(entries.size()-1);
+ uuidToEntry.put(service.getUuid(), old);
+
+ // add all characteristics
+ List<BluetoothGattCharacteristic> charList = service.getCharacteristics();
+ for (BluetoothGattCharacteristic characteristic: charList) {
+ entry = new GattEntry();
+ entry.type = GattEntryType.Characteristic;
+ entry.characteristic = characteristic;
+ entry.associatedServiceHandle = serviceHandle;
+ //entry.endHandle = .. undefined
+ entries.add(entry);
+
+ // this emulates GATT value attributes
+ entry = new GattEntry();
+ entry.type = GattEntryType.CharacteristicValue;
+ entry.associatedServiceHandle = serviceHandle;
+ entry.endHandle = entries.size(); // special case -> current index in entries list
+ entries.add(entry);
+
+ // add all descriptors
+ List<BluetoothGattDescriptor> descList = characteristic.getDescriptors();
+ for (BluetoothGattDescriptor desc: descList) {
+ entry = new GattEntry();
+ entry.type = GattEntryType.Descriptor;
+ entry.descriptor = desc;
+ entry.associatedServiceHandle = serviceHandle;
+ //entry.endHandle = .. undefined
+ entries.add(entry);
+ }
+ }
+
+ // update endHandle of current service
+ serviceEntry.endHandle = entries.size() - 1;
+ }
+
+ entries.trimToSize();
+ }
+
+ private void resetData()
+ {
+ uuidToEntry.clear();
+ entries.clear();
+ servicesToBeDiscovered.clear();
+
+ // kill all timeout handlers
+ timeoutHandler.removeCallbacksAndMessages(null);
+ handleForTimeout.set(HANDLE_FOR_RESET);
+
+ readWriteQueue.clear();
+ pendingJob = null;
+ }
+
+ // This function is called from Qt thread
+ public synchronized boolean discoverServiceDetails(String serviceUuid, boolean fullDiscovery)
+ {
+ Log.d(TAG, "Discover service details for: " + serviceUuid + ", fullDiscovery: "
+ + fullDiscovery + ", BluetoothGatt: " + (mBluetoothGatt != null));
+ try {
+ if (mBluetoothGatt == null)
+ return false;
+
+ if (entries.isEmpty())
+ populateHandles();
+
+ GattEntry entry;
+ int serviceHandle;
+ try {
+ UUID service = UUID.fromString(serviceUuid);
+ List<Integer> handles = uuidToEntry.get(service);
+ if (handles == null || handles.isEmpty()) {
+ Log.w(TAG, "Unknown service uuid for current device: " + service.toString());
+ return false;
+ }
+
+ //TODO for now we assume we always want the first service in case of uuid collision
+ serviceHandle = handles.get(0);
+ entry = entries.get(serviceHandle);
+ if (entry == null) {
+ Log.w(TAG, "Service with UUID " + service.toString() + " not found");
+ return false;
+ }
+ } catch (IllegalArgumentException ex) {
+ //invalid UUID string passed
+ Log.w(TAG, "Cannot parse given UUID");
+ return false;
+ }
+
+ if (entry.type != GattEntryType.Service) {
+ Log.w(TAG, "Given UUID is not a service UUID: " + serviceUuid);
+ return false;
+ }
+
+ // current service already discovered or under investigation
+ if (entry.valueKnown || servicesToBeDiscovered.contains(serviceHandle)) {
+ Log.w(TAG, "Service already known or to be discovered");
+ return true;
+ }
+
+ servicesToBeDiscovered.add(serviceHandle);
+ scheduleServiceDetailDiscovery(serviceHandle, fullDiscovery);
+ performNextIOThreaded();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return false;
+ }
+
+ return true;
+ }
+
+ /*
+ Returns the uuids of the services included by the given service. Otherwise returns null.
+ This function is called from Qt thread
+ */
+ public synchronized String includedServices(String serviceUuid)
+ {
+ if (mBluetoothGatt == null)
+ return null;
+
+ UUID uuid;
+ try {
+ uuid = UUID.fromString(serviceUuid);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return null;
+ }
+
+ //TODO Breaks in case of two services with same uuid
+ BluetoothGattService service = mBluetoothGatt.getService(uuid);
+ if (service == null)
+ return null;
+
+ final List<BluetoothGattService> includes = service.getIncludedServices();
+ if (includes.isEmpty())
+ return null;
+
+ StringBuilder builder = new StringBuilder();
+ for (BluetoothGattService includedService: includes) {
+ builder.append(includedService.getUuid().toString()).append(" "); //space is separator
+ }
+
+ return builder.toString();
+ }
+
+ private synchronized void finishCurrentServiceDiscovery(int handleDiscoveredService)
+ {
+ Log.w(TAG, "Finished current discovery for service handle " + handleDiscoveredService);
+ GattEntry discoveredService = entries.get(handleDiscoveredService);
+ discoveredService.valueKnown = true;
+ try {
+ servicesToBeDiscovered.removeFirst();
+ } catch (NoSuchElementException ex) {
+ Log.w(TAG, "Expected queued service but didn't find any");
+ }
+
+ leServiceDetailDiscoveryFinished(qtObject, discoveredService.service.getUuid().toString(),
+ handleDiscoveredService + 1, discoveredService.endHandle + 1);
+ }
+
+ // Executes under "this" client mutex. Returns true
+ // if no actual MTU exchange is initiated
+ private boolean executeMtuExchange()
+ {
+ if (mBluetoothGatt.requestMtu(MAX_MTU)) {
+ Log.w(TAG, "MTU change initiated");
+ return false;
+ } else {
+ Log.w(TAG, "MTU change request failed");
+ }
+
+ Log.w(TAG, "Assuming default MTU value of 23 bytes");
+ mSupportedMtu = DEFAULT_MTU;
+ return true;
+ }
+
+ private boolean executeRemoteRssiRead()
+ {
+ if (mBluetoothGatt.readRemoteRssi()) {
+ Log.d(TAG, "RSSI read initiated");
+ return false;
+ }
+ Log.w(TAG, "Initiating remote RSSI read failed");
+ leRemoteRssiRead(qtObject, 0, false);
+ return true;
+ }
+
+ /*
+ * Already executed in GattCallback so executed by the HandlerThread. No need to
+ * post it to the Hander.
+ */
+ private void scheduleMtuExchange() {
+ ReadWriteJob newJob = new ReadWriteJob();
+ newJob.jobType = IoJobType.Mtu;
+ newJob.entry = null;
+
+ readWriteQueue.add(newJob);
+
+ performNextIO();
+ }
+
+ /*
+ Internal Helper function for discoverServiceDetails()
+
+ Adds all Gatt entries for the given service to the readWriteQueue to be discovered.
+ This function only ever adds read requests to the queue.
+
+ */
+ private void scheduleServiceDetailDiscovery(int serviceHandle, boolean fullDiscovery)
+ {
+ GattEntry serviceEntry = entries.get(serviceHandle);
+ final int endHandle = serviceEntry.endHandle;
+
+ if (serviceHandle == endHandle) {
+ Log.w(TAG, "scheduleServiceDetailDiscovery: service is empty; nothing to discover");
+ finishCurrentServiceDiscovery(serviceHandle);
+ return;
+ }
+
+ // serviceHandle + 1 -> ignore service handle itself
+ for (int i = serviceHandle + 1; i <= endHandle; i++) {
+ GattEntry entry = entries.get(i);
+
+ if (entry.type == GattEntryType.Service) {
+ // should not really happen unless endHandle is wrong
+ Log.w(TAG, "scheduleServiceDetailDiscovery: wrong endHandle");
+ return;
+ }
+
+ ReadWriteJob newJob = new ReadWriteJob();
+ newJob.entry = entry;
+ if (fullDiscovery) {
+ newJob.jobType = IoJobType.Read;
+ } else {
+ newJob.jobType = IoJobType.SkippedRead;
+ }
+
+ final boolean result = readWriteQueue.add(newJob);
+ if (!result)
+ Log.w(TAG, "Cannot add service discovery job for " + serviceEntry.service.getUuid()
+ + " on item " + entry.type);
+ }
+ }
+
+ /*************************************************************/
+ /* Write Characteristics */
+ /* This function is called from Qt thread */
+ /*************************************************************/
+
+ public synchronized boolean writeCharacteristic(int charHandle, byte[] newValue,
+ int writeMode)
+ {
+ if (mBluetoothGatt == null)
+ return false;
+
+ GattEntry entry;
+ try {
+ entry = entries.get(charHandle-1); //Qt always uses handles+1
+ } catch (IndexOutOfBoundsException ex) {
+ ex.printStackTrace();
+ return false;
+ }
+
+ ReadWriteJob newJob = new ReadWriteJob();
+ newJob.newValue = newValue;
+ newJob.entry = entry;
+ newJob.jobType = IoJobType.Write;
+
+ // writeMode must be in sync with QLowEnergyService::WriteMode
+ switch (writeMode) {
+ case 1: //WriteWithoutResponse
+ newJob.requestedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE;
+ break;
+ case 2: //WriteSigned
+ newJob.requestedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_SIGNED;
+ break;
+ default:
+ newJob.requestedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT;
+ break;
+ }
+
+ boolean result;
+ result = readWriteQueue.add(newJob);
+
+ if (!result) {
+ Log.w(TAG, "Cannot add characteristic write request for " + charHandle + " to queue" );
+ return false;
+ }
+
+ performNextIOThreaded();
+ return true;
+ }
+
+ /*************************************************************/
+ /* Write Descriptors */
+ /* This function is called from Qt thread */
+ /*************************************************************/
+
+ public synchronized boolean writeDescriptor(int descHandle, byte[] newValue)
+ {
+ if (mBluetoothGatt == null)
+ return false;
+
+ GattEntry entry;
+ try {
+ entry = entries.get(descHandle-1); //Qt always uses handles+1
+ } catch (IndexOutOfBoundsException ex) {
+ ex.printStackTrace();
+ return false;
+ }
+
+ ReadWriteJob newJob = new ReadWriteJob();
+ newJob.newValue = newValue;
+ newJob.entry = entry;
+ newJob.requestedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT;
+ newJob.jobType = IoJobType.Write;
+
+ boolean result;
+ result = readWriteQueue.add(newJob);
+
+ if (!result) {
+ Log.w(TAG, "Cannot add descriptor write request for " + descHandle + " to queue" );
+ return false;
+ }
+
+ performNextIOThreaded();
+ return true;
+ }
+
+ /*************************************************************/
+ /* Read Characteristics */
+ /* This function is called from Qt thread */
+ /*************************************************************/
+
+ public synchronized boolean readCharacteristic(int charHandle)
+ {
+ if (mBluetoothGatt == null)
+ return false;
+
+ GattEntry entry;
+ try {
+ entry = entries.get(charHandle-1); //Qt always uses handles+1
+ } catch (IndexOutOfBoundsException ex) {
+ ex.printStackTrace();
+ return false;
+ }
+
+ ReadWriteJob newJob = new ReadWriteJob();
+ newJob.entry = entry;
+ newJob.jobType = IoJobType.Read;
+
+ boolean result;
+ result = readWriteQueue.add(newJob);
+
+ if (!result) {
+ Log.w(TAG, "Cannot add characteristic read request for " + charHandle + " to queue" );
+ return false;
+ }
+
+ performNextIOThreaded();
+ return true;
+ }
+
+ // This function is called from Qt thread
+ public synchronized boolean readDescriptor(int descHandle)
+ {
+ if (mBluetoothGatt == null)
+ return false;
+
+ GattEntry entry;
+ try {
+ entry = entries.get(descHandle-1); //Qt always uses handles+1
+ } catch (IndexOutOfBoundsException ex) {
+ ex.printStackTrace();
+ return false;
+ }
+
+ ReadWriteJob newJob = new ReadWriteJob();
+ newJob.entry = entry;
+ newJob.jobType = IoJobType.Read;
+
+ boolean result;
+ result = readWriteQueue.add(newJob);
+
+ if (!result) {
+ Log.w(TAG, "Cannot add descriptor read request for " + descHandle + " to queue" );
+ return false;
+ }
+
+ performNextIOThreaded();
+ return true;
+ }
+
+ // Called by TimeoutRunnable if the current I/O job timed out.
+ // By the time we reach this point the handleForTimeout counter has already been reset
+ // and the regular responses will be blocked off.
+ private synchronized void interruptCurrentIO(int handle)
+ {
+ //unlock the queue for next item
+ pendingJob = null;
+
+ performNextIOThreaded();
+
+ if (handle == HANDLE_FOR_MTU_EXCHANGE || handle == HANDLE_FOR_RSSI_READ)
+ return;
+
+ try {
+ GattEntry entry = entries.get(handle);
+ if (entry == null)
+ return;
+ if (entry.valueKnown)
+ return;
+ entry.valueKnown = true;
+
+ GattEntry serviceEntry = entries.get(entry.associatedServiceHandle);
+ if (serviceEntry != null && serviceEntry.endHandle == handle)
+ finishCurrentServiceDiscovery(entry.associatedServiceHandle);
+ } catch (IndexOutOfBoundsException outOfBounds) {
+ Log.w(TAG, "interruptCurrentIO(): Unknown gatt entry, index: "
+ + handle + " size: " + entries.size());
+ }
+ }
+
+ /*
+ Wrapper around performNextIO() ensuring that performNextIO() is executed inside
+ the mHandler/mHandlerThread if it exists.
+ */
+ private void performNextIOThreaded()
+ {
+ if (mHandler != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ performNextIO();
+ }
+ });
+ } else {
+ performNextIO();
+ }
+ }
+
+ /*
+ The queuing is required because two writeCharacteristic/writeDescriptor calls
+ cannot execute at the same time. The second write must happen after the
+ previous write has finished with on(Characteristic|Descriptor)Write().
+ */
+ private synchronized void performNextIO()
+ {
+ Log.d(TAG, "Perform next BTLE IO, job queue size: " + readWriteQueue.size()
+ + ", a job is pending: " + (pendingJob != null) + ", BluetoothGatt: "
+ + (mBluetoothGatt != null));
+
+ if (mBluetoothGatt == null)
+ return;
+
+ boolean skip = false;
+ final ReadWriteJob nextJob;
+ int handle = HANDLE_FOR_RESET;
+
+ if (readWriteQueue.isEmpty() || pendingJob != null)
+ return;
+
+ nextJob = readWriteQueue.remove();
+ // MTU requests and RSSI reads are special cases
+ if (nextJob.jobType == IoJobType.Mtu) {
+ handle = HANDLE_FOR_MTU_EXCHANGE;
+ } else if (nextJob.jobType == IoJobType.Rssi) {
+ handle = HANDLE_FOR_RSSI_READ;
+ } else {
+ switch (nextJob.entry.type) {
+ case Characteristic:
+ handle = handleForCharacteristic(nextJob.entry.characteristic);
+ break;
+ case Descriptor:
+ handle = handleForDescriptor(nextJob.entry.descriptor);
+ break;
+ case CharacteristicValue:
+ handle = nextJob.entry.endHandle;
+ default:
+ break;
+ }
+ }
+
+ // timeout handler and handleForTimeout atomic must be setup before
+ // executing the request. Sometimes the callback is quicker than executing the
+ // remainder of this function. Therefore enable the atomic early
+ timeoutHandler.removeCallbacksAndMessages(null); // remove any timeout handlers
+ handleForTimeout.set(modifiedReadWriteHandle(handle, nextJob.jobType));
+
+ switch (nextJob.jobType) {
+ case Read:
+ skip = executeReadJob(nextJob);
+ break;
+ case SkippedRead:
+ skip = true;
+ break;
+ case Write:
+ skip = executeWriteJob(nextJob);
+ break;
+ case Mtu:
+ skip = executeMtuExchange();
+ case Rssi:
+ skip = executeRemoteRssiRead();
+ break;
+ }
+
+ if (skip) {
+ handleForTimeout.set(HANDLE_FOR_RESET); // not a pending call -> release atomic
+ } else {
+ pendingJob = nextJob;
+ timeoutHandler.postDelayed(new TimeoutRunnable(
+ modifiedReadWriteHandle(handle, nextJob.jobType)), RUNNABLE_TIMEOUT);
+ }
+
+ if (nextJob.jobType != IoJobType.Mtu && nextJob.jobType != IoJobType.Rssi) {
+ Log.d(TAG, "Performing queued job, handle: " + handle + " " + nextJob.jobType + " (" +
+ (nextJob.requestedWriteType == BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) +
+ ") ValueKnown: " + nextJob.entry.valueKnown + " Skipping: " + skip +
+ " " + nextJob.entry.type);
+ }
+
+ GattEntry entry = nextJob.entry;
+
+ if (skip) {
+ /*
+ BluetoothGatt.[read|write][Characteristic|Descriptor]() immediately
+ return in cases where meta data doesn't match the intended action
+ (e.g. trying to write to read-only char). When this happens
+ we have to report an error back to Qt. The error report is not required during
+ the initial service discovery though.
+ */
+ if (handle > HANDLE_FOR_RESET) {
+ // during service discovery we do not report error but emit characteristicRead()
+ // any other time a failure emits serviceError() signal
+
+ final boolean isServiceDiscovery = !entry.valueKnown;
+
+ if (isServiceDiscovery) {
+ entry.valueKnown = true;
+ switch (entry.type) {
+ case Characteristic:
+ Log.d(TAG,
+ nextJob.jobType == IoJobType.Read ? "Non-readable" : "Skipped reading of"
+ + " characteristic " + entry.characteristic.getUuid()
+ + " for service " + entry.characteristic.getService().getUuid());
+ leCharacteristicRead(qtObject, entry.characteristic.getService().getUuid().toString(),
+ handle + 1, entry.characteristic.getUuid().toString(),
+ entry.characteristic.getProperties(), null);
+ break;
+ case Descriptor:
+ Log.d(TAG,
+ nextJob.jobType == IoJobType.Read ? "Non-readable" : "Skipped reading of"
+ + " descriptor " + entry.descriptor.getUuid()
+ + " for service/char " + entry.descriptor.getCharacteristic().getService().getUuid()
+ + "/" + entry.descriptor.getCharacteristic().getUuid());
+ leDescriptorRead(qtObject,
+ entry.descriptor.getCharacteristic().getService().getUuid().toString(),
+ entry.descriptor.getCharacteristic().getUuid().toString(),
+ handle + 1, entry.descriptor.getUuid().toString(),
+ null);
+ break;
+ case CharacteristicValue:
+ // for more details see scheduleServiceDetailDiscovery(int, boolean)
+ break;
+ case Service:
+ Log.w(TAG, "Scheduling of Service Gatt entry for service discovery should never happen.");
+ break;
+ }
+
+ // last entry of current discovery run?
+ try {
+ GattEntry serviceEntry = entries.get(entry.associatedServiceHandle);
+ if (serviceEntry.endHandle == handle)
+ finishCurrentServiceDiscovery(entry.associatedServiceHandle);
+ } catch (IndexOutOfBoundsException outOfBounds) {
+ Log.w(TAG, "performNextIO(): Unknown service for entry, index: "
+ + entry.associatedServiceHandle + " size: " + entries.size());
+ }
+ } else {
+ int errorCode = 0;
+
+ // The error codes below must be in sync with QLowEnergyService::ServiceError
+ if (nextJob.jobType == IoJobType.Read) {
+ errorCode = (entry.type == GattEntryType.Characteristic) ?
+ 5 : 6; // CharacteristicReadError : DescriptorReadError
+ } else {
+ errorCode = (entry.type == GattEntryType.Characteristic) ?
+ 2 : 3; // CharacteristicWriteError : DescriptorWriteError
+ }
+
+ leServiceError(qtObject, handle + 1, errorCode);
+ }
+ }
+
+ performNextIO();
+ }
+ }
+
+ private BluetoothGattCharacteristic cloneChararacteristic(BluetoothGattCharacteristic other) {
+ try {
+ return (BluetoothGattCharacteristic) mCharacteristicConstructor.newInstance(other.getService(),
+ other.getUuid(), other.getInstanceId(), other.getProperties(), other.getPermissions());
+ } catch (Exception ex) {
+ Log.w(TAG, "Cloning characteristic failed!" + ex);
+ return null;
+ }
+ }
+
+ // Returns true if nextJob should be skipped.
+ private boolean executeWriteJob(ReadWriteJob nextJob)
+ {
+ boolean result;
+ switch (nextJob.entry.type) {
+ case Characteristic:
+ if (Build.VERSION.SDK_INT >= 33) {
+ int writeResult = mBluetoothGatt.writeCharacteristic(
+ nextJob.entry.characteristic, nextJob.newValue, nextJob.requestedWriteType);
+ return (writeResult != BluetoothStatusCodes.SUCCESS);
+ }
+ if (mHandler != null || mCharacteristicConstructor == null) {
+ if (nextJob.entry.characteristic.getWriteType() != nextJob.requestedWriteType) {
+ nextJob.entry.characteristic.setWriteType(nextJob.requestedWriteType);
+ }
+ result = nextJob.entry.characteristic.setValue(nextJob.newValue);
+ return !result || !mBluetoothGatt.writeCharacteristic(nextJob.entry.characteristic);
+ } else {
+ BluetoothGattCharacteristic orig = nextJob.entry.characteristic;
+ BluetoothGattCharacteristic tmp = cloneChararacteristic(orig);
+ if (tmp == null)
+ return true;
+ tmp.setWriteType(nextJob.requestedWriteType);
+ return !tmp.setValue(nextJob.newValue) || !mBluetoothGatt.writeCharacteristic(tmp);
+ }
+ case Descriptor:
+ if (nextJob.entry.descriptor.getUuid().compareTo(clientCharacteristicUuid) == 0) {
+ /*
+ For some reason, Android splits characteristic notifications
+ into two operations. BluetoothGatt.enableCharacteristicNotification
+ ensures the local Bluetooth stack forwards the notifications. In addition,
+ BluetoothGattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
+ must be written to the peripheral.
+ */
+
+
+ /* There is no documentation on indication behavior. The assumption is
+ that when indication or notification are requested we call
+ BluetoothGatt.setCharacteristicNotification. Furthermore it is assumed
+ indications are send via onCharacteristicChanged too and Android itself
+ will do the confirmation required for an indication as per
+ Bluetooth spec Vol 3, Part G, 4.11 . If neither of the two bits are set
+ we disable the signals.
+ */
+ boolean enableNotifications = false;
+ int value = (nextJob.newValue[0] & 0xff);
+ // first or second bit must be set
+ if (((value & 0x1) == 1) || (((value >> 1) & 0x1) == 1)) {
+ enableNotifications = true;
+ }
+
+ result = mBluetoothGatt.setCharacteristicNotification(
+ nextJob.entry.descriptor.getCharacteristic(), enableNotifications);
+ if (!result) {
+ Log.w(TAG, "Cannot set characteristic notification");
+ //we continue anyway to ensure that we write the requested value
+ //to the device
+ }
+
+ Log.d(TAG, "Enable notifications: " + enableNotifications);
+ }
+
+ if (Build.VERSION.SDK_INT >= 33) {
+ int writeResult = mBluetoothGatt.writeDescriptor(
+ nextJob.entry.descriptor, nextJob.newValue);
+ return (writeResult != BluetoothStatusCodes.SUCCESS);
+ }
+ result = nextJob.entry.descriptor.setValue(nextJob.newValue);
+ if (!result || !mBluetoothGatt.writeDescriptor(nextJob.entry.descriptor))
+ return true;
+
+ break;
+ case Service:
+ case CharacteristicValue:
+ return true;
+ }
+ return false;
+ }
+
+ // Returns true if nextJob should be skipped.
+ private boolean executeReadJob(ReadWriteJob nextJob)
+ {
+ boolean result;
+ switch (nextJob.entry.type) {
+ case Characteristic:
+ try {
+ result = mBluetoothGatt.readCharacteristic(nextJob.entry.characteristic);
+ } catch (java.lang.SecurityException se) {
+ // QTBUG-59917 -> HID services cause problems since Android 5.1
+ se.printStackTrace();
+ result = false;
+ }
+ if (!result)
+ return true; // skip
+ break;
+ case Descriptor:
+ try {
+ result = mBluetoothGatt.readDescriptor(nextJob.entry.descriptor);
+ } catch (java.lang.SecurityException se) {
+ // QTBUG-59917 -> HID services cause problems since Android 5.1
+ se.printStackTrace();
+ result = false;
+ }
+ if (!result)
+ return true; // skip
+ break;
+ case Service:
+ return true;
+ case CharacteristicValue:
+ return true; //skip
+ }
+ return false;
+ }
+
+ /*
+ * Modifies and returns the given \a handle such that the job
+ * \a type is encoded into the returned handle. Hereby we take advantage of the fact that
+ * a Bluetooth Low Energy handle is only 16 bit. The handle will be the bottom two bytes
+ * and the job type will be in the top 2 bytes.
+ *
+ * top 2 bytes
+ * - 0x01 -> Read Job
+ * - 0x02 -> Write Job
+ *
+ * This is done in connection with handleForTimeout and assists in the process of
+ * detecting accidental interruption by the timeout handler.
+ * If two requests for the same handle are scheduled behind each other there is the
+ * theoretical chance that the first request comes back normally while the second request
+ * is interrupted by the timeout handler. This risk still exists but this function ensures that
+ * at least back to back requests of differing types cannot affect each other via the timeout
+ * handler.
+ */
+ private int modifiedReadWriteHandle(int handle, IoJobType type)
+ {
+ int modifiedHandle = handle;
+ // ensure we have 16bit handle only
+ if (handle > 0xFFFF)
+ Log.w(TAG, "Invalid handle");
+
+ modifiedHandle = (modifiedHandle & 0xFFFF);
+
+ switch (type) {
+ case Write:
+ modifiedHandle = (modifiedHandle | 0x00010000);
+ break;
+ case Read:
+ modifiedHandle = (modifiedHandle | 0x00020000);
+ break;
+ case Mtu:
+ modifiedHandle = HANDLE_FOR_MTU_EXCHANGE;
+ break;
+ case Rssi:
+ modifiedHandle = HANDLE_FOR_RSSI_READ;
+ break;
+ }
+
+ return modifiedHandle;
+ }
+
+ // This function is called from Qt thread
+ public synchronized boolean requestConnectionUpdatePriority(double minimalInterval)
+ {
+ if (mBluetoothGatt == null)
+ return false;
+
+ int requestPriority = 0; // BluetoothGatt.CONNECTION_PRIORITY_BALANCED
+ if (minimalInterval < 30)
+ requestPriority = 1; // BluetoothGatt.CONNECTION_PRIORITY_HIGH
+ else if (minimalInterval > 100)
+ requestPriority = 2; //BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER
+
+ try {
+ return mBluetoothGatt.requestConnectionPriority(requestPriority);
+ } catch (IllegalArgumentException ex) {
+ Log.w(TAG, "Connection update priority out of range: " + requestPriority);
+ return false;
+ }
+ }
+
+ public native void leConnectionStateChange(long qtObject, int wasErrorTransition, int newState);
+ public native void leMtuChanged(long qtObject, int mtu);
+ public native void leRemoteRssiRead(long qtObject, int rssi, boolean success);
+ public native void leServicesDiscovered(long qtObject, int errorCode, String uuidList);
+ public native void leServiceDetailDiscoveryFinished(long qtObject, final String serviceUuid,
+ int startHandle, int endHandle);
+ public native void leCharacteristicRead(long qtObject, String serviceUuid,
+ int charHandle, String charUuid,
+ int properties, byte[] data);
+ public native void leDescriptorRead(long qtObject, String serviceUuid, String charUuid,
+ int descHandle, String descUuid, byte[] data);
+ public native void leCharacteristicWritten(long qtObject, int charHandle, byte[] newData,
+ int errorCode);
+ public native void leDescriptorWritten(long qtObject, int charHandle, byte[] newData,
+ int errorCode);
+ public native void leCharacteristicChanged(long qtObject, int charHandle, byte[] newData);
+ public native void leServiceError(long qtObject, int attributeHandle, int errorCode);
+}
+
diff --git a/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLEServer.java b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLEServer.java
new file mode 100644
index 00000000..94601403
--- /dev/null
+++ b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothLEServer.java
@@ -0,0 +1,989 @@
+// 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
+
+package org.qtproject.qt.android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattService;
+import android.content.Context;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattServer;
+import android.bluetooth.BluetoothGattServerCallback;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.le.AdvertiseCallback;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertiseData.Builder;
+import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.os.ParcelUuid;
+import android.os.Build;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.HashMap;
+import java.util.UUID;
+
+public class QtBluetoothLEServer {
+ private static final String TAG = "QtBluetoothGattServer";
+
+ /* Pointer to the Qt object that "owns" the Java object */
+ @SuppressWarnings({"CanBeFinal", "WeakerAccess"})
+ long qtObject = 0;
+ @SuppressWarnings("WeakerAccess")
+
+ private Context qtContext = null;
+
+ // Bluetooth members
+ private BluetoothAdapter mBluetoothAdapter = null;
+ private BluetoothManager mBluetoothManager = null;
+ private BluetoothGattServer mGattServer = null;
+ private BluetoothLeAdvertiser mLeAdvertiser = null;
+
+ private ArrayList<BluetoothGattService> mPendingServiceAdditions =
+ new ArrayList<BluetoothGattService>();
+
+ private String mRemoteName = "";
+ // This function is called from Qt thread
+ public synchronized String remoteName() {
+ return mRemoteName;
+ }
+
+ private String mRemoteAddress = "";
+ // This function is called from Qt thread
+ public synchronized String remoteAddress() {
+ return mRemoteAddress;
+ }
+
+ // BT Core v5.3, 5.2.1, Vol 3, Part G
+ private static final int DEFAULT_LE_ATT_MTU = 23;
+ // Holds the currently supported/used MTU
+ private int mSupportedMtu = DEFAULT_LE_ATT_MTU;
+ // Implementation defined limit
+ private static final int MAX_PENDING_WRITE_COUNT = 1024;
+ // BT Core v5.3, 3.4.6.1, Vol 3, Part F
+ private static final int GATT_ERROR_PREPARE_QUEUE_FULL = 0x9;
+ // BT Core v5.3, 3.2.9, Vol 3, Part F
+ private static final int BTLE_MAX_ATTRIBUTE_VALUE_SIZE = 512;
+
+ // The class stores queued writes from the remote device. The writes are
+ // executed later when instructed to do so by onExecuteWrite() callback.
+ private class WriteEntry {
+ WriteEntry(BluetoothDevice remoteDevice, Object target) {
+ this.remoteDevice = remoteDevice;
+ this.target = target;
+ this.writes = new ArrayList<Pair<byte[], Integer>>();
+ }
+ // Returns true if this is a proper entry for given device + target
+ public boolean match(BluetoothDevice device, Object target) {
+ return remoteDevice.equals(device) && target.equals(target);
+ }
+ public final BluetoothDevice remoteDevice; // Device that issued the writes
+ public final Object target; // Characteristic or Descriptor
+ public final List<Pair<byte[], Integer>> writes; // Value, offset
+ }
+ private final List<WriteEntry> mPendingPreparedWrites = new ArrayList<>();
+
+ // Helper function to clear the pending writes of a remote device. If the provided device
+ // is null, all writes are cleared
+ private void clearPendingPreparedWrites(Object device) {
+ if (device == null)
+ mPendingPreparedWrites.clear();
+ ListIterator<WriteEntry> iterator = mPendingPreparedWrites.listIterator();
+ while (iterator.hasNext()) {
+ if (iterator.next().remoteDevice.equals(device))
+ iterator.remove();
+ }
+ }
+
+ // The function adds a 'prepared write' entry to target's queue. If the "target + device"
+ // didn't have a queue before (this being the first write), the queue is created.
+ // Targets must be either descriptors or characteristics.
+ private int addPendingPreparedWrite(BluetoothDevice device, Object target,
+ int offset, byte[] value) {
+ WriteEntry entry = null;
+ int currentWriteCount = 0;
+
+ // Try to find an existing matching entry. Also while looping, count
+ // the total number of writes so far in order to know if we exceed the
+ // write queue size we have set for ourselves
+ for (WriteEntry e : mPendingPreparedWrites) {
+ if (e.match(device, target))
+ entry = e;
+ currentWriteCount += e.writes.size();
+ }
+
+ // BT Core v5.3, 3.4.6.1, Vol 3, Part F
+ if (currentWriteCount > MAX_PENDING_WRITE_COUNT) {
+ Log.w(TAG, "Prepared write queue is full, returning an error.");
+ return GATT_ERROR_PREPARE_QUEUE_FULL;
+ }
+
+ // If no matching entry, create a new one. This means this is the first prepared
+ // write request to this "device + target" combination
+ if (entry == null)
+ mPendingPreparedWrites.add(entry = new WriteEntry(device, target));
+
+ // Append the newly received chunk of data along with its offset
+ entry.writes.add(new Pair<byte[], Integer>(value, offset));
+ return BluetoothGatt.GATT_SUCCESS;
+ }
+
+ /*
+ As per Bluetooth specification each connected device can have individual and persistent
+ Client characteristic configurations (see Bluetooth Spec 5.0 Vol 3 Part G 3.3.3.3)
+ This class manages the existing configurrations.
+ */
+ private class ClientCharacteristicManager {
+ private final HashMap<BluetoothGattCharacteristic, List<Entry>> notificationStore = new HashMap<BluetoothGattCharacteristic, List<Entry>>();
+
+ private class Entry {
+ BluetoothDevice device = null;
+ byte[] value = null;
+ boolean isConnected = false;
+ }
+
+ public void insertOrUpdate(BluetoothGattCharacteristic characteristic,
+ BluetoothDevice device, byte[] newValue)
+ {
+ if (notificationStore.containsKey(characteristic)) {
+
+ List<Entry> entries = notificationStore.get(characteristic);
+ for (int i = 0; i < entries.size(); i++) {
+ if (entries.get(i).device.equals(device)) {
+ Entry e = entries.get(i);
+ e.value = newValue;
+ entries.set(i, e);
+ return;
+ }
+ }
+
+ // not match so far -> add device to list
+ Entry e = new Entry();
+ e.device = device;
+ e.value = newValue;
+ e.isConnected = true;
+ entries.add(e);
+ return;
+ }
+
+ // new characteristic
+ Entry e = new Entry();
+ e.device = device;
+ e.value = newValue;
+ e.isConnected = true;
+ List<Entry> list = new LinkedList<Entry>();
+ list.add(e);
+ notificationStore.put(characteristic, list);
+ }
+
+ /*
+ Marks client characteristic configuration entries as (in)active based the associated
+ devices general connectivity state.
+ This function avoids that existing configurations are not acted
+ upon when the associated device is not connected.
+ */
+ public void markDeviceConnectivity(BluetoothDevice device, boolean isConnected)
+ {
+ final Iterator<BluetoothGattCharacteristic> keys = notificationStore.keySet().iterator();
+ while (keys.hasNext()) {
+ final BluetoothGattCharacteristic characteristic = keys.next();
+ final List<Entry> entries = notificationStore.get(characteristic);
+ if (entries == null)
+ continue;
+
+ ListIterator<Entry> charConfig = entries.listIterator();
+ while (charConfig.hasNext()) {
+ Entry e = charConfig.next();
+ if (e.device.equals(device))
+ e.isConnected = isConnected;
+ }
+ }
+ }
+
+ // Returns list of all BluetoothDevices which require notification or indication.
+ // No match returns an empty list.
+ List<BluetoothDevice> getToBeUpdatedDevices(BluetoothGattCharacteristic characteristic)
+ {
+ ArrayList<BluetoothDevice> result = new ArrayList<BluetoothDevice>();
+ if (!notificationStore.containsKey(characteristic))
+ return result;
+
+ final ListIterator<Entry> iter = notificationStore.get(characteristic).listIterator();
+ while (iter.hasNext())
+ result.add(iter.next().device);
+
+ return result;
+ }
+
+ // Returns null if no match; otherwise the configured actual client characteristic
+ // configuration value
+ byte[] valueFor(BluetoothGattCharacteristic characteristic, BluetoothDevice device)
+ {
+ if (!notificationStore.containsKey(characteristic))
+ return null;
+
+ List<Entry> entries = notificationStore.get(characteristic);
+ for (int i = 0; i < entries.size(); i++) {
+ final Entry entry = entries.get(i);
+ if (entry.device.equals(device) && entry.isConnected == true)
+ return entries.get(i).value;
+ }
+
+ return null;
+ }
+ }
+
+ private static final UUID CLIENT_CHARACTERISTIC_CONFIGURATION_UUID = UUID
+ .fromString("00002902-0000-1000-8000-00805f9b34fb");
+ ClientCharacteristicManager clientCharacteristicManager = new ClientCharacteristicManager();
+
+ public QtBluetoothLEServer(Context context)
+ {
+ qtContext = context;
+ if (qtContext == null) {
+ Log.w(TAG, "Missing context object. Peripheral role disabled.");
+ return;
+ }
+
+ mBluetoothManager =
+ (BluetoothManager) qtContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ if (mBluetoothManager == null) {
+ Log.w(TAG, "Bluetooth service not available. Peripheral role disabled.");
+ return;
+ }
+
+ mBluetoothAdapter = mBluetoothManager.getAdapter();
+ if (mBluetoothAdapter == null) {
+ Log.w(TAG, "Missing Bluetooth adapter. Peripheral role disabled.");
+ return;
+ }
+
+ Log.w(TAG, "Let's do BTLE Peripheral.");
+ }
+
+ // The following functions are synchronized callback handlers. The callbacks
+ // from Android are forwarded to these methods to synchronize member variable
+ // access with other threads (the Qt thread's JNI calls in particular).
+ //
+ // We use a single lock object (this server) for simplicity because:
+ // - Some variables may change and would thus not be suitable as locking objects but
+ // would require their own additional objects => overhead
+ // - Many accesses to shared variables are infrequent and the code paths are fast and
+ // deterministic meaning that long "wait times" on a lock should not happen
+ // - Typically several shared variables are accessed in a single code block.
+ // If each variable would be protected individually, the amount of (nested) locking
+ // would become quite unreasonable
+
+ public synchronized void handleOnConnectionStateChange(BluetoothDevice device,
+ int status, int newState)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring connection state event, server is disconnected");
+ return;
+ }
+ // Multiple GATT devices may be connected. Check if we still have connected
+ // devices or not, and set the server state accordingly. Note: it seems we get
+ // notifications from all GATT clients, not just from the ones interested in
+ // the services provided by this BT LE Server. Furthermore the list of
+ // currently connected devices does not appear to be in any particular order.
+ List<BluetoothDevice> connectedDevices =
+ mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER);
+ Log.w(TAG, "Device " + device + " connection state: " + newState + ", status: "
+ + status + ", connected devices: " + connectedDevices);
+ // 0 == QLowEnergyController::UnconnectedState
+ // 2 == QLowEnergyController::ConnectedState
+ int qtControllerState = connectedDevices.size() > 0 ? 2 : 0;
+
+ switch (newState) {
+ case BluetoothProfile.STATE_CONNECTED:
+ clientCharacteristicManager.markDeviceConnectivity(device, true);
+ mRemoteName = device.getName();
+ mRemoteAddress = device.getAddress();
+ break;
+ case BluetoothProfile.STATE_DISCONNECTED:
+ clientCharacteristicManager.markDeviceConnectivity(device, false);
+ clearPendingPreparedWrites(device);
+ // Update the remoteAddress and remoteName if needed
+ if (device.getAddress().equals(mRemoteAddress)
+ && !connectedDevices.isEmpty()) {
+ mRemoteName = connectedDevices.get(0).getName();
+ mRemoteAddress = connectedDevices.get(0).getAddress();
+ }
+ break;
+ default:
+ // According to the API doc of this callback this should not happen
+ Log.w(TAG, "Unhandled connection state change: " + newState);
+ return;
+ }
+
+ // If last client disconnected, close down the server
+ if (qtControllerState == 0) { // QLowEnergyController::UnconnectedState
+ mPendingServiceAdditions.clear();
+ mGattServer.close();
+ mGattServer = null;
+ mRemoteName = "";
+ mRemoteAddress = "";
+ mSupportedMtu = DEFAULT_LE_ATT_MTU;
+ }
+
+ int qtErrorCode;
+ switch (status) {
+ case BluetoothGatt.GATT_SUCCESS:
+ qtErrorCode = 0;
+ break;
+ default:
+ Log.w(TAG, "Unhandled error code on peripheral connectionStateChanged: "
+ + status + " " + newState);
+ qtErrorCode = status;
+ break;
+ }
+
+ leConnectionStateChange(qtObject, qtErrorCode, qtControllerState);
+ }
+
+ public synchronized void handleOnServiceAdded(int status, BluetoothGattService service)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring service addition event, server is disconnected");
+ return;
+ }
+
+ Log.d(TAG, "Service " + service.getUuid().toString() + " addition result: " + status);
+
+ // Remove the indicated service from the pending queue
+ ListIterator<BluetoothGattService> iterator = mPendingServiceAdditions.listIterator();
+ while (iterator.hasNext()) {
+ if (iterator.next().getUuid().equals(service.getUuid())) {
+ iterator.remove();
+ break;
+ }
+ }
+
+ // If there are more services in the queue, add the next whose add initiation succeeds
+ iterator = mPendingServiceAdditions.listIterator();
+ while (iterator.hasNext()) {
+ BluetoothGattService nextService = iterator.next();
+ if (mGattServer.addService(nextService)) {
+ break;
+ } else {
+ Log.w(TAG, "Adding service " + nextService.getUuid().toString() + " failed");
+ iterator.remove();
+ }
+ }
+ }
+
+ public synchronized void handleOnCharacteristicReadRequest(BluetoothDevice device,
+ int requestId, int offset,
+ BluetoothGattCharacteristic characteristic)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring characteristic read, server is disconnected");
+ return;
+ }
+
+ byte[] characteristicData =
+ ((QtBluetoothGattCharacteristic)characteristic).getLocalValue();
+
+ try {
+ byte[] dataArray = Arrays.copyOfRange(characteristicData,
+ offset, characteristicData.length);
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,
+ offset, dataArray);
+ } catch (Exception ex) {
+ Log.w(TAG, "onCharacteristicReadRequest: " + requestId + " "
+ + offset + " " + characteristicData.length);
+ ex.printStackTrace();
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE,
+ offset, null);
+ }
+ }
+
+ public synchronized void handleOnCharacteristicWriteRequest(BluetoothDevice device,
+ int requestId,
+ BluetoothGattCharacteristic characteristic,
+ boolean preparedWrite, boolean responseNeeded,
+ int offset, byte[] value)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring characteristic write, server is disconnected");
+ return;
+ }
+ Log.w(TAG, "onCharacteristicWriteRequest " + preparedWrite + " " + offset + " "
+ + value.length);
+ final int minValueLen = ((QtBluetoothGattCharacteristic)characteristic).minValueLength;
+ final int maxValueLen = ((QtBluetoothGattCharacteristic)characteristic).maxValueLength;
+
+ int resultStatus = BluetoothGatt.GATT_SUCCESS;
+ boolean sendNotificationOrIndication = false;
+
+ if (!preparedWrite) { // regular write
+ // User may have defined minimum and maximum size for the value, which
+ // we enforce here. If the user has not defined these limits, the default
+ // values 0..INT_MAX do not limit anything.
+ if (value.length < minValueLen || value.length > maxValueLen) {
+ // BT Core v 5.3, 4.9.3, Vol 3, Part G
+ Log.w(TAG, "onCharacteristicWriteRequest invalid char value length: "
+ + value.length + ", min: " + minValueLen + ", max: " + maxValueLen);
+ resultStatus = BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH;
+ } else if (offset == 0) {
+ ((QtBluetoothGattCharacteristic)characteristic).setLocalValue(value);
+ leServerCharacteristicChanged(qtObject, characteristic, value);
+ sendNotificationOrIndication = true;
+ } else {
+ // This should not really happen as per Bluetooth spec
+ Log.w(TAG, "onCharacteristicWriteRequest: !preparedWrite, offset "
+ + offset + ", Not supported");
+ resultStatus = BluetoothGatt.GATT_INVALID_OFFSET;
+ }
+ } else {
+ // BT Core v5.3, 3.4.6, Vol 3, Part F
+ // This is a prepared write which is used to write characteristics larger than
+ // MTU. We need to record all requests and execute them in one go once
+ // onExecuteWrite() is received. We use a queue to remember the pending
+ // requests.
+ resultStatus = addPendingPreparedWrite(device, characteristic, offset, value);
+ }
+
+ if (responseNeeded)
+ mGattServer.sendResponse(device, requestId, resultStatus, offset, value);
+ if (sendNotificationOrIndication)
+ sendNotificationsOrIndications(characteristic);
+ }
+
+ public synchronized void handleOnDescriptorReadRequest(BluetoothDevice device, int requestId,
+ int offset, BluetoothGattDescriptor descriptor)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring descriptor read, server is disconnected");
+ return;
+ }
+
+ byte[] dataArray = ((QtBluetoothGattDescriptor)descriptor).getLocalValue();
+
+ try {
+ if (descriptor.getUuid().equals(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID)) {
+ dataArray = clientCharacteristicManager.valueFor(
+ descriptor.getCharacteristic(), device);
+ if (dataArray == null)
+ dataArray = ((QtBluetoothGattDescriptor)descriptor).getLocalValue();
+ }
+
+ dataArray = Arrays.copyOfRange(dataArray, offset, dataArray.length);
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS,
+ offset, dataArray);
+ } catch (Exception ex) {
+ Log.w(TAG, "onDescriptorReadRequest: " + requestId + " "
+ + offset + " " + dataArray.length);
+ ex.printStackTrace();
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE,
+ offset, null);
+ }
+ }
+
+ public synchronized void handleOnDescriptorWriteRequest(BluetoothDevice device, int requestId,
+ BluetoothGattDescriptor descriptor, boolean preparedWrite,
+ boolean responseNeeded, int offset, byte[] value)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring descriptor write, server is disconnected");
+ return;
+ }
+
+ Log.w(TAG, "onDescriptorWriteRequest " + preparedWrite + " " + offset + " " + value.length);
+ int resultStatus = BluetoothGatt.GATT_SUCCESS;
+
+ if (!preparedWrite) { // regular write
+ if (offset == 0) {
+ if (descriptor.getUuid().equals(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID)) {
+ // If both IND and NTF are requested, resort to NTF only. BT
+ // specification does not prohibit nor mention using both, but it is
+ // unlikely what the client intended. Stack behaviours vary;
+ // Apple client-side stack does not allow this, while Bluez client-side
+ // stack erroneously sends this even if the developer only asked for
+ // the other. The 0x03 value is a bitwise combination of 0x01 and 0x02
+ // as per specification: BT Core v5.3, 3.3.3.3, Vol 3, Part G
+ if (value[0] == 0x03) {
+ Log.w(TAG, "Warning: In CCC of characteristic: "
+ + descriptor.getCharacteristic().getUuid()
+ + " enabling both NTF & IND requested, enabling NTF only.");
+ value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
+ }
+ clientCharacteristicManager.insertOrUpdate(
+ descriptor.getCharacteristic(),
+ device, value);
+ }
+ ((QtBluetoothGattDescriptor)descriptor).setLocalValue(value);
+ leServerDescriptorWritten(qtObject, descriptor, value);
+ } else {
+ // This should not really happen as per Bluetooth spec
+ Log.w(TAG, "onDescriptorWriteRequest: !preparedWrite, offset "
+ + offset + ", Not supported");
+ resultStatus = BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED;
+ }
+ } else {
+ // BT Core v5.3, 3.4.6, Vol 3, Part F
+ // This is a prepared write which is used to write descriptors larger than MTU.
+ // We need to record all requests and execute them in one go once
+ // onExecuteWrite() is received. We use a queue to remember the pending
+ // requests.
+ resultStatus = addPendingPreparedWrite(device, descriptor, offset, value);
+ }
+
+ if (responseNeeded)
+ mGattServer.sendResponse(device, requestId, resultStatus, offset, value);
+ }
+
+ public synchronized void handleOnExecuteWrite(BluetoothDevice device,
+ int requestId, boolean execute)
+ {
+ if (mGattServer == null) {
+ Log.w(TAG, "Ignoring execute write, server is disconnected");
+ return;
+ }
+
+ Log.w(TAG, "onExecuteWrite " + device + " " + requestId + " " + execute);
+
+ if (execute) {
+ // BT Core v5.3, 3.4.6.3, Vol 3, Part F
+ // Execute all pending prepared writes for the provided 'device'
+ for (WriteEntry entry : mPendingPreparedWrites) {
+ if (!entry.remoteDevice.equals(device))
+ continue;
+
+ byte[] newValue = null;
+ // The target can be a descriptor or a characteristic
+ byte[] currentValue = (entry.target instanceof BluetoothGattCharacteristic)
+ ? ((QtBluetoothGattCharacteristic)entry.target).getLocalValue()
+ : ((QtBluetoothGattDescriptor)entry.target).getLocalValue();
+
+ // Iterate writes and apply them to the currentValue in received order
+ for (Pair<byte[], Integer> write : entry.writes) {
+ // write.first is data, write.second.intValue() is offset. Check
+ // that the offset is not beyond the length of the current value
+ if (write.second.intValue() > currentValue.length) {
+ clearPendingPreparedWrites(device);
+ // BT Core v5.3, 3.4.6.3, Vol 3, Part F
+ mGattServer.sendResponse(device, requestId,
+ BluetoothGatt.GATT_INVALID_OFFSET,
+ 0, null);
+ return;
+ }
+
+ // User may have defined value minimum and maximum sizes for
+ // characteristics, which we enforce here. If the user has not defined
+ // these limits, the default values 0..INT_MAX do not limit anything.
+ // The value size cannot decrease in prepared write (small write is a
+ // partial update) => no check for the minimum size limit here.
+ if (entry.target instanceof QtBluetoothGattCharacteristic &&
+ (write.second.intValue() + write.first.length >
+ ((QtBluetoothGattCharacteristic)entry.target).maxValueLength)) {
+ clearPendingPreparedWrites(device);
+ // BT Core v5.3, 3.4.6.3, Vol 3, Part F
+ mGattServer.sendResponse(device, requestId,
+ BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH,
+ 0, null);
+ return;
+ }
+
+ // Determine the size of the new value as we may be extending the
+ // current value size
+ newValue = new byte[Math.max(write.second.intValue() +
+ write.first.length, currentValue.length)];
+ // Copy the current value to the newValue. We can't use the currentValue
+ // directly because the length of value might increase by this write
+ System.arraycopy(currentValue, 0, newValue, 0, currentValue.length);
+ // Apply this iteration's write to the newValue
+ System.arraycopy(write.first, 0, newValue, write.second.intValue(),
+ write.first.length);
+ // Update the currentValue as there may be more writes to apply
+ currentValue = newValue;
+ }
+
+ // Update value and inform the Qt/C++ side on the update
+ if (entry.target instanceof BluetoothGattCharacteristic) {
+ ((QtBluetoothGattCharacteristic)entry.target).setLocalValue(newValue);
+ leServerCharacteristicChanged(
+ qtObject, (BluetoothGattCharacteristic)entry.target, newValue);
+ } else {
+ ((QtBluetoothGattDescriptor)entry.target).setLocalValue(newValue);
+ leServerDescriptorWritten(
+ qtObject, (BluetoothGattDescriptor)entry.target, newValue);
+ }
+ }
+ }
+ // Either we executed all writes or were asked to cancel.
+ // In any case clear writes and respond.
+ clearPendingPreparedWrites(device);
+ mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
+ }
+
+ public synchronized void handleOnMtuChanged(BluetoothDevice device, int mtu)
+ {
+ if (mSupportedMtu == mtu)
+ return;
+ mSupportedMtu = mtu;
+ leMtuChanged(qtObject, mSupportedMtu);
+ }
+
+ /*
+ * Call back handler for the Gatt Server.
+ */
+ private BluetoothGattServerCallback mGattServerListener = new BluetoothGattServerCallback()
+ {
+ @Override
+ public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
+ super.onConnectionStateChange(device, status, newState);
+ handleOnConnectionStateChange(device, status, newState);
+ }
+
+ @Override
+ public void onServiceAdded(int status, BluetoothGattService service) {
+ super.onServiceAdded(status, service);
+ handleOnServiceAdded(status, service);
+ }
+
+ @Override
+ public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic)
+ {
+ super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
+ handleOnCharacteristicReadRequest(device, requestId, offset, characteristic);
+ }
+
+ @Override
+ public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic,
+ boolean preparedWrite, boolean responseNeeded, int offset, byte[] value)
+ {
+ super.onCharacteristicWriteRequest(device, requestId, characteristic,
+ preparedWrite, responseNeeded, offset, value);
+ handleOnCharacteristicWriteRequest(device, requestId, characteristic,
+ preparedWrite, responseNeeded, offset, value);
+ }
+
+ @Override
+ public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor)
+ {
+ super.onDescriptorReadRequest(device, requestId, offset, descriptor);
+ handleOnDescriptorReadRequest(device, requestId, offset, descriptor);
+ }
+
+ @Override
+ public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor,
+ boolean preparedWrite, boolean responseNeeded, int offset, byte[] value)
+ {
+ super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite,
+ responseNeeded, offset, value);
+ handleOnDescriptorWriteRequest(device, requestId, descriptor, preparedWrite,
+ responseNeeded, offset, value);
+ }
+
+ @Override
+ public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute)
+ {
+ super.onExecuteWrite(device, requestId, execute);
+ handleOnExecuteWrite(device, requestId, execute);
+ }
+
+ @Override
+ public void onNotificationSent(BluetoothDevice device, int status) {
+ super.onNotificationSent(device, status);
+ Log.w(TAG, "onNotificationSent" + device + " " + status);
+ }
+
+ @Override
+ public void onMtuChanged(BluetoothDevice device, int mtu) {
+ handleOnMtuChanged(device, mtu);
+ }
+ };
+
+ // This function is called from Qt thread
+ public synchronized int mtu() {
+ return mSupportedMtu;
+ }
+
+ // This function is called from Qt thread
+ public synchronized boolean connectServer()
+ {
+ if (mGattServer != null)
+ return true;
+
+ BluetoothManager manager = (BluetoothManager) qtContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ if (manager == null) {
+ Log.w(TAG, "Bluetooth service not available.");
+ return false;
+ }
+
+ mGattServer = manager.openGattServer(qtContext, mGattServerListener);
+
+ return (mGattServer != null);
+ }
+
+ // This function is called from Qt thread
+ public synchronized void disconnectServer()
+ {
+ if (mGattServer == null)
+ return;
+
+ clearPendingPreparedWrites(null);
+ mPendingServiceAdditions.clear();
+ mGattServer.close();
+ mGattServer = null;
+
+ mRemoteName = mRemoteAddress = "";
+ leConnectionStateChange(qtObject, 0 /*NoError*/,
+ 0 /*QLowEnergyController::UnconnectedState*/);
+ }
+
+ // This function is called from Qt thread
+ public boolean startAdvertising(AdvertiseData advertiseData,
+ AdvertiseData scanResponse,
+ AdvertiseSettings settings)
+ {
+ // Check that the bluetooth is on
+ if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
+ Log.w(TAG, "StartAdvertising: Bluetooth not available or offline");
+ return false;
+ }
+
+ // According to Android doc this check should always precede the advertiser creation
+ if (mLeAdvertiser == null && mBluetoothAdapter.isMultipleAdvertisementSupported())
+ mLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
+
+ if (mLeAdvertiser == null) {
+ Log.w(TAG, "StartAdvertising: LE advertisement not supported");
+ return false;
+ }
+
+ if (!connectServer()) {
+ Log.w(TAG, "Server::startAdvertising: Cannot open GATT server");
+ return false;
+ }
+
+ Log.w(TAG, "Starting to advertise.");
+ mLeAdvertiser.startAdvertising(settings, advertiseData, scanResponse, mAdvertiseListener);
+
+ return true;
+ }
+
+ // This function is called from Qt thread
+ public void stopAdvertising()
+ {
+ if (mLeAdvertiser == null)
+ return;
+
+ mLeAdvertiser.stopAdvertising(mAdvertiseListener);
+ Log.w(TAG, "Advertisement stopped.");
+ }
+
+ // This function is called from Qt thread
+ public synchronized void addService(BluetoothGattService service)
+ {
+ if (!connectServer()) {
+ Log.w(TAG, "Server::addService: Cannot open GATT server");
+ return;
+ }
+
+ // When we add a service, we must wait for onServiceAdded callback before adding the
+ // next one. If the pending service queue is empty it means that there are no ongoing
+ // service additions => add the service to the server. If there are services in the
+ // queue it means there is an initiated addition ongoing, and we only add to the queue.
+ if (mPendingServiceAdditions.isEmpty()) {
+ if (mGattServer.addService(service))
+ mPendingServiceAdditions.add(service);
+ else
+ Log.w(TAG, "Adding service " + service.getUuid().toString() + " failed.");
+ } else {
+ mPendingServiceAdditions.add(service);
+ }
+ }
+
+ /*
+ Check the client characteristics configuration for the given characteristic
+ and sends notifications or indications as per required.
+
+ This function is called from Qt and Java threads and calls must be protected
+ */
+ private void sendNotificationsOrIndications(BluetoothGattCharacteristic characteristic)
+ {
+ final ListIterator<BluetoothDevice> iter =
+ clientCharacteristicManager.getToBeUpdatedDevices(characteristic).listIterator();
+
+ // TODO This quick loop over multiple devices should be synced with onNotificationSent().
+ // The next notifyCharacteristicChanged() call must wait until onNotificationSent()
+ // was received. At this becomes an issue when the server accepts multiple remote
+ // devices at the same time.
+ while (iter.hasNext()) {
+ final BluetoothDevice device = iter.next();
+ final byte[] clientCharacteristicConfig =
+ clientCharacteristicManager.valueFor(characteristic, device);
+ if (clientCharacteristicConfig != null) {
+ if (Arrays.equals(clientCharacteristicConfig,
+ BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)) {
+ if (Build.VERSION.SDK_INT >= 33) {
+ mGattServer.notifyCharacteristicChanged(device, characteristic, false,
+ ((QtBluetoothGattCharacteristic)characteristic).getLocalValue());
+ } else {
+ mGattServer.notifyCharacteristicChanged(device, characteristic, false);
+ }
+ } else if (Arrays.equals(clientCharacteristicConfig,
+ BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)) {
+ if (Build.VERSION.SDK_INT >= 33) {
+ mGattServer.notifyCharacteristicChanged(device, characteristic, true,
+ ((QtBluetoothGattCharacteristic)characteristic).getLocalValue());
+ } else {
+ mGattServer.notifyCharacteristicChanged(device, characteristic, true);
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ Updates the local database value for the given characteristic with \a charUuid and
+ \a newValue. If notifications for this task are enabled an appropriate notification will
+ be send to the remote client.
+
+ This function is called from the Qt thread.
+ */
+ public boolean writeCharacteristic(BluetoothGattService service, UUID charUuid, byte[] newValue)
+ {
+ BluetoothGattCharacteristic foundChar = null;
+ List<BluetoothGattCharacteristic> charList = service.getCharacteristics();
+ for (BluetoothGattCharacteristic iter: charList) {
+ if (iter.getUuid().equals(charUuid) && foundChar == null) {
+ foundChar = iter;
+ // don't break here since we want to check next condition below on next iteration
+ } else if (iter.getUuid().equals(charUuid)) {
+ Log.w(TAG, "Found second char with same UUID. Wrong char may have been selected.");
+ break;
+ }
+ }
+
+ if (foundChar == null) {
+ Log.w(TAG, "writeCharacteristic: update for unknown characteristic failed");
+ return false;
+ }
+
+ // 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.
+ final int minValueLength = ((QtBluetoothGattCharacteristic)foundChar).minValueLength;
+ final int maxValueLength = ((QtBluetoothGattCharacteristic)foundChar).maxValueLength;
+ if (newValue.length < minValueLength || newValue.length > maxValueLength) {
+ Log.w(TAG, "writeCharacteristic: invalid value length: "
+ + newValue.length + ", min: " + minValueLength + ", max: " + maxValueLength);
+ return false;
+ }
+
+ synchronized (this) // a value update might be in progress
+ {
+ ((QtBluetoothGattCharacteristic)foundChar).setLocalValue(newValue);
+ // Value is updated even if server is not connected, but notifying is not possible
+ if (mGattServer != null)
+ sendNotificationsOrIndications(foundChar);
+ }
+
+ return true;
+ }
+
+ /*
+ Updates the local database value for the given \a descUuid to \a newValue.
+
+ This function is called from the Qt thread.
+ */
+ public boolean writeDescriptor(BluetoothGattService service, UUID charUuid, UUID descUuid,
+ byte[] newValue)
+ {
+ BluetoothGattDescriptor foundDesc = null;
+ BluetoothGattCharacteristic foundChar = null;
+ final List<BluetoothGattCharacteristic> charList = service.getCharacteristics();
+ for (BluetoothGattCharacteristic iter: charList) {
+ if (!iter.getUuid().equals(charUuid))
+ continue;
+
+ if (foundChar == null) {
+ foundChar = iter;
+ } else {
+ Log.w(TAG, "Found second char with same UUID. Wrong char may have been selected.");
+ break;
+ }
+ }
+
+ if (foundChar != null)
+ foundDesc = foundChar.getDescriptor(descUuid);
+
+ if (foundChar == null || foundDesc == null) {
+ Log.w(TAG, "writeDescriptor: update for unknown char or desc failed (" + foundChar + ")");
+ return false;
+ }
+
+ // we even write CLIENT_CHARACTERISTIC_CONFIGURATION_UUID this way as we choose
+ // to interpret the server's call as a change of the default value.
+ synchronized (this) // a value update might be in progress
+ {
+ ((QtBluetoothGattDescriptor)foundDesc).setLocalValue(newValue);
+ }
+
+ return true;
+ }
+
+ /*
+ * Call back handler for Advertisement requests.
+ */
+ private AdvertiseCallback mAdvertiseListener = new AdvertiseCallback()
+ {
+ @Override
+ public void onStartSuccess(AdvertiseSettings settingsInEffect) {
+ super.onStartSuccess(settingsInEffect);
+ }
+
+ @Override
+ public void onStartFailure(int errorCode) {
+ Log.e(TAG, "Advertising failure: " + errorCode);
+ super.onStartFailure(errorCode);
+
+ // changing errorCode here implies changes to errorCode handling on Qt side
+ int qtErrorCode = 0;
+ switch (errorCode) {
+ case AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED:
+ return; // ignore -> noop
+ case AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE:
+ Log.e(TAG, "Please reduce size of advertising data.");
+ qtErrorCode = 1;
+ break;
+ case AdvertiseCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED:
+ qtErrorCode = 2;
+ break;
+ default: // default maps to internal error
+ case AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR:
+ qtErrorCode = 3;
+ break;
+ case AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS:
+ qtErrorCode = 4;
+ break;
+ }
+
+ if (qtErrorCode > 0)
+ leServerAdvertisementError(qtObject, qtErrorCode);
+ }
+ };
+
+ public native void leConnectionStateChange(long qtObject, int errorCode, int newState);
+ public native void leMtuChanged(long qtObject, int mtu);
+ public native void leServerAdvertisementError(long qtObject, int status);
+ public native void leServerCharacteristicChanged(long qtObject,
+ BluetoothGattCharacteristic characteristic,
+ byte[] newValue);
+ public native void leServerDescriptorWritten(long qtObject,
+ BluetoothGattDescriptor descriptor,
+ byte[] newValue);
+}
diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer.java b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothSocketServer.java
index a10b1f62..cc78c5d7 100644
--- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothSocketServer.java
+++ b/src/android/bluetooth/src/org/qtproject/qt/android/bluetooth/QtBluetoothSocketServer.java
@@ -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$
-**
-****************************************************************************/
-
-package org.qtproject.qt5.android.bluetooth;
+// 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
+
+package org.qtproject.qt.android.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothSocket;
+import android.content.Context;
import android.util.Log;
import java.io.IOException;
import java.util.UUID;
@@ -55,6 +21,8 @@ public class QtBluetoothSocketServer extends Thread
long qtObject = 0;
@SuppressWarnings({"WeakerAccess", "CanBeFinal"})
public boolean logEnabled = false;
+ @SuppressWarnings("WeakerAccess")
+ static Context qtContext = null;
private static final String TAG = "QtBluetooth";
private boolean m_isSecure = false;
@@ -67,8 +35,9 @@ public class QtBluetoothSocketServer extends Thread
private static final int QT_LISTEN_FAILED = 1;
private static final int QT_ACCEPT_FAILED = 2;
- public QtBluetoothSocketServer()
+ public QtBluetoothSocketServer(Context context)
{
+ qtContext = context;
setName("QtSocketServerThread");
}
@@ -82,7 +51,15 @@ public class QtBluetoothSocketServer extends Thread
public void run()
{
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ BluetoothManager manager =
+ (BluetoothManager)qtContext.getSystemService(Context.BLUETOOTH_SERVICE);
+
+ if (manager == null) {
+ errorOccurred(qtObject, QT_NO_BLUETOOTH_SUPPORTED);
+ return;
+ }
+
+ BluetoothAdapter adapter = manager.getAdapter();
if (adapter == null) {
errorOccurred(qtObject, QT_NO_BLUETOOTH_SUPPORTED);
return;
@@ -106,6 +83,9 @@ public class QtBluetoothSocketServer extends Thread
return;
}
+ if (isInterrupted()) // close() may have been called
+ return;
+
BluetoothSocket s;
if (m_serverSocket != null) {
try {
@@ -131,6 +111,24 @@ public class QtBluetoothSocketServer extends Thread
Log.d(TAG, "Leaving server socket thread.");
}
+ // This function closes the socket server
+ //
+ // A note on threading behavior
+ // 1. This function is called from Qt thread which is different from the Java thread (run())
+ // 2. The caller of this function expects the Java thread to be finished upon return
+ //
+ // First we mark the Java thread as interrupted, then call close() on the
+ // listening socket if it had been created, and lastly wait for the thread to finish.
+ // The close() method of the socket is intended to be used to abort the accept() from
+ // another thread, as per the accept() documentation.
+ //
+ // If the Java thread was in the middle of creating a socket with the non-blocking
+ // listen* call, the run() will notice after the returning from the listen* that it has
+ // been interrupted and returns early from the run().
+ //
+ // If the Java thread was in the middle of the blocking accept() call, it will get
+ // interrupated by the close() call on the socket. After returning the run() will
+ // notice it has been interrupted and return from the run()
public void close()
{
if (!isAlive())
@@ -143,7 +141,9 @@ public class QtBluetoothSocketServer extends Thread
//interrupts accept() call above
if (m_serverSocket != null)
m_serverSocket.close();
- } catch (IOException ex) {
+ // Wait for the thread to finish
+ join(20); // Maximum wait in ms, typically takes < 1ms
+ } catch (Exception ex) {
Log.d(TAG, "Closing server socket close() failed:" + ex.toString());
ex.printStackTrace();
}
diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java
deleted file mode 100644
index 6b46ec0a..00000000
--- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothBroadcastReceiver.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-package org.qtproject.qt5.android.bluetooth;
-
-import android.app.Activity;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.HashSet;
-import java.util.List;
-
-public class QtBluetoothBroadcastReceiver extends BroadcastReceiver
-{
- /* Pointer to the Qt object that "owns" the Java object */
- @SuppressWarnings("WeakerAccess")
- long qtObject = 0;
- @SuppressWarnings("WeakerAccess")
- static Context qtContext = null;
-
- private static final int TURN_BT_ON = 3330;
- private static final int TURN_BT_DISCOVERABLE = 3331;
- private static final String TAG = "QtBluetoothBroadcastReceiver";
-
- public void onReceive(Context context, Intent intent)
- {
- synchronized (qtContext) {
- if (qtObject == 0)
- return;
-
- jniOnReceive(qtObject, context, intent);
- }
- }
-
- public void unregisterReceiver()
- {
- synchronized (qtContext) {
- qtObject = 0;
- qtContext.unregisterReceiver(this);
- }
- }
-
- public native void jniOnReceive(long qtObject, Context context, Intent intent);
-
- static public void setContext(Context context)
- {
- qtContext = context;
- }
-
- static public void setDiscoverable()
- {
- if (!(qtContext instanceof android.app.Activity)) {
- Log.w(TAG, "Discovery mode cannot be enabled from a service.");
- return;
- }
-
- Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
- intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
- try {
- ((Activity)qtContext).startActivityForResult(intent, TURN_BT_ON);
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
-
- static public void setConnectable()
- {
- if (!(qtContext instanceof android.app.Activity)) {
- Log.w(TAG, "Connectable mode cannot be enabled from a service.");
- return;
- }
-
- Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
- try {
- ((Activity)qtContext).startActivityForResult(intent, TURN_BT_DISCOVERABLE);
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
-
- static public boolean setPairingMode(String address, boolean isPairing)
- {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- try {
- BluetoothDevice device = adapter.getRemoteDevice(address);
- String methodName = "createBond";
- if (!isPairing)
- methodName = "removeBond";
-
- Method m = device.getClass()
- .getMethod(methodName, (Class[]) null);
- m.invoke(device, (Object[]) null);
- } catch (Exception ex) {
- ex.printStackTrace();
- return false;
- }
-
- return true;
- }
-
- /*
- * Returns a list of remote devices confirmed to be connected.
- *
- * This list is not complete as it only detects GATT/BtLE related connections.
- * Unfortunately there is no API that provides the complete list.
- *
- * The function uses Android API v11 & v18. We need to use reflection.
- */
- static public String[] getConnectedDevices()
- {
- try {
- //Bluetooth service name
- Field f = Context.class.getField("BLUETOOTH_SERVICE");
- String serviceValueString = (String)f.get(qtContext);
-
- Class btProfileClz = Class.forName("android.bluetooth.BluetoothProfile");
-
- //value of BluetoothProfile.GATT
- f = btProfileClz.getField("GATT");
- int gatt = f.getInt(null);
-
- //value of BluetoothProfile.GATT_SERVER
- f = btProfileClz.getField("GATT_SERVER");
- int gattServer = f.getInt(null);
-
- //get BluetoothManager instance
- Object bluetoothManager = qtContext.getSystemService(serviceValueString);
-
- Class[] cArg = new Class[1];
- cArg[0] = int.class;
- Method m = bluetoothManager.getClass().getMethod("getConnectedDevices", cArg);
-
- List gattConnections = (List) m.invoke(bluetoothManager, gatt);
- List gattServerConnections = (List) m.invoke(bluetoothManager, gattServer);
-
- //process found remote connections but avoid duplications
- HashSet<String> set = new HashSet<String>();
- for (Object gattConnection : gattConnections)
- set.add(gattConnection.toString());
-
- for (Object gattServerConnection : gattServerConnections)
- set.add(gattServerConnection.toString());
-
- return set.toArray(new String[set.size()]);
- } catch (Exception ex) {
- //API is less than 18
- return new String[0];
- }
- }
-}
diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothInputStreamThread.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothInputStreamThread.java
deleted file mode 100644
index 068febda..00000000
--- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothInputStreamThread.java
+++ /dev/null
@@ -1,104 +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$
-**
-****************************************************************************/
-
-package org.qtproject.qt5.android.bluetooth;
-
-import java.io.InputStream;
-import java.io.IOException;
-import android.util.Log;
-
-@SuppressWarnings("WeakerAccess")
-public class QtBluetoothInputStreamThread extends Thread
-{
- /* Pointer to the Qt object that "owns" the Java object */
- @SuppressWarnings("CanBeFinal")
- long qtObject = 0;
- @SuppressWarnings("CanBeFinal")
- public boolean logEnabled = false;
- private static final String TAG = "QtBluetooth";
- private InputStream m_inputStream = null;
-
- //error codes
- public static final int QT_MISSING_INPUT_STREAM = 0;
- public static final int QT_READ_FAILED = 1;
- public static final int QT_THREAD_INTERRUPTED = 2;
-
- public QtBluetoothInputStreamThread()
- {
- setName("QtBtInputStreamThread");
- }
-
- public void setInputStream(InputStream stream)
- {
- m_inputStream = stream;
- }
-
- public void run()
- {
- if (m_inputStream == null) {
- errorOccurred(qtObject, QT_MISSING_INPUT_STREAM);
- return;
- }
-
- byte[] buffer = new byte[1000];
- int bytesRead;
-
- try {
- while (!isInterrupted()) {
- //this blocks until we see incoming data
- //or close() on related BluetoothSocket is called
- bytesRead = m_inputStream.read(buffer);
- readyData(qtObject, buffer, bytesRead);
- }
-
- errorOccurred(qtObject, QT_THREAD_INTERRUPTED);
- } catch (IOException ex) {
- if (logEnabled)
- Log.d(TAG, "InputStream.read() failed:" + ex.toString());
- ex.printStackTrace();
- errorOccurred(qtObject, QT_READ_FAILED);
- }
-
- if (logEnabled)
- Log.d(TAG, "Leaving input stream thread");
- }
-
- public static native void errorOccurred(long qtObject, int errorCode);
- public static native void readyData(long qtObject, byte[] buffer, int bufferLength);
-}
diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java
deleted file mode 100644
index 8a69b4c7..00000000
--- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLE.java
+++ /dev/null
@@ -1,1532 +0,0 @@
-/****************************************************************************
- **
- ** 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$
- **
- ****************************************************************************/
-
-package org.qtproject.qt5.android.bluetooth;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothGatt;
-import android.bluetooth.BluetoothGattCallback;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.bluetooth.BluetoothGattDescriptor;
-import android.bluetooth.BluetoothGattService;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.le.BluetoothLeScanner;
-import android.bluetooth.le.ScanCallback;
-import android.bluetooth.le.ScanFilter;
-import android.bluetooth.le.ScanResult;
-import android.bluetooth.le.ScanSettings;
-import android.content.Context;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import java.lang.reflect.Method;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.lang.reflect.Method;
-
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.UUID;
-
-
-public class QtBluetoothLE {
- private static final String TAG = "QtBluetoothGatt";
- private final BluetoothAdapter mBluetoothAdapter;
- private boolean mLeScanRunning = false;
-
- private BluetoothGatt mBluetoothGatt = null;
- private String mRemoteGattAddress;
- private final UUID clientCharacteristicUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
- private final int MAX_MTU = 512;
- private final int DEFAULT_MTU = 23;
- private int mSupportedMtu = -1;
-
- /*
- * The atomic synchronizes the timeoutRunnable thread and the response thread for the pending
- * I/O job. Whichever thread comes first will pass the atomic gate. The other thread is
- * cut short.
- */
- // handle values above zero are for regular handle specific read/write requests
- // handle values below zero are reserved for handle-independent requests
- private int HANDLE_FOR_RESET = -1;
- private int HANDLE_FOR_MTU_EXCHANGE = -2;
- private AtomicInteger handleForTimeout = new AtomicInteger(HANDLE_FOR_RESET); // implies not running by default
-
- private final int RUNNABLE_TIMEOUT = 3000; // 3 seconds
- private final Handler timeoutHandler = new Handler(Looper.getMainLooper());
-
- /* New BTLE scanner setup since Android SDK v21 */
- private BluetoothLeScanner mBluetoothLeScanner = null;
-
- private class TimeoutRunnable implements Runnable {
- public TimeoutRunnable(int handle) { pendingJobHandle = handle; }
- @Override
- public void run() {
- boolean timeoutStillValid = handleForTimeout.compareAndSet(pendingJobHandle, HANDLE_FOR_RESET);
- if (timeoutStillValid) {
- Log.w(TAG, "****** Timeout for request on handle " + (pendingJobHandle & 0xffff));
- Log.w(TAG, "****** Looks like the peripheral does NOT act in " +
- "accordance to Bluetooth 4.x spec.");
- Log.w(TAG, "****** Please check server implementation. Continuing under " +
- "reservation.");
-
- if (pendingJobHandle > HANDLE_FOR_RESET)
- interruptCurrentIO(pendingJobHandle & 0xffff);
- else if (pendingJobHandle < HANDLE_FOR_RESET)
- interruptCurrentIO(pendingJobHandle);
- }
- }
-
- // contains handle (0xffff) and top 2 byte contain the job type (0xffff0000)
- private int pendingJobHandle = -1;
- };
-
-
- /* Pointer to the Qt object that "owns" the Java object */
- @SuppressWarnings({"CanBeFinal", "WeakerAccess"})
- long qtObject = 0;
- @SuppressWarnings("WeakerAccess")
- Context qtContext = null;
-
- @SuppressWarnings("WeakerAccess")
- public QtBluetoothLE() {
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
- }
-
- public QtBluetoothLE(final String remoteAddress, Context context) {
- this();
- qtContext = context;
- mRemoteGattAddress = remoteAddress;
- }
-
- /*************************************************************/
- /* Device scan */
- /*************************************************************/
-
- /*
- Returns true, if request was successfully completed
- */
- public boolean scanForLeDevice(final boolean isEnabled) {
- if (isEnabled == mLeScanRunning)
- return true;
-
- if (isEnabled) {
- Log.d(TAG, "New BTLE scanning API");
- ScanSettings.Builder settingsBuilder = new ScanSettings.Builder();
- settingsBuilder = settingsBuilder.setScanMode(ScanSettings.SCAN_MODE_BALANCED);
- ScanSettings settings = settingsBuilder.build();
-
- List<ScanFilter> filterList = new ArrayList<ScanFilter>(2);
-
- mBluetoothLeScanner.startScan(filterList, settings, leScanCallback21);
- mLeScanRunning = true;
- } else {
- mBluetoothLeScanner.stopScan(leScanCallback21);
- mLeScanRunning = false;
- }
-
- return (mLeScanRunning == isEnabled);
- }
-
- // Device scan callback (SDK v21+)
- private final ScanCallback leScanCallback21 = new ScanCallback() {
- @Override
- public void onScanResult(int callbackType, ScanResult result) {
- super.onScanResult(callbackType, result);
- leScanResult(qtObject, result.getDevice(), result.getRssi(), result.getScanRecord().getBytes());
- }
-
- @Override
- public void onBatchScanResults(List<ScanResult> results) {
- super.onBatchScanResults(results);
- for (ScanResult result : results)
- leScanResult(qtObject, result.getDevice(), result.getRssi(), result.getScanRecord().getBytes());
-
- }
-
- @Override
- public void onScanFailed(int errorCode) {
- super.onScanFailed(errorCode);
- Log.d(TAG, "BTLE device scan failed with " + errorCode);
- }
- };
-
- public native void leScanResult(long qtObject, BluetoothDevice device, int rssi, byte[] scanRecord);
-
- /*************************************************************/
- /* Service Discovery */
- /*************************************************************/
-
- private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
-
- public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
- if (qtObject == 0)
- return;
-
- int qLowEnergyController_State = 0;
- //This must be in sync with QLowEnergyController::ControllerState
- switch (newState) {
- case BluetoothProfile.STATE_DISCONNECTED:
- qLowEnergyController_State = 0;
- // we disconnected -> get rid of data from previous run
- resetData();
- // reset mBluetoothGatt, reusing same object is not very reliable
- // sometimes it reconnects and sometimes it does not.
- if (mBluetoothGatt != null)
- mBluetoothGatt.close();
- mBluetoothGatt = null;
- break;
- case BluetoothProfile.STATE_CONNECTED:
- qLowEnergyController_State = 2;
- }
-
- //This must be in sync with QLowEnergyController::Error
- int errorCode;
- switch (status) {
- case BluetoothGatt.GATT_SUCCESS:
- errorCode = 0; break; //QLowEnergyController::NoError
- case BluetoothGatt.GATT_FAILURE: // Android's equivalent of "do not know what error it is"
- errorCode = 1; break; //QLowEnergyController::UnknownError
- case 8: // BLE_HCI_CONNECTION_TIMEOUT
- Log.w(TAG, "Connection Error: Try to delay connect() call after previous activity");
- errorCode = 5; break; //QLowEnergyController::ConnectionError
- case 19: // BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION
- case 20: // BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES
- case 21: // BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF
- Log.w(TAG, "The remote host closed the connection");
- errorCode = 7; //QLowEnergyController::RemoteHostClosedError
- break;
- case 22: // BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION
- // Internally, Android maps PIN_OR_KEY_MISSING to GATT_CONN_TERMINATE_LOCAL_HOST
- errorCode = 8; break; //QLowEnergyController::AuthorizationError
- default:
- Log.w(TAG, "Unhandled error code on connectionStateChanged: " + status + " " + newState);
- errorCode = status; break; //TODO deal with all errors
- }
- leConnectionStateChange(qtObject, errorCode, qLowEnergyController_State);
- }
-
- public void onServicesDiscovered(BluetoothGatt gatt, int status) {
- //This must be in sync with QLowEnergyController::Error
- int errorCode;
- StringBuilder builder = new StringBuilder();
- switch (status) {
- case BluetoothGatt.GATT_SUCCESS:
- errorCode = 0; //QLowEnergyController::NoError
- final List<BluetoothGattService> services = mBluetoothGatt.getServices();
- for (BluetoothGattService service: services) {
- builder.append(service.getUuid().toString()).append(" "); //space is separator
- }
- break;
- default:
- Log.w(TAG, "Unhandled error code on onServicesDiscovered: " + status);
- errorCode = status; break; //TODO deal with all errors
- }
- leServicesDiscovered(qtObject, errorCode, builder.toString());
-
- scheduleMtuExchange();
- }
-
- public void onCharacteristicRead(android.bluetooth.BluetoothGatt gatt,
- android.bluetooth.BluetoothGattCharacteristic characteristic,
- int status)
- {
- int foundHandle = -1;
- synchronized (this) {
- foundHandle = handleForCharacteristic(characteristic);
- if (foundHandle == -1 || foundHandle >= entries.size() ) {
- Log.w(TAG, "Cannot find characteristic read request for read notification - handle: " +
- foundHandle + " size: " + entries.size());
-
- //unlock the queue for next item
- synchronized (readWriteQueue) {
- ioJobPending = false;
- }
-
- performNextIO();
- return;
- }
- }
-
- boolean requestTimedOut = !handleForTimeout.compareAndSet(
- modifiedReadWriteHandle(foundHandle, IoJobType.Read), HANDLE_FOR_RESET);
- if (requestTimedOut) {
- Log.w(TAG, "Late char read reply after timeout was hit for handle " + foundHandle);
- // Timeout has hit before this response -> ignore the response
- // no need to unlock ioJobPending -> the timeout has done that already
- return;
- }
-
- GattEntry entry = entries.get(foundHandle);
- final boolean isServiceDiscoveryRun = !entry.valueKnown;
- entry.valueKnown = true;
-
- if (status == BluetoothGatt.GATT_SUCCESS) {
- // Qt manages handles starting at 1, in Java we use a system starting with 0
- //TODO avoid sending service uuid -> service handle should be sufficient
- leCharacteristicRead(qtObject, characteristic.getService().getUuid().toString(),
- foundHandle + 1, characteristic.getUuid().toString(),
- characteristic.getProperties(), characteristic.getValue());
- } else {
- if (isServiceDiscoveryRun) {
- Log.w(TAG, "onCharacteristicRead during discovery error: " + status);
-
- Log.d(TAG, "Non-readable characteristic " + characteristic.getUuid() +
- " for service " + characteristic.getService().getUuid());
- leCharacteristicRead(qtObject, characteristic.getService().getUuid().toString(),
- foundHandle + 1, characteristic.getUuid().toString(),
- characteristic.getProperties(), characteristic.getValue());
- } else {
- // This must be in sync with QLowEnergyService::CharacteristicReadError
- final int characteristicReadError = 5;
- leServiceError(qtObject, foundHandle + 1, characteristicReadError);
- }
- }
-
- if (isServiceDiscoveryRun) {
-
- // last entry of pending service discovery run -> send discovery finished state update
- GattEntry serviceEntry = entries.get(entry.associatedServiceHandle);
- if (serviceEntry.endHandle == foundHandle)
- finishCurrentServiceDiscovery(entry.associatedServiceHandle);
- }
-
- //unlock the queue for next item
- synchronized (readWriteQueue) {
- ioJobPending = false;
- }
-
- performNextIO();
- }
-
- public void onCharacteristicWrite(android.bluetooth.BluetoothGatt gatt,
- android.bluetooth.BluetoothGattCharacteristic characteristic,
- int status)
- {
- if (status != BluetoothGatt.GATT_SUCCESS)
- Log.w(TAG, "onCharacteristicWrite: error " + status);
-
- int handle = handleForCharacteristic(characteristic);
- if (handle == -1) {
- Log.w(TAG,"onCharacteristicWrite: cannot find handle");
- return;
- }
-
- boolean requestTimedOut = !handleForTimeout.compareAndSet(
- modifiedReadWriteHandle(handle, IoJobType.Write), HANDLE_FOR_RESET);
- if (requestTimedOut) {
- Log.w(TAG, "Late char write reply after timeout was hit for handle " + handle);
- // Timeout has hit before this response -> ignore the response
- // no need to unlock ioJobPending -> the timeout has done that already
- return;
- }
-
- int errorCode;
- //This must be in sync with QLowEnergyService::ServiceError
- switch (status) {
- case BluetoothGatt.GATT_SUCCESS:
- errorCode = 0; break; // NoError
- default:
- errorCode = 2; break; // CharacteristicWriteError
- }
-
- synchronized (readWriteQueue) {
- ioJobPending = false;
- }
- leCharacteristicWritten(qtObject, handle+1, characteristic.getValue(), errorCode);
- performNextIO();
- }
-
- public void onCharacteristicChanged(android.bluetooth.BluetoothGatt gatt,
- android.bluetooth.BluetoothGattCharacteristic characteristic)
- {
- int handle = handleForCharacteristic(characteristic);
- if (handle == -1) {
- Log.w(TAG,"onCharacteristicChanged: cannot find handle");
- return;
- }
-
- leCharacteristicChanged(qtObject, handle+1, characteristic.getValue());
- }
-
- public void onDescriptorRead(android.bluetooth.BluetoothGatt gatt,
- android.bluetooth.BluetoothGattDescriptor descriptor,
- int status)
- {
- int foundHandle = -1;
- synchronized (this) {
- foundHandle = handleForDescriptor(descriptor);
- if (foundHandle == -1 || foundHandle >= entries.size() ) {
- Log.w(TAG, "Cannot find descriptor read request for read notification - handle: " +
- foundHandle + " size: " + entries.size());
-
- //unlock the queue for next item
- synchronized (readWriteQueue) {
- ioJobPending = false;
- }
- performNextIO();
- return;
- }
- }
-
- boolean requestTimedOut = !handleForTimeout.compareAndSet(
- modifiedReadWriteHandle(foundHandle, IoJobType.Read), HANDLE_FOR_RESET);
- if (requestTimedOut) {
- Log.w(TAG, "Late descriptor read reply after timeout was hit for handle " +
- foundHandle);
- // Timeout has hit before this response -> ignore the response
- // no need to unlock ioJobPending -> the timeout has done that already
- return;
- }
-
- GattEntry entry = entries.get(foundHandle);
- final boolean isServiceDiscoveryRun = !entry.valueKnown;
- entry.valueKnown = true;
-
- if (status == BluetoothGatt.GATT_SUCCESS) {
- //TODO avoid sending service and characteristic uuid -> handles should be sufficient
- leDescriptorRead(qtObject, descriptor.getCharacteristic().getService().getUuid().toString(),
- descriptor.getCharacteristic().getUuid().toString(), foundHandle + 1,
- descriptor.getUuid().toString(), descriptor.getValue());
- } else {
- if (isServiceDiscoveryRun) {
- // Cannot read but still advertise the fact that we found a descriptor
- // The value will be empty.
- Log.w(TAG, "onDescriptorRead during discovery error: " + status);
- Log.d(TAG, "Non-readable descriptor " + descriptor.getUuid() +
- " for characteristic " + descriptor.getCharacteristic().getUuid() +
- " for service " + descriptor.getCharacteristic().getService().getUuid());
- leDescriptorRead(qtObject, descriptor.getCharacteristic().getService().getUuid().toString(),
- descriptor.getCharacteristic().getUuid().toString(), foundHandle + 1,
- descriptor.getUuid().toString(), descriptor.getValue());
- } else {
- // This must be in sync with QLowEnergyService::DescriptorReadError
- final int descriptorReadError = 6;
- leServiceError(qtObject, foundHandle + 1, descriptorReadError);
- }
-
- }
-
- if (isServiceDiscoveryRun) {
- // last entry of pending service discovery run? ->send discovery finished state update
- GattEntry serviceEntry = entries.get(entry.associatedServiceHandle);
- if (serviceEntry.endHandle == foundHandle) {
- finishCurrentServiceDiscovery(entry.associatedServiceHandle);
- }
-
- /* Some devices preset ClientCharacteristicConfiguration descriptors
- * to enable notifications out of the box. However the additional
- * BluetoothGatt.setCharacteristicNotification call prevents
- * automatic notifications from coming through. Hence we manually set them
- * up here.
- */
- if (descriptor.getUuid().compareTo(clientCharacteristicUuid) == 0) {
- byte[] bytearray = descriptor.getValue();
- final int value = (bytearray != null && bytearray.length > 0) ? bytearray[0] : 0;
- // notification or indication bit set?
- if ((value & 0x03) > 0) {
- Log.d(TAG, "Found descriptor with automatic notifications.");
- mBluetoothGatt.setCharacteristicNotification(
- descriptor.getCharacteristic(), true);
- }
- }
- }
-
- //unlock the queue for next item
- synchronized (readWriteQueue) {
- ioJobPending = false;
- }
-
- performNextIO();
- }
-
- public void onDescriptorWrite(android.bluetooth.BluetoothGatt gatt,
- android.bluetooth.BluetoothGattDescriptor descriptor,
- int status)
- {
- if (status != BluetoothGatt.GATT_SUCCESS)
- Log.w(TAG, "onDescriptorWrite: error " + status);
-
- int handle = handleForDescriptor(descriptor);
-
- boolean requestTimedOut = !handleForTimeout.compareAndSet(
- modifiedReadWriteHandle(handle, IoJobType.Write), HANDLE_FOR_RESET);
- if (requestTimedOut) {
- Log.w(TAG, "Late descriptor write reply after timeout was hit for handle " +
- handle);
- // Timeout has hit before this response -> ignore the response
- // no need to unlock ioJobPending -> the timeout has done that already
- return;
- }
-
- int errorCode;
- //This must be in sync with QLowEnergyService::ServiceError
- switch (status) {
- case BluetoothGatt.GATT_SUCCESS:
- errorCode = 0; break; // NoError
- default:
- errorCode = 3; break; // DescriptorWriteError
- }
-
- synchronized (readWriteQueue) {
- ioJobPending = false;
- }
-
- leDescriptorWritten(qtObject, handle+1, descriptor.getValue(), errorCode);
- performNextIO();
- }
- //TODO Requires Android API 21 which is not available on CI yet.
-// public void onReliableWriteCompleted(android.bluetooth.BluetoothGatt gatt,
-// int status) {
-// System.out.println("onReliableWriteCompleted");
-// }
-//
-// public void onReadRemoteRssi(android.bluetooth.BluetoothGatt gatt,
-// int rssi, int status) {
-// System.out.println("onReadRemoteRssi");
-// }
-
- // requires Android API v21
- public void onMtuChanged(android.bluetooth.BluetoothGatt gatt, int mtu, int status)
- {
- if (status == BluetoothGatt.GATT_SUCCESS) {
- Log.w(TAG, "MTU changed to " + mtu);
- mSupportedMtu = mtu;
- } else {
- Log.w(TAG, "MTU change error " + status + ". New MTU " + mtu);
- mSupportedMtu = DEFAULT_MTU;
- }
-
- boolean requestTimedOut = !handleForTimeout.compareAndSet(
- modifiedReadWriteHandle(HANDLE_FOR_MTU_EXCHANGE, IoJobType.Mtu), HANDLE_FOR_RESET);
- if (requestTimedOut) {
- Log.w(TAG, "Late mtu reply after timeout was hit");
- // Timeout has hit before this response -> ignore the response
- // no need to unlock ioJobPending -> the timeout has done that already
- return;
- }
-
- synchronized (readWriteQueue) {
- ioJobPending = false;
- }
-
- performNextIO();
- }
- };
-
-
- public boolean connect() {
- BluetoothDevice mRemoteGattDevice;
-
- try {
- mRemoteGattDevice = mBluetoothAdapter.getRemoteDevice(mRemoteGattAddress);
- } catch (IllegalArgumentException ex) {
- Log.w(TAG, "Remote address is not valid: " + mRemoteGattAddress);
- return false;
- }
-
- try {
- // BluetoothDevice.connectGatt(Context, boolean, BluetoothGattCallback, int) was
- // officially introduced by Android API v23. Earlier Android versions have a private
- // implementation already though. Let's check at runtime and use it if possible.
- //
- // In general the new connectGatt() seems to be much more reliable than the function
- // that doesn't specify the transport layer.
-
- Class[] args = new Class[4];
- args[0] = android.content.Context.class;
- args[1] = boolean.class;
- args[2] = android.bluetooth.BluetoothGattCallback.class;
- args[3] = int.class;
- Method connectMethod = mRemoteGattDevice.getClass().getDeclaredMethod("connectGatt", args);
- if (connectMethod != null) {
- mBluetoothGatt = (BluetoothGatt) connectMethod.invoke(mRemoteGattDevice, qtContext,
- false, gattCallback,
- 2 /*TRANSPORT_LE*/);
- Log.w(TAG, "Using Android v23 BluetoothDevice.connectGatt()");
- }
- } catch (Exception ex) {
- // fallback to less reliable API 18 version
- mBluetoothGatt = mRemoteGattDevice.connectGatt(qtContext, false, gattCallback);
- }
-
- return mBluetoothGatt != null;
- }
-
- public void disconnect() {
- if (mBluetoothGatt == null)
- return;
-
- mBluetoothGatt.disconnect();
- }
-
- public boolean discoverServices()
- {
- return mBluetoothGatt != null && mBluetoothGatt.discoverServices();
- }
-
- private enum GattEntryType
- {
- Service, Characteristic, CharacteristicValue, Descriptor
- }
- private class GattEntry
- {
- public GattEntryType type;
- public boolean valueKnown = false;
- public BluetoothGattService service = null;
- public BluetoothGattCharacteristic characteristic = null;
- public BluetoothGattDescriptor descriptor = null;
- /*
- * endHandle defined for GattEntryType.Service and GattEntryType.CharacteristicValue
- * If the type is service this is the value of the last Gatt entry belonging to the very
- * same service. If the type is a char value it is the entries index inside
- * the "entries" list.
- */
- public int endHandle = -1;
- // pointer back to the handle that describes the service that this GATT entry belongs to
- public int associatedServiceHandle;
- }
-
- private enum IoJobType
- {
- Read, Write, Mtu
- }
-
- private class ReadWriteJob
- {
- public GattEntry entry;
- public byte[] newValue;
- public int requestedWriteType;
- public IoJobType jobType;
- }
-
- // service uuid -> service handle mapping (there can be more than one service with same uuid)
- private final Hashtable<UUID, List<Integer>> uuidToEntry = new Hashtable<UUID, List<Integer>>(100);
- // index into array is equivalent to handle id
- private final ArrayList<GattEntry> entries = new ArrayList<GattEntry>(100);
- //backlog of to be discovered services
- // TODO remove
- private final LinkedList<Integer> servicesToBeDiscovered = new LinkedList<Integer>();
-
-
- private final LinkedList<ReadWriteJob> readWriteQueue = new LinkedList<ReadWriteJob>();
- private boolean ioJobPending;
-
- /*
- Internal helper function
- Returns the handle id for the given characteristic; otherwise returns -1.
-
- Note that this is the Java handle. The Qt handle is the Java handle +1.
- */
- private int handleForCharacteristic(BluetoothGattCharacteristic characteristic)
- {
- if (characteristic == null)
- return -1;
-
- List<Integer> handles = uuidToEntry.get(characteristic.getService().getUuid());
- if (handles == null || handles.isEmpty())
- return -1;
-
- //TODO for now we assume we always want the first service in case of uuid collision
- int serviceHandle = handles.get(0);
-
- try {
- GattEntry entry;
- for (int i = serviceHandle+1; i < entries.size(); i++) {
- entry = entries.get(i);
- if (entry == null)
- continue;
-
- switch (entry.type) {
- case Descriptor:
- case CharacteristicValue:
- continue;
- case Service:
- break;
- case Characteristic:
- if (entry.characteristic == characteristic)
- return i;
- break;
- }
- }
- } catch (IndexOutOfBoundsException ex) { /*nothing*/ }
- return -1;
- }
-
- /*
- Internal helper function
- Returns the handle id for the given descriptor; otherwise returns -1.
-
- Note that this is the Java handle. The Qt handle is the Java handle +1.
- */
- private int handleForDescriptor(BluetoothGattDescriptor descriptor)
- {
- if (descriptor == null)
- return -1;
-
- List<Integer> handles = uuidToEntry.get(descriptor.getCharacteristic().getService().getUuid());
- if (handles == null || handles.isEmpty())
- return -1;
-
- //TODO for now we assume we always want the first service in case of uuid collision
- int serviceHandle = handles.get(0);
-
- try {
- GattEntry entry;
- for (int i = serviceHandle+1; i < entries.size(); i++) {
- entry = entries.get(i);
- if (entry == null)
- continue;
-
- switch (entry.type) {
- case Characteristic:
- case CharacteristicValue:
- continue;
- case Service:
- break;
- case Descriptor:
- if (entry.descriptor == descriptor)
- return i;
- break;
- }
- }
- } catch (IndexOutOfBoundsException ignored) { }
- return -1;
- }
-
- private void populateHandles()
- {
- // We introduce the notion of artificial handles. While GATT handles
- // are not exposed on Android they help to quickly identify GATT attributes
- // on the C++ side. The Qt Api will not expose the handles
- GattEntry entry = null;
- List<BluetoothGattService> services = mBluetoothGatt.getServices();
- for (BluetoothGattService service: services) {
- GattEntry serviceEntry = new GattEntry();
- serviceEntry.type = GattEntryType.Service;
- serviceEntry.service = service;
- entries.add(serviceEntry);
-
- // remember handle for the service for later update
- int serviceHandle = entries.size() - 1;
- //point to itself -> mostly done for consistence reasons with other entries
- serviceEntry.associatedServiceHandle = serviceHandle;
-
- //some devices may have more than one service with the same uuid
- List<Integer> old = uuidToEntry.get(service.getUuid());
- if (old == null)
- old = new ArrayList<Integer>();
- old.add(entries.size()-1);
- uuidToEntry.put(service.getUuid(), old);
-
- // add all characteristics
- List<BluetoothGattCharacteristic> charList = service.getCharacteristics();
- for (BluetoothGattCharacteristic characteristic: charList) {
- entry = new GattEntry();
- entry.type = GattEntryType.Characteristic;
- entry.characteristic = characteristic;
- entry.associatedServiceHandle = serviceHandle;
- //entry.endHandle = .. undefined
- entries.add(entry);
-
- // this emulates GATT value attributes
- entry = new GattEntry();
- entry.type = GattEntryType.CharacteristicValue;
- entry.associatedServiceHandle = serviceHandle;
- entry.endHandle = entries.size(); // special case -> current index in entries list
- entries.add(entry);
-
- // add all descriptors
- List<BluetoothGattDescriptor> descList = characteristic.getDescriptors();
- for (BluetoothGattDescriptor desc: descList) {
- entry = new GattEntry();
- entry.type = GattEntryType.Descriptor;
- entry.descriptor = desc;
- entry.associatedServiceHandle = serviceHandle;
- //entry.endHandle = .. undefined
- entries.add(entry);
- }
- }
-
- // update endHandle of current service
- serviceEntry.endHandle = entries.size() - 1;
- }
-
- entries.trimToSize();
- }
-
- private void resetData()
- {
- synchronized (this) {
- uuidToEntry.clear();
- entries.clear();
- servicesToBeDiscovered.clear();
- }
-
- // kill all timeout handlers
- timeoutHandler.removeCallbacksAndMessages(null);
- handleForTimeout.set(HANDLE_FOR_RESET);
-
- synchronized (readWriteQueue) {
- readWriteQueue.clear();
- }
- }
-
- public synchronized boolean discoverServiceDetails(String serviceUuid)
- {
- try {
- if (mBluetoothGatt == null)
- return false;
-
- if (entries.isEmpty())
- populateHandles();
-
- GattEntry entry;
- int serviceHandle;
- try {
- UUID service = UUID.fromString(serviceUuid);
- List<Integer> handles = uuidToEntry.get(service);
- if (handles == null || handles.isEmpty()) {
- Log.w(TAG, "Unknown service uuid for current device: " + service.toString());
- return false;
- }
-
- //TODO for now we assume we always want the first service in case of uuid collision
- serviceHandle = handles.get(0);
- entry = entries.get(serviceHandle);
- if (entry == null) {
- Log.w(TAG, "Service with UUID " + service.toString() + " not found");
- return false;
- }
- } catch (IllegalArgumentException ex) {
- //invalid UUID string passed
- Log.w(TAG, "Cannot parse given UUID");
- return false;
- }
-
- if (entry.type != GattEntryType.Service) {
- Log.w(TAG, "Given UUID is not a service UUID: " + serviceUuid);
- return false;
- }
-
- // current service already discovered or under investigation
- if (entry.valueKnown || servicesToBeDiscovered.contains(serviceHandle)) {
- Log.w(TAG, "Service already known or to be discovered");
- return true;
- }
-
- servicesToBeDiscovered.add(serviceHandle);
- scheduleServiceDetailDiscovery(serviceHandle);
- performNextIO();
-
- } catch (Exception ex) {
- ex.printStackTrace();
- return false;
- }
-
- return true;
- }
-
- /*
- Returns the uuids of the services included by the given service. Otherwise returns null.
- Directly called from Qt.
- */
- public String includedServices(String serviceUuid)
- {
- if (mBluetoothGatt == null)
- return null;
-
- UUID uuid;
- try {
- uuid = UUID.fromString(serviceUuid);
- } catch (Exception ex) {
- ex.printStackTrace();
- return null;
- }
-
- //TODO Breaks in case of two services with same uuid
- BluetoothGattService service = mBluetoothGatt.getService(uuid);
- if (service == null)
- return null;
-
- final List<BluetoothGattService> includes = service.getIncludedServices();
- if (includes.isEmpty())
- return null;
-
- StringBuilder builder = new StringBuilder();
- for (BluetoothGattService includedService: includes) {
- builder.append(includedService.getUuid().toString()).append(" "); //space is separator
- }
-
- return builder.toString();
- }
-
- //TODO function not yet used
- private void finishCurrentServiceDiscovery(int handleDiscoveredService)
- {
- Log.w(TAG, "Finished current discovery for service handle " + handleDiscoveredService);
- GattEntry discoveredService = entries.get(handleDiscoveredService);
- discoveredService.valueKnown = true;
- synchronized (this) {
- try {
- servicesToBeDiscovered.removeFirst();
- } catch (NoSuchElementException ex) {
- Log.w(TAG, "Expected queued service but didn't find any");
- }
- }
-
- leServiceDetailDiscoveryFinished(qtObject, discoveredService.service.getUuid().toString(),
- handleDiscoveredService + 1, discoveredService.endHandle + 1);
- }
-
- private boolean executeMtuExchange()
- {
- if (Build.VERSION.SDK_INT >= 21) {
- try {
- Method mtuMethod = mBluetoothGatt.getClass().getDeclaredMethod("requestMtu", int.class);
- if (mtuMethod != null) {
- Boolean success = (Boolean) mtuMethod.invoke(mBluetoothGatt, MAX_MTU);
- if (success.booleanValue()) {
- Log.w(TAG, "MTU change initiated");
- return false;
- } else {
- Log.w(TAG, "MTU change request failed");
- }
- }
- } catch (Exception ex) {}
- }
-
- Log.w(TAG, "Assuming default MTU value of 23 bytes");
-
- mSupportedMtu = DEFAULT_MTU;
- return true;
- }
-
- private void scheduleMtuExchange()
- {
- ReadWriteJob newJob = new ReadWriteJob();
- newJob.jobType = IoJobType.Mtu;
- newJob.entry = null;
-
- synchronized (readWriteQueue) {
- readWriteQueue.add(newJob);
- }
-
- performNextIO();
- }
-
- /*
- Internal Helper function for discoverServiceDetails()
-
- Adds all Gatt entries for the given service to the readWriteQueue to be discovered.
- This function only ever adds read requests to the queue.
-
- //TODO function not yet used
- */
- private void scheduleServiceDetailDiscovery(int serviceHandle)
- {
- GattEntry serviceEntry = entries.get(serviceHandle);
- final int endHandle = serviceEntry.endHandle;
-
- if (serviceHandle == endHandle) {
- Log.w(TAG, "scheduleServiceDetailDiscovery: service is empty; nothing to discover");
- finishCurrentServiceDiscovery(serviceHandle);
- return;
- }
-
- synchronized (readWriteQueue) {
- // entire block inside mutex to ensure all service discovery jobs go in one after the other
- // ensures that serviceDiscovered() signal is sent when required
-
-
- // serviceHandle + 1 -> ignore service handle itself
- for (int i = serviceHandle + 1; i <= endHandle; i++) {
- GattEntry entry = entries.get(i);
-
- switch (entry.type) {
- case Characteristic:
- case Descriptor:
- // we schedule CharacteristicValue for initial discovery to simplify
- // detection of the end of service discovery process
- // performNextIO() ignores CharacteristicValue GATT entries
- case CharacteristicValue:
- break;
- case Service:
- // should not really happen unless endHandle is wrong
- Log.w(TAG, "scheduleServiceDetailDiscovery: wrong endHandle");
- return;
- }
-
- // only descriptor and characteristic fall through to this point
- ReadWriteJob newJob = new ReadWriteJob();
- newJob.entry = entry;
- newJob.jobType = IoJobType.Read;
-
- final boolean result = readWriteQueue.add(newJob);
- if (!result)
- Log.w(TAG, "Cannot add service discovery job for " + serviceEntry.service.getUuid()
- + " on item " + entry.type);
- }
- }
- }
-
- /*************************************************************/
- /* Write Characteristics */
- /*************************************************************/
-
- public boolean writeCharacteristic(int charHandle, byte[] newValue,
- int writeMode)
- {
- if (mBluetoothGatt == null)
- return false;
-
- GattEntry entry;
- try {
- entry = entries.get(charHandle-1); //Qt always uses handles+1
- } catch (IndexOutOfBoundsException ex) {
- ex.printStackTrace();
- return false;
- }
-
- ReadWriteJob newJob = new ReadWriteJob();
- newJob.newValue = newValue;
- newJob.entry = entry;
- newJob.jobType = IoJobType.Write;
-
- // writeMode must be in sync with QLowEnergyService::WriteMode
- switch (writeMode) {
- case 1: //WriteWithoutResponse
- newJob.requestedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE;
- break;
- case 2: //WriteSigned
- newJob.requestedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_SIGNED;
- break;
- default:
- newJob.requestedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT;
- break;
- }
-
- boolean result;
- synchronized (readWriteQueue) {
- result = readWriteQueue.add(newJob);
- }
-
- if (!result) {
- Log.w(TAG, "Cannot add characteristic write request for " + charHandle + " to queue" );
- return false;
- }
-
- performNextIO();
- return true;
- }
-
- /*************************************************************/
- /* Write Descriptors */
- /*************************************************************/
-
- public boolean writeDescriptor(int descHandle, byte[] newValue)
- {
- if (mBluetoothGatt == null)
- return false;
-
- GattEntry entry;
- try {
- entry = entries.get(descHandle-1); //Qt always uses handles+1
- } catch (IndexOutOfBoundsException ex) {
- ex.printStackTrace();
- return false;
- }
-
- ReadWriteJob newJob = new ReadWriteJob();
- newJob.newValue = newValue;
- newJob.entry = entry;
- newJob.requestedWriteType = BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT;
- newJob.jobType = IoJobType.Write;
-
- boolean result;
- synchronized (readWriteQueue) {
- result = readWriteQueue.add(newJob);
- }
-
- if (!result) {
- Log.w(TAG, "Cannot add descriptor write request for " + descHandle + " to queue" );
- return false;
- }
-
- performNextIO();
- return true;
- }
-
- /*************************************************************/
- /* Read Characteristics */
- /*************************************************************/
-
- public boolean readCharacteristic(int charHandle)
- {
- if (mBluetoothGatt == null)
- return false;
-
- GattEntry entry;
- try {
- entry = entries.get(charHandle-1); //Qt always uses handles+1
- } catch (IndexOutOfBoundsException ex) {
- ex.printStackTrace();
- return false;
- }
-
- ReadWriteJob newJob = new ReadWriteJob();
- newJob.entry = entry;
- newJob.jobType = IoJobType.Read;
-
- boolean result;
- synchronized (readWriteQueue) {
- result = readWriteQueue.add(newJob);
- }
-
- if (!result) {
- Log.w(TAG, "Cannot add characteristic read request for " + charHandle + " to queue" );
- return false;
- }
-
- performNextIO();
- return true;
- }
-
- public boolean readDescriptor(int descHandle)
- {
- if (mBluetoothGatt == null)
- return false;
-
- GattEntry entry;
- try {
- entry = entries.get(descHandle-1); //Qt always uses handles+1
- } catch (IndexOutOfBoundsException ex) {
- ex.printStackTrace();
- return false;
- }
-
- ReadWriteJob newJob = new ReadWriteJob();
- newJob.entry = entry;
- newJob.jobType = IoJobType.Read;
-
- boolean result;
- synchronized (readWriteQueue) {
- result = readWriteQueue.add(newJob);
- }
-
- if (!result) {
- Log.w(TAG, "Cannot add descriptor read request for " + descHandle + " to queue" );
- return false;
- }
-
- performNextIO();
- return true;
- }
-
- // Called by TimeoutRunnable if the current I/O job timed out.
- // By the time we reach this point the handleForTimeout counter has already been reset
- // and the regular responses will be blocked off.
- private void interruptCurrentIO(int handle)
- {
- //unlock the queue for next item
- synchronized (readWriteQueue) {
- ioJobPending = false;
- }
-
- performNextIO();
-
- if (handle == HANDLE_FOR_MTU_EXCHANGE)
- return;
-
- try {
- synchronized (this) {
-
- GattEntry entry = entries.get(handle);
- if (entry == null)
- return;
- if (entry.valueKnown)
- return;
- entry.valueKnown = true;
-
- GattEntry serviceEntry = entries.get(entry.associatedServiceHandle);
- if (serviceEntry != null && serviceEntry.endHandle == handle)
- finishCurrentServiceDiscovery(entry.associatedServiceHandle);
- }
- } catch (IndexOutOfBoundsException outOfBounds) {
- Log.w(TAG, "interruptCurrentIO(): Unknown gatt entry, index: "
- + handle + " size: " + entries.size());
- }
- }
-
- /*
- The queuing is required because two writeCharacteristic/writeDescriptor calls
- cannot execute at the same time. The second write must happen after the
- previous write has finished with on(Characteristic|Descriptor)Write().
- */
- private void performNextIO()
- {
- if (mBluetoothGatt == null)
- return;
-
- boolean skip = false;
- final ReadWriteJob nextJob;
- int handle = HANDLE_FOR_RESET;
-
- synchronized (readWriteQueue) {
- if (readWriteQueue.isEmpty() || ioJobPending)
- return;
-
- nextJob = readWriteQueue.remove();
- if (nextJob.jobType == IoJobType.Mtu) {
- handle = HANDLE_FOR_MTU_EXCHANGE; //mtu request is special case
- } else {
- switch (nextJob.entry.type) {
- case Characteristic:
- handle = handleForCharacteristic(nextJob.entry.characteristic);
- break;
- case Descriptor:
- handle = handleForDescriptor(nextJob.entry.descriptor);
- break;
- case CharacteristicValue:
- handle = nextJob.entry.endHandle;
- default:
- break;
- }
- }
-
- // timeout handler and handleForTimeout atomic must be setup before
- // executing the request. Sometimes the callback is quicker than executing the
- // remainder of this function. Therefore enable the atomic early such that
- // callback handlers start hanging in the readWriteQueue sync block which
- // we are still occupying here.
- timeoutHandler.removeCallbacksAndMessages(null); // remove any timeout handlers
- handleForTimeout.set(modifiedReadWriteHandle(handle, nextJob.jobType));
-
- switch (nextJob.jobType) {
- case Read:
- skip = executeReadJob(nextJob);
- break;
- case Write:
- skip = executeWriteJob(nextJob);
- break;
- case Mtu:
- skip = executeMtuExchange();
- break;
- }
-
- if (skip) {
- handleForTimeout.set(HANDLE_FOR_RESET); // not a pending call -> release atomic
- } else {
- ioJobPending = true;
- timeoutHandler.postDelayed(new TimeoutRunnable(
- modifiedReadWriteHandle(handle, nextJob.jobType)), RUNNABLE_TIMEOUT);
- }
-
- if (nextJob.jobType != IoJobType.Mtu) {
- Log.w(TAG, "Performing queued job, handle: " + handle + " " + nextJob.jobType + " (" +
- (nextJob.requestedWriteType == BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE) +
- ") ValueKnown: " + nextJob.entry.valueKnown + " Skipping: " + skip +
- " " + nextJob.entry.type);
- }
- }
-
- GattEntry entry = nextJob.entry;
-
- if (skip) {
- /*
- BluetoothGatt.[read|write][Characteristic|Descriptor]() immediately
- return in cases where meta data doesn't match the intended action
- (e.g. trying to write to read-only char). When this happens
- we have to report an error back to Qt. The error report is not required during
- the initial service discovery though.
- */
- if (handle > HANDLE_FOR_RESET) {
- // during service discovery we do not report error but emit characteristicRead()
- // any other time a failure emits serviceError() signal
-
- final boolean isServiceDiscovery = !entry.valueKnown;
-
- if (isServiceDiscovery) {
- entry.valueKnown = true;
- switch (entry.type) {
- case Characteristic:
- Log.d(TAG, "Non-readable characteristic " + entry.characteristic.getUuid() +
- " for service " + entry.characteristic.getService().getUuid());
- leCharacteristicRead(qtObject, entry.characteristic.getService().getUuid().toString(),
- handle + 1, entry.characteristic.getUuid().toString(),
- entry.characteristic.getProperties(), entry.characteristic.getValue());
- break;
- case Descriptor:
- // atm all descriptor types are readable
- Log.d(TAG, "Non-readable descriptor " + entry.descriptor.getUuid() +
- " for service/char" + entry.descriptor.getCharacteristic().getService().getUuid() +
- "/" + entry.descriptor.getCharacteristic().getUuid());
- leDescriptorRead(qtObject,
- entry.descriptor.getCharacteristic().getService().getUuid().toString(),
- entry.descriptor.getCharacteristic().getUuid().toString(),
- handle + 1, entry.descriptor.getUuid().toString(),
- entry.descriptor.getValue());
- break;
- case CharacteristicValue:
- // for more details see scheduleServiceDetailDiscovery(int)
- break;
- case Service:
- Log.w(TAG, "Scheduling of Service Gatt entry for service discovery should never happen.");
- break;
- }
-
- // last entry of current discovery run?
- synchronized (this) {
- try {
- GattEntry serviceEntry = entries.get(entry.associatedServiceHandle);
- if (serviceEntry.endHandle == handle)
- finishCurrentServiceDiscovery(entry.associatedServiceHandle);
- } catch (IndexOutOfBoundsException outOfBounds) {
- Log.w(TAG, "performNextIO(): Unknown service for entry, index: "
- + entry.associatedServiceHandle + " size: " + entries.size());
- }
- }
- } else {
- int errorCode = 0;
-
- // The error codes below must be in sync with QLowEnergyService::ServiceError
- if (nextJob.jobType == IoJobType.Read) {
- errorCode = (entry.type == GattEntryType.Characteristic) ?
- 5 : 6; // CharacteristicReadError : DescriptorReadError
- } else {
- errorCode = (entry.type == GattEntryType.Characteristic) ?
- 2 : 3; // CharacteristicWriteError : DescriptorWriteError
- }
-
- leServiceError(qtObject, handle + 1, errorCode);
- }
- }
-
- performNextIO();
- }
- }
-
- // Runs inside the Mutex on readWriteQueue.
- // Returns true if nextJob should be skipped.
- private boolean executeWriteJob(ReadWriteJob nextJob)
- {
- boolean result;
- switch (nextJob.entry.type) {
- case Characteristic:
- if (nextJob.entry.characteristic.getWriteType() != nextJob.requestedWriteType) {
- nextJob.entry.characteristic.setWriteType(nextJob.requestedWriteType);
- }
- result = nextJob.entry.characteristic.setValue(nextJob.newValue);
- if (!result || !mBluetoothGatt.writeCharacteristic(nextJob.entry.characteristic))
- return true;
- break;
- case Descriptor:
- if (nextJob.entry.descriptor.getUuid().compareTo(clientCharacteristicUuid) == 0) {
- /*
- For some reason, Android splits characteristic notifications
- into two operations. BluetoothGatt.enableCharacteristicNotification
- ensures the local Bluetooth stack forwards the notifications. In addition,
- BluetoothGattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
- must be written to the peripheral.
- */
-
-
- /* There is no documentation on indication behavior. The assumption is
- that when indication or notification are requested we call
- BluetoothGatt.setCharacteristicNotification. Furthermore it is assumed
- indications are send via onCharacteristicChanged too and Android itself
- will do the confirmation required for an indication as per
- Bluetooth spec Vol 3, Part G, 4.11 . If neither of the two bits are set
- we disable the signals.
- */
- boolean enableNotifications = false;
- int value = (nextJob.newValue[0] & 0xff);
- // first or second bit must be set
- if (((value & 0x1) == 1) || (((value >> 1) & 0x1) == 1)) {
- enableNotifications = true;
- }
-
- result = mBluetoothGatt.setCharacteristicNotification(
- nextJob.entry.descriptor.getCharacteristic(), enableNotifications);
- if (!result) {
- Log.w(TAG, "Cannot set characteristic notification");
- //we continue anyway to ensure that we write the requested value
- //to the device
- }
-
- Log.d(TAG, "Enable notifications: " + enableNotifications);
- }
-
- result = nextJob.entry.descriptor.setValue(nextJob.newValue);
- if (!result || !mBluetoothGatt.writeDescriptor(nextJob.entry.descriptor))
- return true;
- break;
- case Service:
- case CharacteristicValue:
- return true;
- }
- return false;
- }
-
- // Runs inside the Mutex on readWriteQueue.
- // Returns true if nextJob should be skipped.
- private boolean executeReadJob(ReadWriteJob nextJob)
- {
- boolean result;
- switch (nextJob.entry.type) {
- case Characteristic:
- try {
- result = mBluetoothGatt.readCharacteristic(nextJob.entry.characteristic);
- } catch (java.lang.SecurityException se) {
- // QTBUG-59917 -> HID services cause problems since Android 5.1
- se.printStackTrace();
- result = false;
- }
- if (!result)
- return true; // skip
- break;
- case Descriptor:
- try {
- result = mBluetoothGatt.readDescriptor(nextJob.entry.descriptor);
- } catch (java.lang.SecurityException se) {
- // QTBUG-59917 -> HID services cause problems since Android 5.1
- se.printStackTrace();
- result = false;
- }
- if (!result)
- return true; // skip
- break;
- case Service:
- return true;
- case CharacteristicValue:
- return true; //skip
- }
- return false;
- }
-
- /*
- * Modifies and returns the given \a handle such that the job
- * \a type is encoded into the returned handle. Hereby we take advantage of the fact that
- * a Bluetooth Low Energy handle is only 16 bit. The handle will be the bottom two bytes
- * and the job type will be in the top 2 bytes.
- *
- * top 2 bytes
- * - 0x01 -> Read Job
- * - 0x02 -> Write Job
- *
- * This is done in connection with handleForTimeout and assists in the process of
- * detecting accidental interruption by the timeout handler.
- * If two requests for the same handle are scheduled behind each other there is the
- * theoretical chance that the first request comes back normally while the second request
- * is interrupted by the timeout handler. This risk still exists but this function ensures that
- * at least back to back requests of differing types cannot affect each other via the timeout
- * handler.
- */
- private int modifiedReadWriteHandle(int handle, IoJobType type)
- {
- int modifiedHandle = handle;
- // ensure we have 16bit handle only
- if (handle > 0xFFFF)
- Log.w(TAG, "Invalid handle");
-
- modifiedHandle = (modifiedHandle & 0xFFFF);
-
- switch (type) {
- case Write:
- modifiedHandle = (modifiedHandle | 0x00010000);
- break;
- case Read:
- modifiedHandle = (modifiedHandle | 0x00020000);
- break;
- case Mtu:
- modifiedHandle = HANDLE_FOR_MTU_EXCHANGE;
- break;
- }
-
- return modifiedHandle;
- }
-
- // Directly called from public Qt API
- public boolean requestConnectionUpdatePriority(double minimalInterval)
- {
- if (mBluetoothGatt == null)
- return false;
-
- try {
- //Android API v21
- Method connectionUpdateMethod = mBluetoothGatt.getClass().getDeclaredMethod(
- "requestConnectionPriority", int.class);
- if (connectionUpdateMethod == null)
- return false;
-
- int requestPriority = 0; // BluetoothGatt.CONNECTION_PRIORITY_BALANCED
- if (minimalInterval < 30)
- requestPriority = 1; // BluetoothGatt.CONNECTION_PRIORITY_HIGH
- else if (minimalInterval > 100)
- requestPriority = 2; //BluetoothGatt/CONNECTION_PRIORITY_LOW_POWER
-
- Object result = connectionUpdateMethod.invoke(mBluetoothGatt, requestPriority);
- return (Boolean) result;
- } catch (Exception ex) {
- return false;
- }
- }
-
- public native void leConnectionStateChange(long qtObject, int wasErrorTransition, int newState);
- public native void leServicesDiscovered(long qtObject, int errorCode, String uuidList);
- public native void leServiceDetailDiscoveryFinished(long qtObject, final String serviceUuid,
- int startHandle, int endHandle);
- public native void leCharacteristicRead(long qtObject, String serviceUuid,
- int charHandle, String charUuid,
- int properties, byte[] data);
- public native void leDescriptorRead(long qtObject, String serviceUuid, String charUuid,
- int descHandle, String descUuid, byte[] data);
- public native void leCharacteristicWritten(long qtObject, int charHandle, byte[] newData,
- int errorCode);
- public native void leDescriptorWritten(long qtObject, int charHandle, byte[] newData,
- int errorCode);
- public native void leCharacteristicChanged(long qtObject, int charHandle, byte[] newData);
- public native void leServiceError(long qtObject, int attributeHandle, int errorCode);
-}
-
diff --git a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLEServer.java b/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLEServer.java
deleted file mode 100644
index cdd16686..00000000
--- a/src/android/bluetooth/src/org/qtproject/qt5/android/bluetooth/QtBluetoothLEServer.java
+++ /dev/null
@@ -1,611 +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$
- **
- ****************************************************************************/
-
-package org.qtproject.qt5.android.bluetooth;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothGattCharacteristic;
-import android.bluetooth.BluetoothGattDescriptor;
-import android.bluetooth.BluetoothGattService;
-import android.content.Context;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothGatt;
-import android.bluetooth.BluetoothGattServer;
-import android.bluetooth.BluetoothGattServerCallback;
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.le.AdvertiseCallback;
-import android.bluetooth.le.AdvertiseData;
-import android.bluetooth.le.AdvertiseData.Builder;
-import android.bluetooth.le.AdvertiseSettings;
-import android.bluetooth.le.BluetoothLeAdvertiser;
-import android.os.ParcelUuid;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.HashMap;
-import java.util.UUID;
-
-public class QtBluetoothLEServer {
- private static final String TAG = "QtBluetoothGattServer";
-
- /* Pointer to the Qt object that "owns" the Java object */
- @SuppressWarnings({"CanBeFinal", "WeakerAccess"})
- long qtObject = 0;
- @SuppressWarnings("WeakerAccess")
-
- private Context qtContext = null;
-
- // Bluetooth members
- private final BluetoothAdapter mBluetoothAdapter;
- private BluetoothGattServer mGattServer = null;
- private BluetoothLeAdvertiser mLeAdvertiser = null;
-
- private String mRemoteName = "";
- public String remoteName() { return mRemoteName; }
-
- private String mRemoteAddress = "";
- public String remoteAddress() { return mRemoteAddress; }
-
- /*
- As per Bluetooth specification each connected device can have individual and persistent
- Client characteristic configurations (see Bluetooth Spec 5.0 Vol 3 Part G 3.3.3.3)
- This class manages the existing configurrations.
- */
- private class ClientCharacteristicManager {
- private final HashMap<BluetoothGattCharacteristic, List<Entry>> notificationStore = new HashMap<BluetoothGattCharacteristic, List<Entry>>();
-
- private class Entry {
- BluetoothDevice device = null;
- byte[] value = null;
- boolean isConnected = false;
- }
-
- public void insertOrUpdate(BluetoothGattCharacteristic characteristic,
- BluetoothDevice device, byte[] newValue)
- {
- if (notificationStore.containsKey(characteristic)) {
-
- List<Entry> entries = notificationStore.get(characteristic);
- for (int i = 0; i < entries.size(); i++) {
- if (entries.get(i).device.equals(device)) {
- Entry e = entries.get(i);
- e.value = newValue;
- entries.set(i, e);
- return;
- }
- }
-
- // not match so far -> add device to list
- Entry e = new Entry();
- e.device = device;
- e.value = newValue;
- e.isConnected = true;
- entries.add(e);
- return;
- }
-
- // new characteristic
- Entry e = new Entry();
- e.device = device;
- e.value = newValue;
- e.isConnected = true;
- List<Entry> list = new LinkedList<Entry>();
- list.add(e);
- notificationStore.put(characteristic, list);
- }
-
- /*
- Marks client characteristic configuration entries as (in)active based the associated
- devices general connectivity state.
- This function avoids that existing configurations are not acted
- upon when the associated device is not connected.
- */
- public void markDeviceConnectivity(BluetoothDevice device, boolean isConnected)
- {
- final Iterator<BluetoothGattCharacteristic> keys = notificationStore.keySet().iterator();
- while (keys.hasNext()) {
- final BluetoothGattCharacteristic characteristic = keys.next();
- final List<Entry> entries = notificationStore.get(characteristic);
- if (entries == null)
- continue;
-
- ListIterator<Entry> charConfig = entries.listIterator();
- while (charConfig.hasNext()) {
- Entry e = charConfig.next();
- if (e.device.equals(device))
- e.isConnected = isConnected;
- }
- }
- }
-
- // Returns list of all BluetoothDevices which require notification or indication.
- // No match returns an empty list.
- List<BluetoothDevice> getToBeUpdatedDevices(BluetoothGattCharacteristic characteristic)
- {
- ArrayList<BluetoothDevice> result = new ArrayList<BluetoothDevice>();
- if (!notificationStore.containsKey(characteristic))
- return result;
-
- final ListIterator<Entry> iter = notificationStore.get(characteristic).listIterator();
- while (iter.hasNext())
- result.add(iter.next().device);
-
- return result;
- }
-
- // Returns null if no match; otherwise the configured actual client characteristic
- // configuration value
- byte[] valueFor(BluetoothGattCharacteristic characteristic, BluetoothDevice device)
- {
- if (!notificationStore.containsKey(characteristic))
- return null;
-
- List<Entry> entries = notificationStore.get(characteristic);
- for (int i = 0; i < entries.size(); i++) {
- final Entry entry = entries.get(i);
- if (entry.device.equals(device) && entry.isConnected == true)
- return entries.get(i).value;
- }
-
- return null;
- }
- }
-
- private static final UUID CLIENT_CHARACTERISTIC_CONFIGURATION_UUID = UUID
- .fromString("00002902-0000-1000-8000-00805f9b34fb");
- ClientCharacteristicManager clientCharacteristicManager = new ClientCharacteristicManager();
-
- public QtBluetoothLEServer(Context context)
- {
- qtContext = context;
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-
- if (mBluetoothAdapter == null || qtContext == null) {
- Log.w(TAG, "Missing Bluetooth adapter or Qt context. Peripheral role disabled.");
- return;
- }
-
- BluetoothManager manager = (BluetoothManager) qtContext.getSystemService(Context.BLUETOOTH_SERVICE);
- if (manager == null) {
- Log.w(TAG, "Bluetooth service not available.");
- return;
- }
-
- mLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
-
- if (!mBluetoothAdapter.isMultipleAdvertisementSupported())
- Log.w(TAG, "Device does not support Bluetooth Low Energy advertisement.");
- else
- Log.w(TAG, "Let's do BTLE Peripheral.");
- }
-
- /*
- * Call back handler for the Gatt Server.
- */
- private BluetoothGattServerCallback mGattServerListener = new BluetoothGattServerCallback()
- {
- @Override
- public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
- Log.w(TAG, "Our gatt server connection state changed, new state: " + newState + " " + status);
- super.onConnectionStateChange(device, status, newState);
-
- int qtControllerState = 0;
- switch (newState) {
- case BluetoothProfile.STATE_DISCONNECTED:
- qtControllerState = 0; // QLowEnergyController::UnconnectedState
- clientCharacteristicManager.markDeviceConnectivity(device, false);
- mGattServer.close();
- break;
- case BluetoothProfile.STATE_CONNECTED:
- clientCharacteristicManager.markDeviceConnectivity(device, true);
- qtControllerState = 2; // QLowEnergyController::ConnectedState
- break;
- }
-
- mRemoteName = device.getName();
- mRemoteAddress = device.getAddress();
-
- int qtErrorCode;
- switch (status) {
- case BluetoothGatt.GATT_SUCCESS:
- qtErrorCode = 0; break;
- default:
- Log.w(TAG, "Unhandled error code on peripheral connectionStateChanged: " + status + " " + newState);
- qtErrorCode = status;
- break;
- }
-
- leServerConnectionStateChange(qtObject, qtErrorCode, qtControllerState);
- }
-
- @Override
- public void onServiceAdded(int status, BluetoothGattService service) {
- super.onServiceAdded(status, service);
- }
-
- @Override
- public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic)
- {
- byte[] dataArray;
- try {
- dataArray = Arrays.copyOfRange(characteristic.getValue(), offset, characteristic.getValue().length);
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, dataArray);
- } catch (Exception ex) {
- Log.w(TAG, "onCharacteristicReadRequest: " + requestId + " " + offset + " " + characteristic.getValue().length);
- ex.printStackTrace();
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, offset, null);
- }
-
- super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
- }
-
- @Override
- public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic,
- boolean preparedWrite, boolean responseNeeded, int offset, byte[] value)
- {
- Log.w(TAG, "onCharacteristicWriteRequest");
- int resultStatus = BluetoothGatt.GATT_SUCCESS;
- boolean sendNotificationOrIndication = false;
- if (!preparedWrite) { // regular write
- if (offset == 0) {
- characteristic.setValue(value);
- leServerCharacteristicChanged(qtObject, characteristic, value);
- sendNotificationOrIndication = true;
- } else {
- // This should not really happen as per Bluetooth spec
- Log.w(TAG, "onCharacteristicWriteRequest: !preparedWrite, offset " + offset + ", Not supported");
- resultStatus = BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED;
- }
-
-
- } else {
- Log.w(TAG, "onCharacteristicWriteRequest: preparedWrite, offset " + offset + ", Not supported");
- resultStatus = BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED;
-
- // TODO we need to record all requests and execute them in one go once onExecuteWrite() is received
- // we use a queue to remember the pending requests
- // TODO we are ignoring the device identificator for now -> Bluetooth spec requires a queue per device
- }
-
-
- if (responseNeeded)
- mGattServer.sendResponse(device, requestId, resultStatus, offset, value);
- if (sendNotificationOrIndication)
- sendNotificationsOrIndications(characteristic);
-
- super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
- }
-
- @Override
- public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor)
- {
- byte[] dataArray = descriptor.getValue();
- try {
- if (descriptor.getUuid().equals(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID)) {
- dataArray = clientCharacteristicManager.valueFor(descriptor.getCharacteristic(), device);
- if (dataArray == null)
- dataArray = descriptor.getValue();
- }
-
- dataArray = Arrays.copyOfRange(dataArray, offset, dataArray.length);
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, dataArray);
- } catch (Exception ex) {
- Log.w(TAG, "onDescriptorReadRequest: " + requestId + " " + offset + " " + dataArray.length);
- ex.printStackTrace();
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, offset, null);
- }
-
- super.onDescriptorReadRequest(device, requestId, offset, descriptor);
- }
-
- @Override
- public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor,
- boolean preparedWrite, boolean responseNeeded, int offset, byte[] value)
- {
- int resultStatus = BluetoothGatt.GATT_SUCCESS;
- if (!preparedWrite) { // regular write
- if (offset == 0) {
- descriptor.setValue(value);
-
- if (descriptor.getUuid().equals(CLIENT_CHARACTERISTIC_CONFIGURATION_UUID)) {
- clientCharacteristicManager.insertOrUpdate(descriptor.getCharacteristic(),
- device, value);
- }
-
- leServerDescriptorWritten(qtObject, descriptor, value);
- } else {
- // This should not really happen as per Bluetooth spec
- Log.w(TAG, "onDescriptorWriteRequest: !preparedWrite, offset " + offset + ", Not supported");
- resultStatus = BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED;
- }
-
-
- } else {
- Log.w(TAG, "onDescriptorWriteRequest: preparedWrite, offset " + offset + ", Not supported");
- resultStatus = BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED;
- // TODO we need to record all requests and execute them in one go once onExecuteWrite() is received
- // we use a queue to remember the pending requests
- // TODO we are ignoring the device identificator for now -> Bluetooth spec requires a queue per device
- }
-
-
- if (responseNeeded)
- mGattServer.sendResponse(device, requestId, resultStatus, offset, value);
-
- super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
- }
-
- @Override
- public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute)
- {
- // TODO not yet implemented -> return proper GATT error for it
- mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED, 0, null);
-
- super.onExecuteWrite(device, requestId, execute);
- }
-
- @Override
- public void onNotificationSent(BluetoothDevice device, int status) {
- super.onNotificationSent(device, status);
- Log.w(TAG, "onNotificationSent" + device + " " + status);
- }
-
- // MTU change disabled since it requires API level 22. Right now we only enforce lvl 21
-// @Override
-// public void onMtuChanged(BluetoothDevice device, int mtu) {
-// super.onMtuChanged(device, mtu);
-// }
- };
-
- public boolean connectServer()
- {
- if (mGattServer != null)
- return true;
-
- BluetoothManager manager = (BluetoothManager) qtContext.getSystemService(Context.BLUETOOTH_SERVICE);
- if (manager == null) {
- Log.w(TAG, "Bluetooth service not available.");
- return false;
- }
-
- mGattServer = manager.openGattServer(qtContext, mGattServerListener);
-
- return (mGattServer != null);
- }
-
- public void disconnectServer()
- {
- if (mGattServer == null)
- return;
-
- mGattServer.close();
- mGattServer = null;
-
- mRemoteName = mRemoteAddress = "";
- leServerConnectionStateChange(qtObject, 0 /*NoError*/, 0 /*QLowEnergyController::UnconnectedState*/);
- }
-
- public boolean startAdvertising(AdvertiseData advertiseData,
- AdvertiseData scanResponse,
- AdvertiseSettings settings)
- {
- if (mLeAdvertiser == null)
- return false;
-
- if (!connectServer()) {
- Log.w(TAG, "Server::startAdvertising: Cannot open GATT server");
- return false;
- }
-
- Log.w(TAG, "Starting to advertise.");
- mLeAdvertiser.startAdvertising(settings, advertiseData, scanResponse, mAdvertiseListener);
-
- return true;
- }
-
- public void stopAdvertising()
- {
- if (mLeAdvertiser == null)
- return;
-
- mLeAdvertiser.stopAdvertising(mAdvertiseListener);
- Log.w(TAG, "Advertisement stopped.");
- }
-
- public void addService(BluetoothGattService service)
- {
- if (!connectServer()) {
- Log.w(TAG, "Server::addService: Cannot open GATT server");
- return;
- }
-
- mGattServer.addService(service);
- }
-
- /*
- Check the client characteristics configuration for the given characteristic
- and sends notifications or indications as per required.
- */
- private void sendNotificationsOrIndications(BluetoothGattCharacteristic characteristic)
- {
- final ListIterator<BluetoothDevice> iter =
- clientCharacteristicManager.getToBeUpdatedDevices(characteristic).listIterator();
-
- // TODO This quick loop over multiple devices should be synced with onNotificationSent().
- // The next notifyCharacteristicChanged() call must wait until onNotificationSent()
- // was received. At this becomes an issue when the server accepts multiple remote
- // devices at the same time.
- while (iter.hasNext()) {
- final BluetoothDevice device = iter.next();
- final byte[] clientCharacteristicConfig = clientCharacteristicManager.valueFor(characteristic, device);
- if (clientCharacteristicConfig != null) {
- if (Arrays.equals(clientCharacteristicConfig, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)) {
- mGattServer.notifyCharacteristicChanged(device, characteristic, false);
- } else if (Arrays.equals(clientCharacteristicConfig, BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)) {
- mGattServer.notifyCharacteristicChanged(device, characteristic, true);
- }
- }
- }
- }
-
- /*
- Updates the local database value for the given characteristic with \a charUuid and
- \a newValue. If notifications for this task are enabled an approproiate notification will
- be send to the remote client.
-
- This function is called from the Qt thread.
- */
- public boolean writeCharacteristic(BluetoothGattService service, UUID charUuid, byte[] newValue)
- {
- BluetoothGattCharacteristic foundChar = null;
- List<BluetoothGattCharacteristic> charList = service.getCharacteristics();
- for (BluetoothGattCharacteristic iter: charList) {
- if (iter.getUuid().equals(charUuid) && foundChar == null) {
- foundChar = iter;
- // don't break here since we want to check next condition below on next iteration
- } else if (iter.getUuid().equals(charUuid)) {
- Log.w(TAG, "Found second char with same UUID. Wrong char may have been selected.");
- break;
- }
- }
-
- if (foundChar == null) {
- Log.w(TAG, "writeCharacteristic: update for unknown characteristic failed");
- return false;
- }
-
- foundChar.setValue(newValue);
- sendNotificationsOrIndications(foundChar);
-
- return true;
- }
-
- /*
- Updates the local database value for the given \a descUuid to \a newValue.
-
- This function is called from the Qt thread.
- */
- public boolean writeDescriptor(BluetoothGattService service, UUID charUuid, UUID descUuid,
- byte[] newValue)
- {
- BluetoothGattDescriptor foundDesc = null;
- BluetoothGattCharacteristic foundChar = null;
- final List<BluetoothGattCharacteristic> charList = service.getCharacteristics();
- for (BluetoothGattCharacteristic iter: charList) {
- if (!iter.getUuid().equals(charUuid))
- continue;
-
- if (foundChar == null) {
- foundChar = iter;
- } else {
- Log.w(TAG, "Found second char with same UUID. Wrong char may have been selected.");
- break;
- }
- }
-
- if (foundChar != null)
- foundDesc = foundChar.getDescriptor(descUuid);
-
- if (foundChar == null || foundDesc == null) {
- Log.w(TAG, "writeDescriptor: update for unknown char or desc failed (" + foundChar + ")");
- return false;
- }
-
- // we even write CLIENT_CHARACTERISTIC_CONFIGURATION_UUID this way as we choose
- // to interpret the server's call as a change of the default value.
- foundDesc.setValue(newValue);
-
- return true;
- }
-
- /*
- * Call back handler for Advertisement requests.
- */
- private AdvertiseCallback mAdvertiseListener = new AdvertiseCallback()
- {
- @Override
- public void onStartSuccess(AdvertiseSettings settingsInEffect) {
- super.onStartSuccess(settingsInEffect);
- }
-
- @Override
- public void onStartFailure(int errorCode) {
- Log.e(TAG, "Advertising failure: " + errorCode);
- super.onStartFailure(errorCode);
-
- // changing errorCode here implies changes to errorCode handling on Qt side
- int qtErrorCode = 0;
- switch (errorCode) {
- case AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED:
- return; // ignore -> noop
- case AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE:
- qtErrorCode = 1;
- break;
- case AdvertiseCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED:
- qtErrorCode = 2;
- break;
- default: // default maps to internal error
- case AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR:
- qtErrorCode = 3;
- break;
- case AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS:
- qtErrorCode = 4;
- break;
- }
-
- if (qtErrorCode > 0)
- leServerAdvertisementError(qtObject, qtErrorCode);
- }
- };
-
- public native void leServerConnectionStateChange(long qtObject, int errorCode, int newState);
- public native void leServerAdvertisementError(long qtObject, int status);
- public native void leServerCharacteristicChanged(long qtObject,
- BluetoothGattCharacteristic characteristic,
- byte[] newValue);
- public native void leServerDescriptorWritten(long qtObject,
- BluetoothGattDescriptor descriptor,
- byte[] newValue);
-}
diff --git a/src/android/nfc/AndroidManifest.xml b/src/android/nfc/AndroidManifest.xml
index 2ba062ae..30db61fd 100644
--- a/src/android/nfc/AndroidManifest.xml
+++ b/src/android/nfc/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.qtproject.qt5.android.nfc"
+ package="org.qtproject.qt.android.nfc"
android:versionCode="1"
android:versionName="1.0">
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
diff --git a/src/android/nfc/CMakeLists.txt b/src/android/nfc/CMakeLists.txt
new file mode 100644
index 00000000..f16f60c4
--- /dev/null
+++ b/src/android/nfc/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+set(java_sources
+ src/org/qtproject/qt/android/nfc/QtNfc.java
+ src/org/qtproject/qt/android/nfc/QtNfcBroadcastReceiver.java
+)
+
+qt_internal_add_jar(Qt${QtConnectivity_VERSION_MAJOR}AndroidNfc
+ INCLUDE_JARS ${QT_ANDROID_JAR}
+ SOURCES ${java_sources}
+ OUTPUT_DIR "${QT_BUILD_DIR}/jar"
+)
+
+qt_path_join(destination ${INSTALL_DATADIR} "jar")
+
+install_jar(Qt${QtConnectivity_VERSION_MAJOR}AndroidNfc
+ DESTINATION ${destination}
+ COMPONENT Devel
+)
+
+add_dependencies(Nfc Qt${QtConnectivity_VERSION_MAJOR}AndroidNfc)
diff --git a/src/android/nfc/nfc.pro b/src/android/nfc/nfc.pro
deleted file mode 100644
index 66b1d8a4..00000000
--- a/src/android/nfc/nfc.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-TARGET = QtNfc
-
-CONFIG += java
-DESTDIR = $$[QT_INSTALL_PREFIX/get]/jar
-API_VERSION = android-18
-
-PATHPREFIX = $$PWD/src/org/qtproject/qt5/android/nfc
-
-JAVACLASSPATH += $$PWD/src/
-JAVASOURCES += \
- $$PWD/src/org/qtproject/qt5/android/nfc/QtNfc.java \
- $$PWD/src/org/qtproject/qt5/android/nfc/QtNfcBroadcastReceiver.java \
-
-# install
-target.path = $$[QT_INSTALL_PREFIX]/jar
-INSTALLS += target
diff --git a/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java b/src/android/nfc/src/org/qtproject/qt/android/nfc/QtNfc.java
index 19e645f5..9d8cae92 100644
--- a/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java
+++ b/src/android/nfc/src/org/qtproject/qt/android/nfc/QtNfc.java
@@ -1,49 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Centria research and development
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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$
-**
-****************************************************************************/
-
-package org.qtproject.qt5.android.nfc;
-
-import java.lang.Thread;
+// Copyright (C) 2016 Centria research and development
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android.nfc;
+
import java.lang.Runnable;
-import android.os.Parcelable;
-import android.os.Looper;
import android.content.Context;
import android.app.Activity;
import android.app.PendingIntent;
@@ -51,20 +12,18 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NfcAdapter;
import android.content.IntentFilter.MalformedMimeTypeException;
-import android.os.Bundle;
+import android.os.Build;
+import android.os.Parcelable;
import android.util.Log;
-import android.content.BroadcastReceiver;
import android.content.pm.PackageManager;
public class QtNfc
{
- /* static final QtNfc m_nfc = new QtNfc(); */
static private final String TAG = "QtNfc";
- static public NfcAdapter m_adapter = null;
- static public PendingIntent m_pendingIntent = null;
- static public IntentFilter[] m_filters;
- static public Context m_context = null;
- static public Activity m_activity = null;
+ static private NfcAdapter m_adapter = null;
+ static private PendingIntent m_pendingIntent = null;
+ static private Context m_context = null;
+ static private Activity m_activity = null;
static public void setContext(Context context)
{
@@ -78,34 +37,22 @@ public class QtNfc
}
if (m_adapter == null) {
- //Log.e(TAG, "No NFC available");
return;
}
+ // Since Android 12 (API level 31) it's mandatory to specify mutability
+ // of PendingIntent. We need a mutable intent, which was a default
+ // option earlier.
+ int flags = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) ? PendingIntent.FLAG_MUTABLE
+ : 0;
m_pendingIntent = PendingIntent.getActivity(
m_activity,
0,
new Intent(m_activity, m_activity.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
- 0);
-
- //Log.d(TAG, "Pending intent:" + m_pendingIntent);
-
- IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
-
- m_filters = new IntentFilter[]{
- filter
- };
-
- try {
- filter.addDataType("*/*");
- } catch(MalformedMimeTypeException e) {
- throw new RuntimeException("Fail", e);
- }
-
- //Log.d(TAG, "Thread:" + Thread.currentThread().getId());
+ flags);
}
- static public boolean start()
+ static public boolean startDiscovery()
{
if (m_adapter == null || m_activity == null
|| !m_activity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC))
@@ -113,7 +60,6 @@ public class QtNfc
m_activity.runOnUiThread(new Runnable() {
public void run() {
- //Log.d(TAG, "Enabling NFC");
IntentFilter[] filters = new IntentFilter[3];
filters[0] = new IntentFilter();
filters[0].addAction(NfcAdapter.ACTION_TAG_DISCOVERED);
@@ -124,9 +70,9 @@ public class QtNfc
try {
filters[1].addDataType("*/*");
} catch (MalformedMimeTypeException e) {
- throw new RuntimeException("Check your mime type.");
+ throw new RuntimeException("IntentFilter.addDataType() failed");
}
- // some tags will report as tech, even if they are ndef formated/formatable.
+ // some tags will report as tech, even if they are ndef formatted/formattable.
filters[2] = new IntentFilter();
filters[2].addAction(NfcAdapter.ACTION_TECH_DISCOVERED);
String[][] techList = new String[][]{
@@ -144,7 +90,7 @@ public class QtNfc
return true;
}
- static public boolean stop()
+ static public boolean stopDiscovery()
{
if (m_adapter == null || m_activity == null
|| !m_activity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC))
@@ -152,7 +98,6 @@ public class QtNfc
m_activity.runOnUiThread(new Runnable() {
public void run() {
- //Log.d(TAG, "Disabling NFC");
try {
m_adapter.disableForegroundDispatch(m_activity);
} catch(IllegalStateException e) {
@@ -164,10 +109,9 @@ public class QtNfc
return true;
}
- static public boolean isAvailable()
+ static public boolean isEnabled()
{
if (m_adapter == null) {
- //Log.e(TAG, "No NFC available (Adapter is null)");
return false;
}
@@ -193,4 +137,9 @@ public class QtNfc
return null;
}
}
+
+ static public Parcelable getTag(Intent intent)
+ {
+ return intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
+ }
}
diff --git a/src/android/nfc/src/org/qtproject/qt/android/nfc/QtNfcBroadcastReceiver.java b/src/android/nfc/src/org/qtproject/qt/android/nfc/QtNfcBroadcastReceiver.java
new file mode 100644
index 00000000..e70ec9a5
--- /dev/null
+++ b/src/android/nfc/src/org/qtproject/qt/android/nfc/QtNfcBroadcastReceiver.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2018 Governikus GmbH & Co. KG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android.nfc;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.nfc.NfcAdapter;
+
+public class QtNfcBroadcastReceiver extends BroadcastReceiver
+{
+ final private long qtObject;
+ final private Context qtContext;
+
+ public QtNfcBroadcastReceiver(long obj, Context context)
+ {
+ qtObject = obj;
+ qtContext = context;
+ IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
+ qtContext.registerReceiver(this, filter);
+ }
+
+ public void unregisterReceiver()
+ {
+ qtContext.unregisterReceiver(this);
+ }
+
+ public void onReceive(Context context, Intent intent)
+ {
+ final int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, NfcAdapter.STATE_OFF);
+ jniOnReceive(qtObject, state);
+ }
+
+ public native void jniOnReceive(long qtObject, int state);
+}
diff --git a/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfcBroadcastReceiver.java b/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfcBroadcastReceiver.java
deleted file mode 100644
index ea650ede..00000000
--- a/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfcBroadcastReceiver.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Governikus GmbH & Co. KG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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$
-**
-****************************************************************************/
-
-package org.qtproject.qt5.android.nfc;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.nfc.NfcAdapter;
-
-
-public class QtNfcBroadcastReceiver extends BroadcastReceiver
-{
- private Context qtContext;
-
- public QtNfcBroadcastReceiver(Context context)
- {
- qtContext = context;
- IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
- qtContext.registerReceiver(this, filter);
- }
-
- public void unregisterReceiver()
- {
- qtContext.unregisterReceiver(this);
- }
-
- public void onReceive(Context context, Intent intent)
- {
- final int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, NfcAdapter.STATE_OFF);
- jniOnReceive(state);
- }
-
- public native void jniOnReceive(int state);
-}
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
diff --git a/src/imports/bluetooth/bluetooth.pro b/src/imports/bluetooth/bluetooth.pro
deleted file mode 100644
index c4e6e3df..00000000
--- a/src/imports/bluetooth/bluetooth.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-TARGETPATH = QtBluetooth
-
-QT = core quick bluetooth
-
-HEADERS += \
- qdeclarativebluetoothservice_p.h \
- qdeclarativebluetoothsocket_p.h \
- qdeclarativebluetoothdiscoverymodel_p.h
-
-SOURCES += plugin.cpp \
- qdeclarativebluetoothservice.cpp \
- qdeclarativebluetoothsocket.cpp \
- qdeclarativebluetoothdiscoverymodel.cpp
-
-DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
-
-load(qml_plugin)
diff --git a/src/imports/bluetooth/plugin.cpp b/src/imports/bluetooth/plugin.cpp
deleted file mode 100644
index 7c0712a1..00000000
--- a/src/imports/bluetooth/plugin.cpp
+++ /dev/null
@@ -1,84 +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 <QtCore/QLoggingCategory>
-#include <QtQml/QQmlEngine>
-#include <QtQml/QQmlExtensionPlugin>
-
-#include "qdeclarativebluetoothdiscoverymodel_p.h"
-#include "qdeclarativebluetoothservice_p.h"
-#include "qdeclarativebluetoothsocket_p.h"
-
-QT_USE_NAMESPACE
-
-class QBluetoothQmlPlugin : public QQmlExtensionPlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
-public:
- QBluetoothQmlPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
- void registerTypes(const char *uri)
- {
- // @uri QtBluetooth
-
- Q_ASSERT(uri == QStringLiteral("QtBluetooth"));
-
- int major = 5;
- int minor = 0;
-
- // Register the 5.0 types
- //5.0 is silent and not advertised
- qmlRegisterType<QDeclarativeBluetoothDiscoveryModel >(uri, major, minor, "BluetoothDiscoveryModel");
- qmlRegisterType<QDeclarativeBluetoothService >(uri, major, minor, "BluetoothService");
- qmlRegisterType<QDeclarativeBluetoothSocket >(uri, major, minor, "BluetoothSocket");
-
- // Register the 5.2 types
- minor = 2;
- qmlRegisterType<QDeclarativeBluetoothDiscoveryModel >(uri, major, minor, "BluetoothDiscoveryModel");
- qmlRegisterType<QDeclarativeBluetoothService >(uri, major, minor, "BluetoothService");
- qmlRegisterType<QDeclarativeBluetoothSocket >(uri, major, minor, "BluetoothSocket");
-
- // Register the latest Qt version as QML type version
- qmlRegisterModule(uri, QT_VERSION_MAJOR, QT_VERSION_MINOR);
- }
-};
-
-Q_LOGGING_CATEGORY(QT_BT_QML, "qt.bluetooth.qml")
-
-#include "plugin.moc"
diff --git a/src/imports/bluetooth/plugins.qmltypes b/src/imports/bluetooth/plugins.qmltypes
deleted file mode 100644
index 2060b594..00000000
--- a/src/imports/bluetooth/plugins.qmltypes
+++ /dev/null
@@ -1,409 +0,0 @@
-import QtQuick.tooling 1.2
-
-// This file describes the plugin-supplied types contained in the library.
-// It is used for QML tooling purposes only.
-//
-// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtBluetooth 5.14'
-
-Module {
- dependencies: ["QtQuick 2.0"]
- Component {
- name: "QAbstractItemModel"
- prototype: "QObject"
- Enum {
- name: "LayoutChangeHint"
- values: {
- "NoLayoutChangeHint": 0,
- "VerticalSortHint": 1,
- "HorizontalSortHint": 2
- }
- }
- Enum {
- name: "CheckIndexOption"
- values: {
- "NoOption": 0,
- "IndexIsValid": 1,
- "DoNotUseParent": 2,
- "ParentIsInvalid": 4
- }
- }
- Signal {
- name: "dataChanged"
- Parameter { name: "topLeft"; type: "QModelIndex" }
- Parameter { name: "bottomRight"; type: "QModelIndex" }
- Parameter { name: "roles"; type: "QVector<int>" }
- }
- Signal {
- name: "dataChanged"
- Parameter { name: "topLeft"; type: "QModelIndex" }
- Parameter { name: "bottomRight"; type: "QModelIndex" }
- }
- Signal {
- name: "headerDataChanged"
- Parameter { name: "orientation"; type: "Qt::Orientation" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "layoutChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" }
- }
- Signal {
- name: "layoutChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- }
- Signal { name: "layoutChanged" }
- Signal {
- name: "layoutAboutToBeChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" }
- }
- Signal {
- name: "layoutAboutToBeChanged"
- Parameter { name: "parents"; type: "QList<QPersistentModelIndex>" }
- }
- Signal { name: "layoutAboutToBeChanged" }
- Signal {
- name: "rowsAboutToBeInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "rowsInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "rowsAboutToBeRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "rowsRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsAboutToBeInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsInserted"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsAboutToBeRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal {
- name: "columnsRemoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "first"; type: "int" }
- Parameter { name: "last"; type: "int" }
- }
- Signal { name: "modelAboutToBeReset" }
- Signal { name: "modelReset" }
- Signal {
- name: "rowsAboutToBeMoved"
- Parameter { name: "sourceParent"; type: "QModelIndex" }
- Parameter { name: "sourceStart"; type: "int" }
- Parameter { name: "sourceEnd"; type: "int" }
- Parameter { name: "destinationParent"; type: "QModelIndex" }
- Parameter { name: "destinationRow"; type: "int" }
- }
- Signal {
- name: "rowsMoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "start"; type: "int" }
- Parameter { name: "end"; type: "int" }
- Parameter { name: "destination"; type: "QModelIndex" }
- Parameter { name: "row"; type: "int" }
- }
- Signal {
- name: "columnsAboutToBeMoved"
- Parameter { name: "sourceParent"; type: "QModelIndex" }
- Parameter { name: "sourceStart"; type: "int" }
- Parameter { name: "sourceEnd"; type: "int" }
- Parameter { name: "destinationParent"; type: "QModelIndex" }
- Parameter { name: "destinationColumn"; type: "int" }
- }
- Signal {
- name: "columnsMoved"
- Parameter { name: "parent"; type: "QModelIndex" }
- Parameter { name: "start"; type: "int" }
- Parameter { name: "end"; type: "int" }
- Parameter { name: "destination"; type: "QModelIndex" }
- Parameter { name: "column"; type: "int" }
- }
- Method { name: "submit"; type: "bool" }
- Method { name: "revert" }
- Method {
- name: "hasIndex"
- type: "bool"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "hasIndex"
- type: "bool"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- }
- Method {
- name: "index"
- type: "QModelIndex"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "index"
- type: "QModelIndex"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- }
- Method {
- name: "parent"
- type: "QModelIndex"
- Parameter { name: "child"; type: "QModelIndex" }
- }
- Method {
- name: "sibling"
- type: "QModelIndex"
- Parameter { name: "row"; type: "int" }
- Parameter { name: "column"; type: "int" }
- Parameter { name: "idx"; type: "QModelIndex" }
- }
- Method {
- name: "rowCount"
- type: "int"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method { name: "rowCount"; type: "int" }
- Method {
- name: "columnCount"
- type: "int"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method { name: "columnCount"; type: "int" }
- Method {
- name: "hasChildren"
- type: "bool"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method { name: "hasChildren"; type: "bool" }
- Method {
- name: "data"
- type: "QVariant"
- Parameter { name: "index"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- }
- Method {
- name: "data"
- type: "QVariant"
- Parameter { name: "index"; type: "QModelIndex" }
- }
- Method {
- name: "setData"
- type: "bool"
- Parameter { name: "index"; type: "QModelIndex" }
- Parameter { name: "value"; type: "QVariant" }
- Parameter { name: "role"; type: "int" }
- }
- Method {
- name: "setData"
- type: "bool"
- Parameter { name: "index"; type: "QModelIndex" }
- Parameter { name: "value"; type: "QVariant" }
- }
- Method {
- name: "headerData"
- type: "QVariant"
- Parameter { name: "section"; type: "int" }
- Parameter { name: "orientation"; type: "Qt::Orientation" }
- Parameter { name: "role"; type: "int" }
- }
- Method {
- name: "headerData"
- type: "QVariant"
- Parameter { name: "section"; type: "int" }
- Parameter { name: "orientation"; type: "Qt::Orientation" }
- }
- Method {
- name: "fetchMore"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "canFetchMore"
- type: "bool"
- Parameter { name: "parent"; type: "QModelIndex" }
- }
- Method {
- name: "flags"
- type: "Qt::ItemFlags"
- Parameter { name: "index"; type: "QModelIndex" }
- }
- Method {
- name: "match"
- type: "QModelIndexList"
- Parameter { name: "start"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- Parameter { name: "value"; type: "QVariant" }
- Parameter { name: "hits"; type: "int" }
- Parameter { name: "flags"; type: "Qt::MatchFlags" }
- }
- Method {
- name: "match"
- type: "QModelIndexList"
- Parameter { name: "start"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- Parameter { name: "value"; type: "QVariant" }
- Parameter { name: "hits"; type: "int" }
- }
- Method {
- name: "match"
- type: "QModelIndexList"
- Parameter { name: "start"; type: "QModelIndex" }
- Parameter { name: "role"; type: "int" }
- Parameter { name: "value"; type: "QVariant" }
- }
- }
- Component { name: "QAbstractListModel"; prototype: "QAbstractItemModel" }
- Component {
- name: "QDeclarativeBluetoothDiscoveryModel"
- prototype: "QAbstractListModel"
- exports: [
- "QtBluetooth/BluetoothDiscoveryModel 5.0",
- "QtBluetooth/BluetoothDiscoveryModel 5.2"
- ]
- exportMetaObjectRevisions: [0, 0]
- Enum {
- name: "DiscoveryMode"
- values: {
- "MinimalServiceDiscovery": 0,
- "FullServiceDiscovery": 1,
- "DeviceDiscovery": 2
- }
- }
- Enum {
- name: "Error"
- values: {
- "NoError": 0,
- "InputOutputError": 1,
- "PoweredOffError": 2,
- "UnknownError": 3,
- "InvalidBluetoothAdapterError": 4
- }
- }
- Property { name: "error"; type: "Error"; isReadonly: true }
- Property { name: "discoveryMode"; type: "DiscoveryMode" }
- Property { name: "running"; type: "bool" }
- Property { name: "uuidFilter"; type: "string" }
- Property { name: "remoteAddress"; type: "string" }
- Signal {
- name: "serviceDiscovered"
- Parameter { name: "service"; type: "QDeclarativeBluetoothService"; isPointer: true }
- }
- Signal {
- name: "deviceDiscovered"
- Parameter { name: "device"; type: "string" }
- }
- }
- Component {
- name: "QDeclarativeBluetoothService"
- prototype: "QObject"
- exports: [
- "QtBluetooth/BluetoothService 5.0",
- "QtBluetooth/BluetoothService 5.2"
- ]
- exportMetaObjectRevisions: [0, 0]
- Enum {
- name: "Protocol"
- values: {
- "RfcommProtocol": 2,
- "L2CapProtocol": 1,
- "UnknownProtocol": 0
- }
- }
- Property { name: "deviceName"; type: "string"; isReadonly: true }
- Property { name: "deviceAddress"; type: "string" }
- Property { name: "serviceName"; type: "string" }
- Property { name: "serviceDescription"; type: "string" }
- Property { name: "serviceUuid"; type: "string" }
- Property { name: "serviceProtocol"; type: "Protocol" }
- Property { name: "registered"; type: "bool" }
- Signal { name: "detailsChanged" }
- Signal { name: "newClient" }
- Method { name: "nextClient"; type: "QDeclarativeBluetoothSocket*" }
- Method {
- name: "assignNextClient"
- Parameter { name: "dbs"; type: "QDeclarativeBluetoothSocket"; isPointer: true }
- }
- }
- Component {
- name: "QDeclarativeBluetoothSocket"
- prototype: "QObject"
- exports: [
- "QtBluetooth/BluetoothSocket 5.0",
- "QtBluetooth/BluetoothSocket 5.2"
- ]
- exportMetaObjectRevisions: [0, 0]
- Enum {
- name: "Error"
- values: {
- "NoError": -2,
- "UnknownSocketError": -1,
- "RemoteHostClosedError": 1,
- "HostNotFoundError": 2,
- "ServiceNotFoundError": 9,
- "NetworkError": 7,
- "UnsupportedProtocolError": 8
- }
- }
- Enum {
- name: "SocketState"
- values: {
- "Unconnected": 0,
- "ServiceLookup": 1,
- "Connecting": 2,
- "Connected": 3,
- "Bound": 4,
- "Closing": 6,
- "Listening": 5,
- "NoServiceSet": 100
- }
- }
- Property { name: "service"; type: "QDeclarativeBluetoothService"; isPointer: true }
- Property { name: "connected"; type: "bool" }
- Property { name: "error"; type: "Error"; isReadonly: true }
- Property { name: "socketState"; type: "SocketState"; isReadonly: true }
- Property { name: "stringData"; type: "string" }
- Signal { name: "stateChanged" }
- Signal { name: "dataAvailable" }
- Method {
- name: "setService"
- Parameter { name: "service"; type: "QDeclarativeBluetoothService"; isPointer: true }
- }
- Method {
- name: "setConnected"
- Parameter { name: "connected"; type: "bool" }
- }
- Method {
- name: "sendStringData"
- Parameter { name: "data"; type: "string" }
- }
- }
-}
diff --git a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
deleted file mode 100644
index 6213355e..00000000
--- a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel.cpp
+++ /dev/null
@@ -1,651 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include "qdeclarativebluetoothdiscoverymodel_p.h"
-
-#include <QPixmap>
-
-#include <QtCore/QLoggingCategory>
-#include <QtBluetooth/QBluetoothDeviceInfo>
-#include <QtBluetooth/QBluetoothAddress>
-
-#include "qdeclarativebluetoothservice_p.h"
-
-/*!
- \qmltype BluetoothDiscoveryModel
- \instantiates QDeclarativeBluetoothDiscoveryModel
- \inqmlmodule QtBluetooth
- \since 5.2
- \brief Enables searching for the Bluetooth devices and services in
- range.
-
- BluetoothDiscoveryModel provides a model of connectable services. The
- contents of the model can be filtered by UUID allowing discovery to be
- limited to a single service such as a game.
-
- The model roles provided by BluetoothDiscoveryModel are
- \c service, \c name, \c remoteAddress and \c deviceName. The meaning of the roles
- changes based on the current \l discoveryMode.
-
- \table
- \header
- \li Model role
- \li Device Discovery
- \li Service Discovery
- \row
- \li \c name
- \li The device's name and address.
- \li The service name and the name of the device offering the service. If the device name is empty the devices address will be used.
- \row
- \li \c deviceName
- \li The name of the device.
- \li The name of the device offering the service.
- \row
- \li \c service
- \li The role is undefined in this mode.
- \li The \l BluetoothService object describing the discovered service.
- \row
- \li \c remoteAddress
- \li The address of the found device.
- \li The address of the device offering the service.
- \endtable
-
- \sa QBluetoothServiceDiscoveryAgent
-*/
-
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_QML)
-
-class QDeclarativeBluetoothDiscoveryModelPrivate
-{
-public:
- QDeclarativeBluetoothDiscoveryModelPrivate()
- :
- m_error(QDeclarativeBluetoothDiscoveryModel::NoError),
- m_discoveryMode(QDeclarativeBluetoothDiscoveryModel::MinimalServiceDiscovery),
- m_running(false),
- m_runningRequested(true),
- m_componentCompleted(false),
- m_currentState(QDeclarativeBluetoothDiscoveryModel::IdleAction),
- m_nextState(QDeclarativeBluetoothDiscoveryModel::IdleAction),
- m_wasDirectDeviceAgentCancel(false)
- {
- }
- ~QDeclarativeBluetoothDiscoveryModelPrivate()
- {
- if (m_deviceAgent)
- delete m_deviceAgent;
-
- if (m_serviceAgent)
- delete m_serviceAgent;
-
- qDeleteAll(m_services);
- }
-
- QBluetoothServiceDiscoveryAgent *m_serviceAgent = nullptr;
- QBluetoothDeviceDiscoveryAgent *m_deviceAgent = nullptr;
-
- QDeclarativeBluetoothDiscoveryModel::Error m_error;
- QList<QDeclarativeBluetoothService *> m_services;
- QList<QBluetoothDeviceInfo> m_devices;
- QDeclarativeBluetoothDiscoveryModel::DiscoveryMode m_discoveryMode;
- QString m_uuid;
- bool m_running;
- bool m_runningRequested;
- bool m_componentCompleted;
- QString m_remoteAddress;
-
- QDeclarativeBluetoothDiscoveryModel::Action m_currentState;
- QDeclarativeBluetoothDiscoveryModel::Action m_nextState;
- bool m_wasDirectDeviceAgentCancel;
-};
-
-QDeclarativeBluetoothDiscoveryModel::QDeclarativeBluetoothDiscoveryModel(QObject *parent) :
- QAbstractListModel(parent),
- d(new QDeclarativeBluetoothDiscoveryModelPrivate)
-{
- d->m_deviceAgent = new QBluetoothDeviceDiscoveryAgent(this);
- connect(d->m_deviceAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
- this, QOverload<const QBluetoothDeviceInfo&>::of(&QDeclarativeBluetoothDiscoveryModel::deviceDiscovered));
- connect(d->m_deviceAgent, &QBluetoothDeviceDiscoveryAgent::finished,
- this, &QDeclarativeBluetoothDiscoveryModel::finishedDiscovery);
- connect(d->m_deviceAgent, &QBluetoothDeviceDiscoveryAgent::canceled,
- this, &QDeclarativeBluetoothDiscoveryModel::finishedDiscovery);
- connect(d->m_deviceAgent,
- QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error),
- this,
- &QDeclarativeBluetoothDiscoveryModel::errorDeviceDiscovery);
- d->m_deviceAgent->setObjectName(QStringLiteral("DeviceDiscoveryAgent"));
-
- d->m_serviceAgent = new QBluetoothServiceDiscoveryAgent(this);
- connect(d->m_serviceAgent, &QBluetoothServiceDiscoveryAgent::serviceDiscovered,
- this, QOverload<const QBluetoothServiceInfo&>::of(&QDeclarativeBluetoothDiscoveryModel::serviceDiscovered));
- connect(d->m_serviceAgent, &QBluetoothServiceDiscoveryAgent::finished,
- this, &QDeclarativeBluetoothDiscoveryModel::finishedDiscovery);
- connect(d->m_serviceAgent, &QBluetoothServiceDiscoveryAgent::canceled,
- this, &QDeclarativeBluetoothDiscoveryModel::finishedDiscovery);
- connect(d->m_serviceAgent,
- QOverload<QBluetoothServiceDiscoveryAgent::Error>::of(&QBluetoothServiceDiscoveryAgent::error),
- this,
- &QDeclarativeBluetoothDiscoveryModel::errorDiscovery);
- d->m_serviceAgent->setObjectName(QStringLiteral("ServiceDiscoveryAgent"));
-}
-
-QDeclarativeBluetoothDiscoveryModel::~QDeclarativeBluetoothDiscoveryModel()
-{
- delete d;
-}
-void QDeclarativeBluetoothDiscoveryModel::componentComplete()
-{
- d->m_componentCompleted = true;
- if (d->m_runningRequested)
- setRunning(true);
-}
-
-void QDeclarativeBluetoothDiscoveryModel::errorDiscovery(QBluetoothServiceDiscoveryAgent::Error error)
-{
- switch (error) {
- case QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError:
- d->m_error = QDeclarativeBluetoothDiscoveryModel::InvalidBluetoothAdapterError; break;
- case QBluetoothServiceDiscoveryAgent::NoError:
- d->m_error = QDeclarativeBluetoothDiscoveryModel::NoError; break;
- case QBluetoothServiceDiscoveryAgent::InputOutputError:
- d->m_error = QDeclarativeBluetoothDiscoveryModel::InputOutputError; break;
- case QBluetoothServiceDiscoveryAgent::PoweredOffError:
- d->m_error = QDeclarativeBluetoothDiscoveryModel::PoweredOffError; break;
- case QBluetoothServiceDiscoveryAgent::UnknownError:
- d->m_error = QDeclarativeBluetoothDiscoveryModel::UnknownError; break;
- }
-
- emit errorChanged();
-}
-
-void QDeclarativeBluetoothDiscoveryModel::errorDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::Error error)
-{
- d->m_error = static_cast<QDeclarativeBluetoothDiscoveryModel::Error>(error);
- emit errorChanged();
-
- //QBluetoothDeviceDiscoveryAgent::finished() signal is not emitted in case of an error
- //Note that this behavior is different from QBluetoothServiceDiscoveryAgent.
- //This resets the models running flag.
- finishedDiscovery();
-}
-
-void QDeclarativeBluetoothDiscoveryModel::clearModel()
-{
- beginResetModel();
- qDeleteAll(d->m_services);
- d->m_services.clear();
- d->m_devices.clear();
- endResetModel();
-}
-
-/*!
- \qmlproperty enumeration BluetoothDiscoveryModel::error
-
- This property holds the last error reported during discovery.
- \table
- \header \li Property \li Description
- \row \li \c BluetoothDiscoveryModel.NoError
- \li No error occurred.
- \row \li \c BluetoothDiscoveryModel.InputOutputError
- \li An IO failure occurred during device discovery
- \row \li \c BluetoothDiscoveryModel.PoweredOffError
- \li The bluetooth device is not powered on.
- \row \li \c BluetoothDiscoveryModel.InvalidBluetoothAdapterError
- \li There is no default Bluetooth device to perform the
- service discovery. The model always uses the local default adapter.
- Specifying a default adapter is not possible. If that's required,
- \l QBluetoothServiceDiscoveryAgent should be directly used. This
- value was introduced by Qt 5.4.
- \row \li \c BluetoothDiscoveryModel.UnknownError
- \li An unknown error occurred.
- \endtable
-
- This property is read-only.
- */
-QDeclarativeBluetoothDiscoveryModel::Error QDeclarativeBluetoothDiscoveryModel::error() const
-{
- return d->m_error;
-}
-
-int QDeclarativeBluetoothDiscoveryModel::rowCount(const QModelIndex &parent) const
-{
- Q_UNUSED(parent);
- if (discoveryMode() == DeviceDiscovery)
- return d->m_devices.count();
- else
- return d->m_services.count();
-}
-
-QVariant QDeclarativeBluetoothDiscoveryModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid() || index.row() < 0)
- return QVariant();
-
- if (discoveryMode() != DeviceDiscovery) {
- if (index.row() >= d->m_services.count()){
- qCWarning(QT_BT_QML) << "index out of bounds";
- return QVariant();
- }
-
- QDeclarativeBluetoothService *service = d->m_services.value(index.row());
-
- switch (role) {
- case Name: {
- QString label = service->deviceName();
- if (label.isEmpty())
- label += service->deviceAddress();
- else
- label+= QStringLiteral(":");
- label += QStringLiteral(" ") + service->serviceName();
- return label;
- }
- case ServiceRole:
- return QVariant::fromValue(service);
- case DeviceName:
- return service->deviceName();
- case RemoteAddress:
- return service->deviceAddress();
- }
- } else {
- if (index.row() >= d->m_devices.count()) {
- qCWarning(QT_BT_QML) << "index out of bounds";
- return QVariant();
- }
-
- QBluetoothDeviceInfo device = d->m_devices.value(index.row());
- switch (role) {
- case Name:
- return (device.name() + QStringLiteral(" (") + device.address().toString() + QStringLiteral(")"));
- case ServiceRole:
- break;
- case DeviceName:
- return device.name();
- case RemoteAddress:
- return device.address().toString();
- }
- }
-
- return QVariant();
-}
-
-QHash<int,QByteArray> QDeclarativeBluetoothDiscoveryModel::roleNames() const
-{
- return {{Name, "name"},
- {ServiceRole, "service"},
- {RemoteAddress, "remoteAddress"},
- {DeviceName, "deviceName"}};
-}
-
-/*!
- \qmlsignal BluetoothDiscoveryModel::serviceDiscovered(BluetoothService service)
-
- This signal is emitted when a new service is discovered. The \a service
- parameter contains the service details.
-
- The corresponding handler is \c onServiceDiscovered.
-
- \sa BluetoothService
- */
-
-void QDeclarativeBluetoothDiscoveryModel::serviceDiscovered(const QBluetoothServiceInfo &service)
-{
- //qDebug() << "service discovered";
-
- QDeclarativeBluetoothService *bs = new QDeclarativeBluetoothService(service, this);
- QDeclarativeBluetoothService *current = nullptr;
- for (int i = 0; i < d->m_services.count(); i++) {
- current = d->m_services.at(i);
- if (bs->deviceAddress() == current->deviceAddress()
- && bs->serviceName() == current->serviceName()
- && bs->serviceUuid() == current->serviceUuid()) {
- delete bs;
- return;
- }
- }
-
- beginInsertRows(QModelIndex(),d->m_services.count(), d->m_services.count());
- d->m_services.append(bs);
- endInsertRows();
- emit serviceDiscovered(bs);
-}
-
-/*!
- \qmlsignal BluetoothDiscoveryModel::deviceDiscovered(string device)
-
- This signal is emitted when a new device is discovered. \a device contains
- the Bluetooth address of the discovered device.
-
- The corresponding handler is \c onDeviceDiscovered.
- */
-
-void QDeclarativeBluetoothDiscoveryModel::deviceDiscovered(const QBluetoothDeviceInfo &device)
-{
- //qDebug() << "Device discovered" << device.address().toString() << device.name();
-
- beginInsertRows(QModelIndex(),d->m_devices.count(), d->m_devices.count());
- d->m_devices.append(device);
- endInsertRows();
- emit deviceDiscovered(device.address().toString());
-}
-
-void QDeclarativeBluetoothDiscoveryModel::finishedDiscovery()
-{
- QDeclarativeBluetoothDiscoveryModel::Action previous = d->m_currentState;
- d->m_currentState = IdleAction;
-
- switch (previous) {
- case IdleAction:
- // last transition didn't even start
- // can happen when start() or stop() immediately returned
- // usually this happens within a current transitionToNextAction call
- break;
- case StopAction:
- qCDebug(QT_BT_QML) << "Agent cancel detected";
- transitionToNextAction();
- break;
- default: // all other
- qCDebug(QT_BT_QML) << "Discovery finished" << sender()->objectName();
-
- //TODO Qt6 This hack below is once again due to the pendingCancel logic
- // because QBluetoothDeviceDiscoveryAgent::isActive() is not reliable.
- // In toggleStartStop() we need to know whether the stop() is delayed or immediate.
- // isActive() cannot be used. Hence we have to wait for the canceled() signal.
- // Android, WinRT and Bluez5 are immediate, Bluez4 is always delayed.
- // The immediate case is what we catch here.
- if (sender() == d->m_deviceAgent && d->m_nextState == StopAction) {
- d->m_wasDirectDeviceAgentCancel = true;
- return;
- }
- setRunning(false);
- break;
- }
-}
-
-/*!
- \qmlproperty enumeration BluetoothDiscoveryModel::discoveryMode
-
- Sets the discovery mode. The discovery mode has to be set before the discovery is started
- \table
- \header \li Property \li Description
- \row \li \c BluetoothDiscoveryModel.FullServiceDiscovery
- \li Starts a full discovery of all services of all devices in range.
- \row \li \c BluetoothDiscoveryModel.MinimalServiceDiscovery
- \li (Default) Starts a minimal discovery of all services of all devices in range. A minimal discovery is
- faster but only guarantees the device and UUID information to be correct.
- \row \li \c BluetoothDiscoveryModel.DeviceDiscovery
- \li Discovers only devices in range. The service role will be 0 for any model item.
- \endtable
-*/
-
-QDeclarativeBluetoothDiscoveryModel::DiscoveryMode QDeclarativeBluetoothDiscoveryModel::discoveryMode() const
-{
- return d->m_discoveryMode;
-}
-
-void QDeclarativeBluetoothDiscoveryModel::setDiscoveryMode(DiscoveryMode discovery)
-{
- d->m_discoveryMode = discovery;
- emit discoveryModeChanged();
-}
-
-
-void QDeclarativeBluetoothDiscoveryModel::updateNextAction(Action action)
-{
- qCDebug(QT_BT_QML) << "New action queue:"
- << d->m_currentState << d->m_nextState << action;
-
- if (action == IdleAction)
- return;
-
- switch (d->m_nextState) {
- case IdleAction:
- d->m_nextState = action;
- return;
- case StopAction:
- qWarning() << "Invalid Stop state when processing new action" << action;
- return;
- case DeviceDiscoveryAction:
- case MinimalServiceDiscoveryAction:
- case FullServiceDiscoveryAction:
- if (action == StopAction) // cancel out previous start call
- d->m_nextState = IdleAction;
- else
- qWarning() << "Ignoring new DMF state while another DMF state is scheduled.";
- return;
- }
-}
-
-void QDeclarativeBluetoothDiscoveryModel::transitionToNextAction()
-{
- qCDebug(QT_BT_QML) << "Before transition change:" << d->m_currentState << d->m_nextState;
- bool isRunning;
- switch (d->m_currentState) {
- case IdleAction:
- switch (d->m_nextState) {
- case IdleAction: break; // nothing to do
- case StopAction: d->m_nextState = IdleAction; break; // clear, nothing to do
- case DeviceDiscoveryAction:
- case MinimalServiceDiscoveryAction:
- case FullServiceDiscoveryAction:
- Action temp = d->m_nextState;
- clearModel();
- isRunning = toggleStartStop(d->m_nextState);
- d->m_nextState = IdleAction;
- if (isRunning) {
- d->m_currentState = temp;
- } else {
- if (temp != DeviceDiscoveryAction )
- errorDiscovery(d->m_serviceAgent->error());
- d->m_running = false;
- }
- }
- break;
- case StopAction:
- break; // do nothing, StopAction cleared by finished()/cancelled()/error() handlers
- case DeviceDiscoveryAction:
- case MinimalServiceDiscoveryAction:
- case FullServiceDiscoveryAction:
- switch (d->m_nextState) {
- case IdleAction: break;
- case StopAction:
- isRunning = toggleStartStop(StopAction);
- (isRunning) ? d->m_currentState = StopAction : d->m_currentState = IdleAction;
- d->m_nextState = IdleAction;
- break;
- default:
- Q_ASSERT(false); // should never happen
- break;
- }
-
- break;
- }
-
- qCDebug(QT_BT_QML) << "After transition change:" << d->m_currentState << d->m_nextState;
-}
-
-// Returns true if the agent is active
-// this can be used to detect whether the agent still needs time to
-// perform the requested action.
-bool QDeclarativeBluetoothDiscoveryModel::toggleStartStop(Action action)
-{
- Q_ASSERT(action != IdleAction);
- switch (action) {
- case DeviceDiscoveryAction:
- Q_ASSERT(!d->m_deviceAgent->isActive() && !d->m_serviceAgent->isActive());
- d->m_deviceAgent->start();
- return d->m_deviceAgent->isActive();
- case MinimalServiceDiscoveryAction:
- case FullServiceDiscoveryAction:
- Q_ASSERT(!d->m_deviceAgent->isActive() && !d->m_serviceAgent->isActive());
- d->m_serviceAgent->setRemoteAddress(QBluetoothAddress(d->m_remoteAddress));
- d->m_serviceAgent->clear();
-
- if (!d->m_uuid.isEmpty())
- d->m_serviceAgent->setUuidFilter(QBluetoothUuid(d->m_uuid));
-
- if (action == FullServiceDiscoveryAction) {
- qCDebug(QT_BT_QML) << "Full Discovery";
- d->m_serviceAgent->start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
- } else {
- qCDebug(QT_BT_QML) << "Minimal Discovery";
- d->m_serviceAgent->start(QBluetoothServiceDiscoveryAgent::MinimalDiscovery);
- }
- return d->m_serviceAgent->isActive();
- case StopAction:
- Q_ASSERT(d->m_currentState != StopAction && d->m_currentState != IdleAction);
- if (d->m_currentState == DeviceDiscoveryAction) {
- d->m_deviceAgent->stop();
-
- // TODO Qt6 Crude hack below
- // cannot use isActive() below due to pendingCancel logic
- // we always wait for canceled() signal coming through or check
- // for directly invoked cancel() response caused by stop() above
- bool stillActive = !d->m_wasDirectDeviceAgentCancel;
- d->m_wasDirectDeviceAgentCancel = false;
- return stillActive;
- } else {
- d->m_serviceAgent->stop();
- return d->m_serviceAgent->isActive();
- }
- default:
- return true;
- }
-}
-
-
-/*!
- \qmlproperty bool BluetoothDiscoveryModel::running
-
- This property starts or stops discovery. A restart of the discovery process
- requires setting this property to \c false and subsequently to \c true again.
-
-*/
-
-bool QDeclarativeBluetoothDiscoveryModel::running() const
-{
- return d->m_running;
-}
-
-void QDeclarativeBluetoothDiscoveryModel::setRunning(bool running)
-{
- if (!d->m_componentCompleted) {
- d->m_runningRequested = running;
- return;
- }
-
- if (d->m_running == running)
- return;
-
- d->m_running = running;
-
- Action nextAction = IdleAction;
- if (running) {
- if (discoveryMode() == MinimalServiceDiscovery)
- nextAction = MinimalServiceDiscoveryAction;
- else if (discoveryMode() == FullServiceDiscovery)
- nextAction = FullServiceDiscoveryAction;
- else
- nextAction = DeviceDiscoveryAction;
- } else {
- nextAction = StopAction;
- }
-
- Q_ASSERT(nextAction != IdleAction);
- updateNextAction(nextAction);
- transitionToNextAction();
-
- qCDebug(QT_BT_QML) << "Running state:" << d->m_running;
- emit runningChanged();
-}
-
-/*!
- \qmlproperty string BluetoothDiscoveryModel::uuidFilter
-
- This property holds an optional UUID filter. A UUID can be used to return only
- matching services. 16 bit, 32 bit or 128 bit UUIDs can be used. The string format
- is same as the format of QUuid.
-
- \sa QBluetoothUuid
- \sa QUuid
- */
-
-
-QString QDeclarativeBluetoothDiscoveryModel::uuidFilter() const
-{
- return d->m_uuid;
-}
-
-void QDeclarativeBluetoothDiscoveryModel::setUuidFilter(QString uuid)
-{
- if (uuid == d->m_uuid)
- return;
-
- QBluetoothUuid qbuuid(uuid);
- if (qbuuid.isNull()) {
- qCWarning(QT_BT_QML) << "Invalid UUID providded " << uuid;
- return;
- }
- d->m_uuid = uuid;
- emit uuidFilterChanged();
-}
-
-/*!
- \qmlproperty string BluetoothDiscoveryModel::remoteAddress
-
- This property holds an optional bluetooth address for a remote bluetooth device.
- Only services on this remote device will be discovered. It has no effect if
- an invalid bluetooth address was set or if the property was set after the discovery
- was started.
-
- The property is ignored if device discovery is selected.
-
-*/
-
-QString QDeclarativeBluetoothDiscoveryModel::remoteAddress()
-{
- return d->m_remoteAddress;
-}
-
-void QDeclarativeBluetoothDiscoveryModel::setRemoteAddress(QString address)
-{
- d->m_remoteAddress = address;
- emit remoteAddressChanged();
-}
diff --git a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h b/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h
deleted file mode 100644
index 6cbde088..00000000
--- a/src/imports/bluetooth/qdeclarativebluetoothdiscoverymodel_p.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-#ifndef QDECLARATIVECONTACTMODEL_P_H
-#define QDECLARATIVECONTACTMODEL_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 <QAbstractListModel>
-#include <QQmlParserStatus>
-#include <QQmlListProperty>
-#include <QQmlParserStatus>
-
-#include <qbluetoothserviceinfo.h>
-#include <qbluetoothservicediscoveryagent.h>
-#include <qbluetoothdevicediscoveryagent.h>
-
-#include <qtbluetoothglobal.h>
-
-#include "qdeclarativebluetoothservice_p.h"
-
-QT_USE_NAMESPACE
-
-class QDeclarativeBluetoothDiscoveryModelPrivate;
-class QDeclarativeBluetoothDiscoveryModel : public QAbstractListModel, public QQmlParserStatus
-{
- Q_OBJECT
- Q_PROPERTY(Error error READ error NOTIFY errorChanged)
- Q_PROPERTY(DiscoveryMode discoveryMode READ discoveryMode WRITE setDiscoveryMode NOTIFY discoveryModeChanged)
- Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged)
- Q_PROPERTY(QString uuidFilter READ uuidFilter WRITE setUuidFilter NOTIFY uuidFilterChanged)
- Q_PROPERTY(QString remoteAddress READ remoteAddress WRITE setRemoteAddress NOTIFY remoteAddressChanged)
- Q_INTERFACES(QQmlParserStatus)
-public:
- explicit QDeclarativeBluetoothDiscoveryModel(QObject *parent = 0);
- virtual ~QDeclarativeBluetoothDiscoveryModel();
-
- enum {
- Name = Qt::UserRole + 1,
- ServiceRole,
- DeviceName,
- RemoteAddress
- };
-
- enum DiscoveryMode {
- MinimalServiceDiscovery,
- FullServiceDiscovery,
- DeviceDiscovery
- };
- Q_ENUM(DiscoveryMode)
-
- enum Error
- {
- NoError,
- InputOutputError,
- PoweredOffError,
- UnknownError,
- InvalidBluetoothAdapterError
- };
- Q_ENUM(Error)
-
- Error error() const;
-
- void componentComplete() override;
-
- void classBegin() override { }
-
- // From QAbstractListModel
- int rowCount(const QModelIndex &parent) const override;
- QVariant data(const QModelIndex &index, int role) const override;
-
- QHash<int,QByteArray> roleNames() const override;
-
- DiscoveryMode discoveryMode() const;
- void setDiscoveryMode(DiscoveryMode discovery);
-
- // TODO Qt 6 This property behaves synchronously but should really be
- // asynchronous. The agents start/stop/restart is not immediate.
- bool running() const;
- void setRunning(bool running);
-
- QString uuidFilter() const;
- void setUuidFilter(QString uuid);
-
- QString remoteAddress();
- void setRemoteAddress(QString);
-
-signals:
- void errorChanged();
- void discoveryModeChanged();
- void serviceDiscovered(QDeclarativeBluetoothService *service);
- void deviceDiscovered(const QString& device);
- void runningChanged();
- void uuidFilterChanged();
- void remoteAddressChanged();
-
-private slots:
- void serviceDiscovered(const QBluetoothServiceInfo &service);
- void deviceDiscovered(const QBluetoothDeviceInfo &device);
- void finishedDiscovery();
- void errorDiscovery(QBluetoothServiceDiscoveryAgent::Error error);
- void errorDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::Error);
-
-private:
- void clearModel();
-
- enum Action {
- IdleAction = 0,
- StopAction,
- DeviceDiscoveryAction,
- MinimalServiceDiscoveryAction,
- FullServiceDiscoveryAction
- };
-
- bool toggleStartStop(Action action);
- void updateNextAction(Action action);
- void transitionToNextAction();
-
-private:
- QDeclarativeBluetoothDiscoveryModelPrivate* d;
- friend class QDeclarativeBluetoothDiscoveryModelPrivate;
-
-};
-
-#endif // QDECLARATIVECONTACTMODEL_P_H
diff --git a/src/imports/bluetooth/qdeclarativebluetoothservice.cpp b/src/imports/bluetooth/qdeclarativebluetoothservice.cpp
deleted file mode 100644
index b0d0db60..00000000
--- a/src/imports/bluetooth/qdeclarativebluetoothservice.cpp
+++ /dev/null
@@ -1,382 +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 "qdeclarativebluetoothservice_p.h"
-
-#include <QtCore/QLoggingCategory>
-
-#include <QtBluetooth/QBluetoothDeviceInfo>
-#include <QtBluetooth/QBluetoothSocket>
-#include <QtBluetooth/QBluetoothAddress>
-#include <QtBluetooth/QBluetoothServer>
-
-#include <QObject>
-
-/* ==================== QDeclarativeBluetoothService ======================= */
-
-/*!
- \qmltype BluetoothService
- \instantiates QDeclarativeBluetoothService
- \inqmlmodule QtBluetooth
- \since 5.2
- \brief Provides information about a particular Bluetooth service.
-
- \sa QBluetoothAddress
- \sa QBluetoothSocket
-
- It allows a QML project to get information about a remote service, or describe a service
- for a BluetoothSocket to connect to.
- */
-
-/*!
- \qmlsignal BluetoothService::detailsChanged()
-
- This signal is emitted when any of the following properties changes:
-
- \list
- \li deviceAddress
- \li deviceName
- \li serviceDescription
- \li serviceName
- \li serviceProtocol
- \li serviceUuid
- \endlist
-
- The corresponding handler is \c onDetailsChanged.
-*/
-
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_QML)
-
-class QDeclarativeBluetoothServicePrivate
-{
-public:
- QDeclarativeBluetoothServicePrivate()
- : m_componentComplete(false)
- {
-
- }
-
- ~QDeclarativeBluetoothServicePrivate()
- {
- delete m_service;
- }
-
- bool m_componentComplete;
- QBluetoothServiceInfo *m_service = nullptr;
- QDeclarativeBluetoothService::Protocol m_protocol;
- QBluetoothServer *m_server = nullptr;
-};
-
-QDeclarativeBluetoothService::QDeclarativeBluetoothService(QObject *parent) :
- QObject(parent)
-{
- d = new QDeclarativeBluetoothServicePrivate;
- d->m_service = new QBluetoothServiceInfo();
-}
-
-QDeclarativeBluetoothService::QDeclarativeBluetoothService(const QBluetoothServiceInfo &service, QObject *parent)
- : QObject(parent)
-{
- d = new QDeclarativeBluetoothServicePrivate;
- d->m_service = new QBluetoothServiceInfo(service);
-}
-
-QDeclarativeBluetoothService::~QDeclarativeBluetoothService()
-{
- delete d;
-}
-
-void QDeclarativeBluetoothService::componentComplete()
-{
- d->m_componentComplete = true;
-
- if (!d->m_service->isRegistered())
- setRegistered(true);
-}
-
-
-/*!
- \qmlproperty string BluetoothService::deviceName
-
- This property holds the name of the remote device. Changing this property emits the
- detailsChanged signal.
- */
-
-QString QDeclarativeBluetoothService::deviceName() const
-{
-
- return d->m_service->device().name();
-}
-
-/*!
- \qmlproperty string BluetoothService::deviceAddress
-
- This property holds the remote device's MAC address. It must be a valid address to
- connect to a remote device using a Bluetooth socket. Changing this property emits the
- detailsChanged signal.
-
- */
-
-QString QDeclarativeBluetoothService::deviceAddress() const
-{
- return d->m_service->device().address().toString();
-}
-
-void QDeclarativeBluetoothService::setDeviceAddress(const QString &newAddress)
-{
- QBluetoothAddress address(newAddress);
- QBluetoothDeviceInfo device(address, QString(), QBluetoothDeviceInfo::ComputerDevice);
- d->m_service->setDevice(device);
- emit detailsChanged();
-}
-
-/*!
- \qmlproperty string BluetoothService::serviceName
-
- This property holds the name of the remote service if available. Changing this property emits the
- detailsChanged signal.
- */
-
-QString QDeclarativeBluetoothService::serviceName() const
-{
- return d->m_service->serviceName();
-}
-
-void QDeclarativeBluetoothService::setServiceName(const QString &name)
-{
- d->m_service->setServiceName(name);
- emit detailsChanged();
-}
-
-
-/*!
- \qmlproperty string BluetoothService::serviceDescription
-
- This property holds the description provided by the remote service. Changing this property emits the
- detailsChanged signal.
- */
-QString QDeclarativeBluetoothService::serviceDescription() const
-{
- return d->m_service->serviceDescription();
-}
-
-void QDeclarativeBluetoothService::setServiceDescription(const QString &description)
-{
- d->m_service->setServiceDescription(description);
- emit detailsChanged();
-}
-
-/*!
- \qmlproperty enumeration BluetoothService::serviceProtocol
-
- This property holds the protocol used for the service. Changing this property emits the
- detailsChanged signal.
-
- Possible values for this property are:
- \table
- \header \li Property \li Description
- \row \li \c BluetoothService.RfcommProtocol
- \li The Rfcomm protocol is used.
- \row \li \c BluetoothService.L2capProtocol
- \li The L2cap protocol is used.
- \row \li \c BluetoothService.UnknownProtocol
- \li The protocol is unknown.
- \endtable
-
- \sa QBluetoothServiceInfo::Protocol
-
- */
-
-QDeclarativeBluetoothService::Protocol QDeclarativeBluetoothService::serviceProtocol() const
-{
- return d->m_protocol;
-}
-
-void QDeclarativeBluetoothService::setServiceProtocol(QDeclarativeBluetoothService::Protocol protocol)
-{
- d->m_protocol = protocol;
- emit detailsChanged();
-}
-
-/*!
- \qmlproperty string BluetoothService::serviceUuid
-
- This property holds the UUID of the remote service. Service UUID,
- and the address must be set to connect to a remote service. Changing
- this property emits the detailsChanged signal.
-
-*/
-
-QString QDeclarativeBluetoothService::serviceUuid() const
-{
- return d->m_service->serviceUuid().toString();
-}
-
-void QDeclarativeBluetoothService::setServiceUuid(const QString &uuid)
-{
- d->m_service->setServiceUuid(QBluetoothUuid(uuid));
- emit detailsChanged();
-}
-
-/*!
- \qmlproperty string BluetoothService::registered
-
- This property holds the registration/publication status of the service. If true, the service
- is published during service discovery.
-*/
-
-bool QDeclarativeBluetoothService::isRegistered() const
-{
- return d->m_service->isRegistered();
-}
-
-void QDeclarativeBluetoothService::setRegistered(bool registered)
-{
- if (!d->m_componentComplete) {
- return;
- }
-
- delete d->m_server;
- d->m_server = nullptr;
-
- if (!registered) {
- d->m_service->unregisterService();
- emit registeredChanged();
- return;
- }
-
- if (d->m_protocol == UnknownProtocol) {
- qCWarning(QT_BT_QML) << "Unknown protocol, can't make service" << d->m_protocol;
- return;
- }
-
- QBluetoothServer *server
- = new QBluetoothServer(static_cast<QBluetoothServiceInfo::Protocol>(d->m_protocol));
- server->setMaxPendingConnections(1);
- if (!server->listen()) {
- qCWarning(QT_BT_QML) << "Could not start server. Error:" << server->error();
- return;
- }
-
- d->m_server = server;
- connect(d->m_server, &QBluetoothServer::newConnection,
- this, &QDeclarativeBluetoothService::new_connection);
-
- d->m_service->setAttribute(QBluetoothServiceInfo::ServiceRecordHandle, (uint)0x00010010);
-
- QBluetoothServiceInfo::Sequence classId;
- classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
- d->m_service->setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
-
- //qDebug() << "name/uuid" << d->m_name << d->m_uuid << d->m_port;
-
- QBluetoothServiceInfo::Sequence publicBrowse;
- publicBrowse << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup));
- d->m_service->setAttribute(QBluetoothServiceInfo::BrowseGroupList, publicBrowse);
-
- QBluetoothServiceInfo::Sequence protocolDescriptorList;
- QBluetoothServiceInfo::Sequence protocol;
-
- if (d->m_protocol == L2CapProtocol) {
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap))
- << QVariant::fromValue(quint16(d->m_server->serverPort()));
- } else if (d->m_protocol == RfcommProtocol) {
- //rfcomm implies l2cp protocol
- {
- QBluetoothServiceInfo::Sequence l2cpProtocol;
- l2cpProtocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
- protocolDescriptorList.append(QVariant::fromValue(l2cpProtocol));
- }
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
- << QVariant::fromValue(quint8(d->m_server->serverPort()));
- }
- protocolDescriptorList.append(QVariant::fromValue(protocol));
-
- d->m_service->setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList,
- protocolDescriptorList);
-
- if (d->m_service->registerService())
- emit registeredChanged();
- else
- qCWarning(QT_BT_QML) << "Register service failed"; // TODO: propagate this error to the user
-}
-
-QBluetoothServiceInfo *QDeclarativeBluetoothService::serviceInfo() const
-{
- return d->m_service;
-}
-
-void QDeclarativeBluetoothService::new_connection()
-{
- emit newClient();
-}
-
-QDeclarativeBluetoothSocket *QDeclarativeBluetoothService::nextClient()
-{
- QBluetoothServer *server = qobject_cast<QBluetoothServer *>(d->m_server);
- if (server) {
- if (server->hasPendingConnections()) {
- QBluetoothSocket *socket = server->nextPendingConnection();
- return new QDeclarativeBluetoothSocket(socket, this, nullptr);
- }
- else {
- qCWarning(QT_BT_QML) << "Socket has no pending connection, failing";
- return nullptr;
- }
- }
- return nullptr;
-}
-
-void QDeclarativeBluetoothService::assignNextClient(QDeclarativeBluetoothSocket *dbs)
-{
- QBluetoothServer *server = qobject_cast<QBluetoothServer *>(d->m_server);
- if (server) {
- if (server->hasPendingConnections()) {
- QBluetoothSocket *socket = server->nextPendingConnection();
- dbs->newSocket(socket, this);
- return;
- }
- else {
- qCWarning(QT_BT_QML) << "Socket has no pending connection, failing";
- return;
- }
- }
- return;
-}
-
diff --git a/src/imports/bluetooth/qdeclarativebluetoothservice_p.h b/src/imports/bluetooth/qdeclarativebluetoothservice_p.h
deleted file mode 100644
index 927f100e..00000000
--- a/src/imports/bluetooth/qdeclarativebluetoothservice_p.h
+++ /dev/null
@@ -1,131 +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 QDECLARATIVEBLUETOOTHSERVICE_P_H
-#define QDECLARATIVEBLUETOOTHSERVICE_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 <QObject>
-#include <qqml.h>
-#include <qbluetoothserviceinfo.h>
-#include "qdeclarativebluetoothsocket_p.h"
-
-class QDeclarativeBluetoothSocket;
-
-QT_USE_NAMESPACE
-
-class QDeclarativeBluetoothServicePrivate;
-
-class QDeclarativeBluetoothService : public QObject, public QQmlParserStatus
-{
- Q_OBJECT
- Q_PROPERTY(QString deviceName READ deviceName NOTIFY detailsChanged)
- Q_PROPERTY(QString deviceAddress READ deviceAddress WRITE setDeviceAddress NOTIFY detailsChanged)
- Q_PROPERTY(QString serviceName READ serviceName WRITE setServiceName NOTIFY detailsChanged)
- Q_PROPERTY(QString serviceDescription READ serviceDescription WRITE setServiceDescription NOTIFY detailsChanged)
- Q_PROPERTY(QString serviceUuid READ serviceUuid WRITE setServiceUuid NOTIFY detailsChanged)
- Q_PROPERTY(Protocol serviceProtocol READ serviceProtocol WRITE setServiceProtocol NOTIFY detailsChanged)
- Q_PROPERTY(bool registered READ isRegistered WRITE setRegistered NOTIFY registeredChanged)
- Q_INTERFACES(QQmlParserStatus)
-
-public:
- /// TODO: Merge/Replace with QBluetoothServiceInfo::Protocol in Qt 6
- enum Protocol {
- RfcommProtocol = QBluetoothServiceInfo::RfcommProtocol,
- L2CapProtocol = QBluetoothServiceInfo::L2capProtocol,
- UnknownProtocol = QBluetoothServiceInfo::UnknownProtocol
- };
- Q_ENUM(Protocol)
-
- explicit QDeclarativeBluetoothService(QObject *parent = 0);
- explicit QDeclarativeBluetoothService(const QBluetoothServiceInfo &service,
- QObject *parent = 0);
- ~QDeclarativeBluetoothService();
-
- QString deviceName() const;
- QString deviceAddress() const;
- QString serviceName() const;
- QString serviceDescription() const;
- QString serviceUuid() const;
- Protocol serviceProtocol() const;
- bool isRegistered() const;
-
- QBluetoothServiceInfo *serviceInfo() const;
-
- Q_INVOKABLE QDeclarativeBluetoothSocket *nextClient();
- Q_INVOKABLE void assignNextClient(QDeclarativeBluetoothSocket *dbs);
-
- // From QDeclarativeParserStatus
- void classBegin() {}
- void componentComplete();
-
- void setServiceName(const QString &name);
- void setDeviceAddress(const QString &address);
- void setServiceDescription(const QString &description);
- void setServiceUuid(const QString &uuid);
- void setServiceProtocol(QDeclarativeBluetoothService::Protocol protocol);
- void setRegistered(bool registered);
-
-signals:
- void detailsChanged();
- void registeredChanged();
- void newClient();
-
-private slots:
- void new_connection();
-
-private:
- QDeclarativeBluetoothServicePrivate* d;
- friend class QDeclarativeBluetoothServicePrivate;
-
-};
-
-QML_DECLARE_TYPE(QDeclarativeBluetoothService)
-
-#endif // QDECLARATIVEBLUETOOTHSERVICE_P_H
diff --git a/src/imports/bluetooth/qdeclarativebluetoothsocket.cpp b/src/imports/bluetooth/qdeclarativebluetoothsocket.cpp
deleted file mode 100644
index 0deb82a5..00000000
--- a/src/imports/bluetooth/qdeclarativebluetoothsocket.cpp
+++ /dev/null
@@ -1,385 +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 "qdeclarativebluetoothsocket_p.h"
-
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QPointer>
-#include <QtCore/QStringList>
-#include <QtCore/QDataStream>
-#include <QtCore/QByteArray>
-
-#include <QtBluetooth/QBluetoothDeviceInfo>
-#include <QtBluetooth/QBluetoothAddress>
-#include <QtBluetooth/QBluetoothSocket>
-
-/*!
- \qmltype BluetoothSocket
- \instantiates QDeclarativeBluetoothSocket
- \inqmlmodule QtBluetooth
- \since 5.2
- \brief Enables connecting and communicating with a Bluetooth service or
- device.
-
- \sa QBluetoothSocket
- \sa QDataStream
-
- It allows a QML class connect to another Bluetooth device and exchange strings
- with it. Data is sent and received using a QDataStream object allowing type
- safe transfers of QStrings. QDataStream is a well known format and can be
- decoded by non-Qt applications. Note that for the ease of use, BluetoothSocket
- is only well suited for use with strings. If you want to
- use a binary protocol for your application's communication you should
- consider using its C++ counterpart QBluetoothSocket.
-
- Connections to remote devices can be over RFCOMM or L2CAP. Either the remote port
- or service UUID is required. This is specified by creating a BluetoothService,
- or passing in the service return from BluetoothDiscoveryModel.
- */
-
-Q_DECLARE_LOGGING_CATEGORY(QT_BT_QML)
-
-class QDeclarativeBluetoothSocketPrivate
-{
-public:
- QDeclarativeBluetoothSocketPrivate(QDeclarativeBluetoothSocket *bs)
- : m_dbs(bs),
- m_error(QDeclarativeBluetoothSocket::NoError),
- m_state(QDeclarativeBluetoothSocket::NoServiceSet),
- m_componentCompleted(false),
- m_connected(false)
- {
-
- }
-
- ~QDeclarativeBluetoothSocketPrivate()
- {
- delete m_socket;
- }
-
- void connect()
- {
- Q_ASSERT(m_service);
- //qDebug() << "Connecting to: " << m_service->serviceInfo()->device().address().toString();
- m_error = QDeclarativeBluetoothSocket::NoError;
-
- if (m_socket)
- m_socket->deleteLater();
-
- QBluetoothServiceInfo::Protocol socketProtocol;
- if (m_service->serviceInfo()->socketProtocol() == QBluetoothServiceInfo::L2capProtocol)
- socketProtocol = QBluetoothServiceInfo::L2capProtocol;
- else if (m_service->serviceInfo()->socketProtocol() == QBluetoothServiceInfo::RfcommProtocol)
- socketProtocol = QBluetoothServiceInfo::RfcommProtocol;
- else
- socketProtocol = QBluetoothServiceInfo::UnknownProtocol;
-
- m_socket = new QBluetoothSocket(socketProtocol);
- m_socket->connectToService(*m_service->serviceInfo());
- QObject::connect(m_socket, &QBluetoothSocket::connected,
- m_dbs, &QDeclarativeBluetoothSocket::socket_connected);
- QObject::connect(m_socket, &QBluetoothSocket::disconnected,
- m_dbs, &QDeclarativeBluetoothSocket::socket_disconnected);
- QObject::connect(m_socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error),
- m_dbs, &QDeclarativeBluetoothSocket::socket_error);
- QObject::connect(m_socket, &QBluetoothSocket::stateChanged,
- m_dbs, &QDeclarativeBluetoothSocket::socket_state);
- QObject::connect(m_socket, &QIODevice::readyRead,
- m_dbs, &QDeclarativeBluetoothSocket::socket_readyRead);
- }
-
- QDeclarativeBluetoothSocket *m_dbs;
- QDeclarativeBluetoothService *m_service = nullptr;
- QBluetoothSocket *m_socket = nullptr;
- QDeclarativeBluetoothSocket::Error m_error;
- QDeclarativeBluetoothSocket::SocketState m_state;
- bool m_componentCompleted;
- bool m_connected;
-};
-
-QDeclarativeBluetoothSocket::QDeclarativeBluetoothSocket(QObject *parent) :
- QObject(parent)
-{
- d = new QDeclarativeBluetoothSocketPrivate(this);
-}
-
-QDeclarativeBluetoothSocket::QDeclarativeBluetoothSocket(QDeclarativeBluetoothService *service, QObject *parent)
- : QObject(parent)
-{
- d = new QDeclarativeBluetoothSocketPrivate(this);
- d->m_service = service;
-}
-
-QDeclarativeBluetoothSocket::QDeclarativeBluetoothSocket(QBluetoothSocket *socket, QDeclarativeBluetoothService *service, QObject *parent)
- : QObject(parent)
-{
- d = new QDeclarativeBluetoothSocketPrivate(this);
- d->m_service = service;
- d->m_socket = socket;
- d->m_connected = true;
- d->m_componentCompleted = true;
-
- QObject::connect(socket, SIGNAL(connected()), this, SLOT(socket_connected()));
- QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(socket_disconnected()));
- QObject::connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(socket_error(QBluetoothSocket::SocketError)));
- QObject::connect(socket, SIGNAL(stateChanged(QBluetoothSocket::SocketState)), this, SLOT(socket_state(QBluetoothSocket::SocketState)));
- QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(socket_readyRead()));
-}
-
-
-QDeclarativeBluetoothSocket::~QDeclarativeBluetoothSocket()
-{
- delete d;
-}
-
-void QDeclarativeBluetoothSocket::componentComplete()
-{
- d->m_componentCompleted = true;
-
- if (d->m_connected && d->m_service)
- d->connect();
-}
-
-/*!
- \qmlproperty BluetoothService BluetoothSocket::service
-
- This property holds the details of the remote service to connect to. It can be
- set to a static BluetoothService with a fixed description, or a service returned
- by service discovery.
- */
-
-
-QDeclarativeBluetoothService *QDeclarativeBluetoothSocket::service()
-{
- return d->m_service;
-}
-
-void QDeclarativeBluetoothSocket::setService(QDeclarativeBluetoothService *service)
-{
- d->m_service = service;
-
- if (!d->m_componentCompleted)
- return;
-
- if (d->m_connected)
- d->connect();
- emit serviceChanged();
-}
-
-/*!
- \qmlproperty bool BluetoothSocket::connected
-
- This property holds the connection state of the socket. If the socket is
- connected to peer, it returns true. It can be set true or false to control the
- connection. When set to true, the property will not return true until the
- connection is established.
-
- */
-
-
-bool QDeclarativeBluetoothSocket::connected() const
-{
- if (!d->m_socket)
- return false;
-
- return d->m_socket->state() == QBluetoothSocket::ConnectedState;
-}
-
-void QDeclarativeBluetoothSocket::setConnected(bool connected)
-{
- d->m_connected = connected;
- if (connected && d->m_componentCompleted) {
- if (d->m_service) {
- d->connect();
- }
- else {
- qCWarning(QT_BT_QML) << "BluetoothSocket::setConnected called before a service was set";
- }
- }
-
- if (!connected && d->m_socket){
- d->m_socket->close();
- }
-}
-
-/*!
- \qmlproperty enumeration BluetoothSocket::error
-
- This property holds the last error that happened.
- \list
- \li \c{NoError}
- \li \c{UnknownSocketError}
- \li \c{HostNotFoundError}
- \li \c{ServiceNotFoundError}
- \li \c{NetworkError}
- \li \c{UnsupportedProtocolError}
- \li \c{RemoteHostClosedError}
- \endlist
-
- The errors are derived from \l QBluetoothSocket::SocketError. This property is read-only.
-*/
-
-
-QDeclarativeBluetoothSocket::Error QDeclarativeBluetoothSocket::error() const
-{
- return d->m_error;
-}
-
-void QDeclarativeBluetoothSocket::socket_connected()
-{
- emit connectedChanged();
-}
-
-void QDeclarativeBluetoothSocket::socket_disconnected()
-{
- d->m_socket->deleteLater();
- d->m_socket = nullptr;
- emit connectedChanged();
-}
-
-void QDeclarativeBluetoothSocket::socket_error(QBluetoothSocket::SocketError error)
-{
- d->m_error = static_cast<QDeclarativeBluetoothSocket::Error>(error);
-
- emit errorChanged();
-}
-
-void QDeclarativeBluetoothSocket::socket_state(QBluetoothSocket::SocketState state)
-{
- d->m_state = static_cast<QDeclarativeBluetoothSocket::SocketState>(state);
-
- emit stateChanged();
-}
-
-/*!
- \qmlproperty enumeration BluetoothSocket::state
-
- This property holds the current state of the socket.
-
- \list
- \li \c{NoServiceSet}
- \li \c{Unconnected}
- \li \c{ServiceLookup}
- \li \c{Connecting}
- \li \c{Connected}
- \li \c{Closing}
- \li \c{Listening}
- \li \c{Bound}
- \endlist
-
- The states (except \c{NoServiceSet}) are derived from \l QBluetoothSocket::SocketState. This property is read-only.
- \c{NoServiceSet} indicates that the socket state is not yet available due to the \l service not being
- set yet.
-*/
-QDeclarativeBluetoothSocket::SocketState QDeclarativeBluetoothSocket::state() const
-{
- return d->m_state;
-}
-
-void QDeclarativeBluetoothSocket::socket_readyRead()
-{
- emit dataAvailable();
-}
-
-/*!
- \qmlproperty string BluetoothSocket::stringData
-
- This property receives or sends data to a remote Bluetooth device. Arrival of
- data can be detected by connecting to this properties changed signal and can be read via
- stringData. Setting stringData will transmit the string.
- If excessive amounts of data are sent, the function may block sending. Reading will
- never block.
- */
-
-QString QDeclarativeBluetoothSocket::stringData()
-{
- if (!d->m_socket|| !d->m_socket->bytesAvailable())
- return QString();
-
- QString data;
- while (d->m_socket->canReadLine()) {
- QByteArray line = d->m_socket->readLine();
- data += QString::fromUtf8(line.constData(), line.length());
- }
- return data;
-}
-
-/*!
- This method transmits the string data passed with "data" to the remote device.
- If excessive amounts of data are sent, the function may block sending.
- */
-
-void QDeclarativeBluetoothSocket::sendStringData(const QString &data)
-{
- if (!d->m_connected || !d->m_socket){
- qCWarning(QT_BT_QML) << "Writing data to unconnected socket";
- return;
- }
-
- QByteArray text = data.toUtf8() + '\n';
- d->m_socket->write(text);
-}
-
-void QDeclarativeBluetoothSocket::newSocket(QBluetoothSocket *socket, QDeclarativeBluetoothService *service)
-{
- if (d->m_socket){
- delete d->m_socket;
- }
-
- d->m_service = service;
- d->m_socket = socket;
- d->m_connected = true;
- d->m_componentCompleted = true;
- d->m_error = NoError;
-
- QObject::connect(socket, &QBluetoothSocket::connected,
- this, &QDeclarativeBluetoothSocket::socket_connected);
- QObject::connect(socket, &QBluetoothSocket::disconnected,
- this, &QDeclarativeBluetoothSocket::socket_disconnected);
- QObject::connect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error),
- this, &QDeclarativeBluetoothSocket::socket_error);
- QObject::connect(socket, &QBluetoothSocket::stateChanged,
- this, &QDeclarativeBluetoothSocket::socket_state);
- QObject::connect(socket, &QIODevice::readyRead,
- this, &QDeclarativeBluetoothSocket::socket_readyRead);
-
- socket_state(socket->state());
-
- emit connectedChanged();
-}
diff --git a/src/imports/bluetooth/qdeclarativebluetoothsocket_p.h b/src/imports/bluetooth/qdeclarativebluetoothsocket_p.h
deleted file mode 100644
index 2c17b4b1..00000000
--- a/src/imports/bluetooth/qdeclarativebluetoothsocket_p.h
+++ /dev/null
@@ -1,148 +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 QDECLARATIVEBLUETOOTHSOCKET_P_H
-#define QDECLARATIVEBLUETOOTHSOCKET_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 <QObject>
-#include <qqml.h>
-#include <QQmlParserStatus>
-
-#include <QtBluetooth/QBluetoothSocket>
-
-#include "qdeclarativebluetoothservice_p.h"
-
-QT_USE_NAMESPACE
-
-class QDeclarativeBluetoothSocketPrivate;
-class QDeclarativeBluetoothService;
-
-class QDeclarativeBluetoothSocket : public QObject, public QQmlParserStatus
-{
- Q_OBJECT
- Q_PROPERTY(QDeclarativeBluetoothService *service READ service WRITE setService NOTIFY serviceChanged)
- Q_PROPERTY(bool connected READ connected WRITE setConnected NOTIFY connectedChanged)
- Q_PROPERTY(Error error READ error NOTIFY errorChanged)
- Q_PROPERTY(SocketState socketState READ state NOTIFY stateChanged)
- Q_PROPERTY(QString stringData READ stringData WRITE sendStringData NOTIFY dataAvailable)
- Q_INTERFACES(QQmlParserStatus)
-
-public:
- enum Error {
- NoError = QBluetoothSocket::NoSocketError,
- UnknownSocketError = QBluetoothSocket::UnknownSocketError,
- RemoteHostClosedError = QBluetoothSocket::RemoteHostClosedError,
- HostNotFoundError = QBluetoothSocket::HostNotFoundError,
- ServiceNotFoundError = QBluetoothSocket::ServiceNotFoundError,
- NetworkError = QBluetoothSocket::NetworkError,
- UnsupportedProtocolError = QBluetoothSocket::UnsupportedProtocolError
- };
- Q_ENUM(Error)
-
- enum SocketState {
- Unconnected = QBluetoothSocket::UnconnectedState,
- ServiceLookup = QBluetoothSocket::ServiceLookupState,
- Connecting = QBluetoothSocket::ConnectingState,
- Connected = QBluetoothSocket::ConnectedState,
- Bound = QBluetoothSocket::BoundState,
- Closing = QBluetoothSocket::ClosingState,
- Listening = QBluetoothSocket::ListeningState,
- NoServiceSet = 100 //Leave gap for future enums and to avoid collision with QBluetoothSocket enums
- };
- Q_ENUM(SocketState)
-
- explicit QDeclarativeBluetoothSocket(QObject *parent = nullptr);
- explicit QDeclarativeBluetoothSocket(QDeclarativeBluetoothService *service,
- QObject *parent = nullptr);
- explicit QDeclarativeBluetoothSocket(QBluetoothSocket *socket, QDeclarativeBluetoothService *service,
- QObject *paprent = nullptr);
- ~QDeclarativeBluetoothSocket();
-
- QDeclarativeBluetoothService *service();
- bool connected() const;
- Error error() const;
- SocketState state() const;
-
- QString stringData();
-
- // From QDeclarativeParserStatus
- void classBegin() {}
- void componentComplete();
-
- void newSocket(QBluetoothSocket *socket, QDeclarativeBluetoothService *service);
-
-signals:
- void serviceChanged();
- void connectedChanged();
- void errorChanged();
- void stateChanged();
- void dataAvailable();
-
-public slots:
- void setService(QDeclarativeBluetoothService *service);
- void setConnected(bool connected);
- void sendStringData(const QString& data);
-
-private slots:
- void socket_connected();
- void socket_disconnected();
- void socket_error(QBluetoothSocket::SocketError);
- void socket_state(QBluetoothSocket::SocketState);
- void socket_readyRead();
-
-private:
- QDeclarativeBluetoothSocketPrivate* d;
- friend class QDeclarativeBluetoothSocketPrivate;
-
-};
-
-QML_DECLARE_TYPE(QDeclarativeBluetoothSocket)
-
-#endif // QDECLARATIVEBLUETOOTHSOCKET_P_H
diff --git a/src/imports/bluetooth/qmldir b/src/imports/bluetooth/qmldir
deleted file mode 100644
index 2f5b2fac..00000000
--- a/src/imports/bluetooth/qmldir
+++ /dev/null
@@ -1,4 +0,0 @@
-module QtBluetooth
-plugin declarative_bluetooth
-classname QBluetoothQmlPlugin
-typeinfo plugins.qmltypes
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
deleted file mode 100644
index f5e92257..00000000
--- a/src/imports/imports.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-TEMPLATE = subdirs
-
-qtHaveModule(bluetooth): SUBDIRS += bluetooth
-qtHaveModule(nfc): SUBDIRS += nfc
diff --git a/src/imports/nfc/nfc.pro b/src/imports/nfc/nfc.pro
deleted file mode 100644
index e7ce081b..00000000
--- a/src/imports/nfc/nfc.pro
+++ /dev/null
@@ -1,20 +0,0 @@
-TARGETPATH = QtNfc
-
-QT = core qml nfc
-
-# Input
-HEADERS += \
- qdeclarativenearfield_p.h \
- qdeclarativendeffilter_p.h \
- qdeclarativendeftextrecord_p.h \
- qdeclarativendefurirecord_p.h \
- qdeclarativendefmimerecord_p.h
-
-SOURCES += plugin.cpp \
- qdeclarativenearfield.cpp \
- qdeclarativendeffilter.cpp \
- qdeclarativendeftextrecord.cpp \
- qdeclarativendefurirecord.cpp \
- qdeclarativendefmimerecord.cpp
-
-load(qml_plugin)
diff --git a/src/imports/nfc/plugin.cpp b/src/imports/nfc/plugin.cpp
deleted file mode 100644
index 3a6806fa..00000000
--- a/src/imports/nfc/plugin.cpp
+++ /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 QtNfc 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 <QtQml/QQmlEngine>
-#include <QtQml/QQmlExtensionPlugin>
-
-#include "qqmlndefrecord.h"
-#include "qdeclarativenearfield_p.h"
-#include "qdeclarativendeffilter_p.h"
-#include "qdeclarativendeftextrecord_p.h"
-#include "qdeclarativendefurirecord_p.h"
-#include "qdeclarativendefmimerecord_p.h"
-
-QT_USE_NAMESPACE
-
-class QNfcQmlPlugin : public QQmlExtensionPlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
-
-public:
- QNfcQmlPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { }
- void registerTypes(const char *uri)
- {
- Q_ASSERT(uri == QStringLiteral("QtNfc"));
-
- // @uri QtNfc
-
- // Register the 5.0 types
- int major = 5;
- int minor = 0;
-
- qmlRegisterType<QDeclarativeNearField>(uri, major, minor, "NearField");
- qmlRegisterType<QDeclarativeNdefFilter>(uri, major, minor, "NdefFilter");
- qmlRegisterType<QQmlNdefRecord>(uri, major, minor, "NdefRecord");
- qmlRegisterType<QDeclarativeNdefTextRecord>(uri, major, minor, "NdefTextRecord");
- qmlRegisterType<QDeclarativeNdefUriRecord>(uri, major, minor, "NdefUriRecord");
- qmlRegisterType<QDeclarativeNdefMimeRecord>(uri, major, minor, "NdefMimeRecord");
-
- // Register the 5.2 types
- minor = 2;
- qmlRegisterType<QDeclarativeNearField>(uri, major, minor, "NearField");
- qmlRegisterType<QDeclarativeNdefFilter>(uri, major, minor, "NdefFilter");
- qmlRegisterType<QQmlNdefRecord>(uri, major, minor, "NdefRecord");
- qmlRegisterType<QDeclarativeNdefTextRecord>(uri, major, minor, "NdefTextRecord");
- qmlRegisterType<QDeclarativeNdefUriRecord>(uri, major, minor, "NdefUriRecord");
- qmlRegisterType<QDeclarativeNdefMimeRecord>(uri, major, minor, "NdefMimeRecord");
-
- // Register the 5.4 types
- // introduces 5.4 version, other existing 5.2 exports become automatically available under 5.2-5.4l
- minor = 4;
- qmlRegisterType<QDeclarativeNearField>(uri, major, minor, "NearField");
-
- // Register the 5.5 types
- minor = 5;
- qmlRegisterType<QDeclarativeNearField, 1>(uri, major, minor, "NearField");
-
-
- // Register the latest Qt version as QML type version
- qmlRegisterModule(uri, QT_VERSION_MAJOR, QT_VERSION_MINOR);
- }
-};
-
-#include "plugin.moc"
-
diff --git a/src/imports/nfc/plugins.qmltypes b/src/imports/nfc/plugins.qmltypes
deleted file mode 100644
index 2151ad7d..00000000
--- a/src/imports/nfc/plugins.qmltypes
+++ /dev/null
@@ -1,91 +0,0 @@
-import QtQuick.tooling 1.2
-
-// This file describes the plugin-supplied types contained in the library.
-// It is used for QML tooling purposes only.
-//
-// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtNfc 5.14'
-
-Module {
- dependencies: ["QtQuick 2.0"]
- Component {
- name: "QDeclarativeNdefFilter"
- prototype: "QObject"
- exports: ["QtNfc/NdefFilter 5.0", "QtNfc/NdefFilter 5.2"]
- exportMetaObjectRevisions: [0, 0]
- Property { name: "type"; type: "string" }
- Property { name: "typeNameFormat"; type: "QQmlNdefRecord::TypeNameFormat" }
- Property { name: "minimum"; type: "int" }
- Property { name: "maximum"; type: "int" }
- }
- Component {
- name: "QDeclarativeNdefMimeRecord"
- prototype: "QQmlNdefRecord"
- exports: ["QtNfc/NdefMimeRecord 5.0", "QtNfc/NdefMimeRecord 5.2"]
- exportMetaObjectRevisions: [0, 0]
- Property { name: "uri"; type: "string"; isReadonly: true }
- }
- Component {
- name: "QDeclarativeNdefTextRecord"
- prototype: "QQmlNdefRecord"
- exports: ["QtNfc/NdefTextRecord 5.0", "QtNfc/NdefTextRecord 5.2"]
- exportMetaObjectRevisions: [0, 0]
- Enum {
- name: "LocaleMatch"
- values: {
- "LocaleMatchedNone": 0,
- "LocaleMatchedEnglish": 1,
- "LocaleMatchedLanguage": 2,
- "LocaleMatchedLanguageAndCountry": 3
- }
- }
- Property { name: "text"; type: "string" }
- Property { name: "locale"; type: "string" }
- Property { name: "localeMatch"; type: "LocaleMatch"; isReadonly: true }
- }
- Component {
- name: "QDeclarativeNdefUriRecord"
- prototype: "QQmlNdefRecord"
- exports: ["QtNfc/NdefUriRecord 5.0", "QtNfc/NdefUriRecord 5.2"]
- exportMetaObjectRevisions: [0, 0]
- Property { name: "uri"; type: "string" }
- }
- Component {
- name: "QDeclarativeNearField"
- prototype: "QObject"
- exports: [
- "QtNfc/NearField 5.0",
- "QtNfc/NearField 5.2",
- "QtNfc/NearField 5.4",
- "QtNfc/NearField 5.5"
- ]
- exportMetaObjectRevisions: [0, 0, 0, 1]
- Property { name: "messageRecords"; type: "QQmlNdefRecord"; isList: true; isReadonly: true }
- Property { name: "filter"; type: "QDeclarativeNdefFilter"; isList: true; isReadonly: true }
- Property { name: "orderMatch"; type: "bool" }
- Property { name: "polling"; revision: 1; type: "bool" }
- Signal { name: "pollingChanged"; revision: 1 }
- Signal { name: "tagFound"; revision: 1 }
- Signal { name: "tagRemoved"; revision: 1 }
- }
- Component {
- name: "QQmlNdefRecord"
- prototype: "QObject"
- exports: ["QtNfc/NdefRecord 5.0", "QtNfc/NdefRecord 5.2"]
- exportMetaObjectRevisions: [0, 0]
- Enum {
- name: "TypeNameFormat"
- values: {
- "Empty": 0,
- "NfcRtd": 1,
- "Mime": 2,
- "Uri": 3,
- "ExternalRtd": 4,
- "Unknown": 5
- }
- }
- Property { name: "type"; type: "string" }
- Property { name: "typeNameFormat"; type: "TypeNameFormat" }
- Property { name: "record"; type: "QNdefRecord" }
- }
-}
diff --git a/src/imports/nfc/qdeclarativendeffilter.cpp b/src/imports/nfc/qdeclarativendeffilter.cpp
deleted file mode 100644
index 96cf4f3a..00000000
--- a/src/imports/nfc/qdeclarativendeffilter.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qdeclarativendeffilter_p.h"
-
-#include <limits.h>
-
-/*!
- \qmltype NdefFilter
- \instantiates QDeclarativeNdefFilter
- \since 5.2
- \brief Represents a filtering constraint for NDEF message records.
-
- \ingroup nfc-qml
- \inqmlmodule QtNfc
-
- \sa NearField
- \sa QNdefFilter
-
- The NdefFilter type is used with the NearField type to read NDEF messages from NFC Forum
- tags that match a given structure.
-
- \code
- NearField {
- filter: [
- NdefFilter {
- type: "urn:nfc:wkt:U"
- minimum: 1
- maximum: 1
- }
- ]
- }
- \endcode
-*/
-
-/*!
- \qmlproperty string NdefFilter::type
-
- This property holds the NDEF record type that the filter matches. This property must be set to
- the fully qualified record type, i.e. including the NIS and NSS prefixes. For example set to
- \c {urn:nfc:wkt:U} to match NFC RTD-URI records.
-*/
-
-/*!
- \qmlproperty QQmlNdefRecord::TypeNameFormat NdefFilter::typeNameFormat
-
- This property holds the NDEF record name format type \l QQmlNdefRecord::TypeNameFormat.
-*/
-
-/*!
- \qmlproperty int NdefFilter::minimum
-
- This property holds the minimum number of records of the given type that must be in the NDEF
- message for it match.
-
- The default minimum is 1.
-
- \sa maximum
-*/
-
-/*!
- \qmlproperty int NdefFilter::maximum
-
- This property holds the maximum number of records of the given type that must be in the NDEF
- message for it match.
-
- The default maximum is UINT_MAX.
-
- \sa minimum
-*/
-
-QDeclarativeNdefFilter::QDeclarativeNdefFilter(QObject *parent)
-: QObject(parent), m_minimum(1), m_maximum(INT_MAX)
-{
-}
-
-QString QDeclarativeNdefFilter::type() const
-{
- return m_type;
-}
-
-void QDeclarativeNdefFilter::setType(const QString &t)
-{
- if (m_type == t)
- return;
-
- m_type = t;
- emit typeChanged();
-}
-
-QQmlNdefRecord::TypeNameFormat QDeclarativeNdefFilter::typeNameFormat() const
-{
- return m_typeNameFormat;
-}
-
-void QDeclarativeNdefFilter::setTypeNameFormat(QQmlNdefRecord::TypeNameFormat format)
-{
- if (m_typeNameFormat == format)
- return;
-
- m_typeNameFormat = format;
- emit typeNameFormatChanged();
-}
-
-int QDeclarativeNdefFilter::minimum() const
-{
- return m_minimum;
-}
-
-void QDeclarativeNdefFilter::setMinimum(int value)
-{
- if (m_minimum == value)
- return;
-
- m_minimum = value;
- emit minimumChanged();
-}
-
-int QDeclarativeNdefFilter::maximum() const
-{
- return m_maximum;
-}
-
-void QDeclarativeNdefFilter::setMaximum(int value)
-{
- if (m_maximum == value)
- return;
-
- m_maximum = value;
- emit maximumChanged();
-}
diff --git a/src/imports/nfc/qdeclarativendeffilter_p.h b/src/imports/nfc/qdeclarativendeffilter_p.h
deleted file mode 100644
index 7ecc3093..00000000
--- a/src/imports/nfc/qdeclarativendeffilter_p.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QDECLARATIVENDEFFILTER_P_H
-#define QDECLARATIVENDEFFILTER_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 <qqmlndefrecord.h>
-
-class QDeclarativeNdefFilter : public QObject
-{
- Q_OBJECT
-
- Q_PROPERTY(QString type READ type WRITE setType NOTIFY typeChanged)
- Q_PROPERTY(QQmlNdefRecord::TypeNameFormat typeNameFormat READ typeNameFormat WRITE setTypeNameFormat NOTIFY typeNameFormatChanged)
- Q_PROPERTY(int minimum READ minimum WRITE setMinimum NOTIFY minimumChanged)
- Q_PROPERTY(int maximum READ maximum WRITE setMaximum NOTIFY maximumChanged)
-public:
- explicit QDeclarativeNdefFilter(QObject *parent = 0);
-
- QString type() const;
- void setType(const QString &t);
-
- QQmlNdefRecord::TypeNameFormat typeNameFormat() const;
- void setTypeNameFormat(QQmlNdefRecord::TypeNameFormat format);
-
- int minimum() const;
- void setMinimum(int value);
-
- int maximum() const;
- void setMaximum(int value);
-
-signals:
- void typeChanged();
- void minimumChanged();
- void maximumChanged();
- void typeNameFormatChanged();
-
-private:
- QString m_type;
- int m_minimum;
- int m_maximum;
- QQmlNdefRecord::TypeNameFormat m_typeNameFormat;
-};
-
-#endif // QDECLARATIVENDEFFILTER_P_H
diff --git a/src/imports/nfc/qdeclarativendefmimerecord.cpp b/src/imports/nfc/qdeclarativendefmimerecord.cpp
deleted file mode 100644
index ffeecfb1..00000000
--- a/src/imports/nfc/qdeclarativendefmimerecord.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qdeclarativendefmimerecord_p.h"
-
-/*!
- \qmltype NdefMimeRecord
- \since 5.2
- \brief Represents an NFC MIME record.
-
- \ingroup connectivity-nfc
- \inqmlmodule QtNfc
-
- \inherits NdefRecord
-
- The NdefMimeRecord type can contain data with an associated MIME type. The data is
- accessible from the uri in the \l {NdefMimeRecord::uri}{uri} property.
-*/
-
-/*!
- \qmlproperty string NdefMimeRecord::uri
-
- This property hold the URI from which the MIME data can be fetched from. Currently this
- property returns a data url.
-*/
-
-Q_DECLARE_NDEFRECORD(QDeclarativeNdefMimeRecord, QNdefRecord::Mime, ".*")
-
-static inline QNdefRecord createMimeRecord()
-{
- QNdefRecord mimeRecord;
- mimeRecord.setTypeNameFormat(QNdefRecord::Mime);
- return mimeRecord;
-}
-
-static inline QNdefRecord castToMimeRecord(const QNdefRecord &record)
-{
- if (record.typeNameFormat() != QNdefRecord::Mime)
- return createMimeRecord();
- return record;
-}
-
-QDeclarativeNdefMimeRecord::QDeclarativeNdefMimeRecord(QObject *parent)
-: QQmlNdefRecord(createMimeRecord(), parent)
-{
-}
-
-QDeclarativeNdefMimeRecord::QDeclarativeNdefMimeRecord(const QNdefRecord &record, QObject *parent)
-: QQmlNdefRecord(castToMimeRecord(record), parent)
-{
-}
-
-QDeclarativeNdefMimeRecord::~QDeclarativeNdefMimeRecord()
-{
-}
-
-QString QDeclarativeNdefMimeRecord::uri() const
-{
- QByteArray dataUri = "data:" + record().type() + ";base64," + record().payload().toBase64();
- return QString::fromLatin1(dataUri.constData(), dataUri.length());
-}
diff --git a/src/imports/nfc/qdeclarativendefmimerecord_p.h b/src/imports/nfc/qdeclarativendefmimerecord_p.h
deleted file mode 100644
index a06f5218..00000000
--- a/src/imports/nfc/qdeclarativendefmimerecord_p.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QDECLARATIVENDEFMIMERECORD_P_H
-#define QDECLARATIVENDEFMIMERECORD_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 <qqmlndefrecord.h>
-
-QT_USE_NAMESPACE
-
-class QDeclarativeNdefMimeRecord : public QQmlNdefRecord
-{
- Q_OBJECT
-
- Q_PROPERTY(QString uri READ uri NOTIFY uriChanged)
-
-public:
- explicit QDeclarativeNdefMimeRecord(QObject *parent = 0);
- Q_INVOKABLE QDeclarativeNdefMimeRecord(const QNdefRecord &record, QObject *parent = 0);
- ~QDeclarativeNdefMimeRecord();
-
- QString uri() const;
-
-signals:
- void uriChanged();
-};
-
-#endif // QDECLARATIVENDEFMIMERECORD_P_H
diff --git a/src/imports/nfc/qdeclarativendeftextrecord.cpp b/src/imports/nfc/qdeclarativendeftextrecord.cpp
deleted file mode 100644
index ff93a44b..00000000
--- a/src/imports/nfc/qdeclarativendeftextrecord.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qdeclarativendeftextrecord_p.h"
-
-#include <QtCore/QLocale>
-
-/*!
- \qmltype NdefTextRecord
- \since 5.2
- \brief Represents an NFC RTD-Text NDEF record.
-
- \ingroup nfc-qml
- \inqmlmodule QtNfc
-
- \inherits NdefRecord
-
- \sa QNdefNfcTextRecord
-
- The NdefTextRecord type contains a localized piece of text that can be display to the user.
- An NDEF message may contain many text records for different locales, it is up to the
- application to select the most appropriate one to display to the user. The localeMatch
- property can be used to determine if the text record has been matched.
-*/
-
-/*!
- \qmlproperty string NdefTextRecord::text
-
- This property holds the text which should be displayed when the current locale matches
- \l locale.
-*/
-
-/*!
- \qmlproperty string NdefTextRecord::locale
-
- This property holds the locale that this text record is for.
-*/
-
-/*!
- \qmlproperty enumeration NdefTextRecord::localeMatch
-
- This property holds an enum describing how closely the locale of the text record matches the
- applications current locale. The application should display only the text record that most
- closely matches the applications current locale.
-
- \table
- \header
- \li Value
- \li Description
- \row
- \li LocaleMatchedNone
- \li The text record does not match at all.
- \row
- \li LocaleMatchedEnglish
- \li The language of the text record is English and the language of application's current
- locale is \b {not} English. The English language text should be displayed if
- there is not a more appropriate match.
- \row
- \li LocaleMatchedLanguage
- \li The language of the text record and the language of the applications's current
- locale are the same.
- \row
- \li LocaleMatchedLanguageAndCountry
- \li The language and country of the text record matches that of the applicatin's current
- locale.
- \endtable
-*/
-
-Q_DECLARE_NDEFRECORD(QDeclarativeNdefTextRecord, QNdefRecord::NfcRtd, "T")
-
-QDeclarativeNdefTextRecord::QDeclarativeNdefTextRecord(QObject *parent)
-: QQmlNdefRecord(QNdefNfcTextRecord(), parent)
-{
-}
-
-QDeclarativeNdefTextRecord::QDeclarativeNdefTextRecord(const QNdefRecord &record, QObject *parent)
-: QQmlNdefRecord(QNdefNfcTextRecord(record), parent)
-{
-}
-
-QDeclarativeNdefTextRecord::~QDeclarativeNdefTextRecord()
-{
-}
-
-QString QDeclarativeNdefTextRecord::text() const
-{
- QNdefNfcTextRecord textRecord(record());
-
- return textRecord.text();
-}
-
-void QDeclarativeNdefTextRecord::setText(const QString &text)
-{
- QNdefNfcTextRecord textRecord(record());
-
- if (textRecord.text() == text)
- return;
-
- textRecord.setText(text);
- setRecord(textRecord);
- emit textChanged();
-}
-
-QString QDeclarativeNdefTextRecord::locale() const
-{
- if (!record().isRecordType<QNdefNfcTextRecord>())
- return QString();
-
- QNdefNfcTextRecord textRecord(record());
-
- return textRecord.locale();
-}
-
-void QDeclarativeNdefTextRecord::setLocale(const QString &locale)
-{
- QNdefNfcTextRecord textRecord(record());
-
- if (textRecord.locale() == locale)
- return;
-
- LocaleMatch previous = localeMatch();
-
- textRecord.setLocale(locale);
- setRecord(textRecord);
- emit localeChanged();
-
- if (previous != localeMatch())
- emit localeMatchChanged();
-}
-
-QDeclarativeNdefTextRecord::LocaleMatch QDeclarativeNdefTextRecord::localeMatch() const
-{
- const QLocale recordLocale(locale());
- const QLocale defaultLocale;
-
- if (recordLocale == defaultLocale)
- return LocaleMatchedLanguageAndCountry;
- else if (recordLocale.language() == defaultLocale.language())
- return LocaleMatchedLanguage;
- else if (recordLocale.language() == QLocale::English)
- return LocaleMatchedEnglish;
- else
- return LocaleMatchedNone;
-}
diff --git a/src/imports/nfc/qdeclarativendeftextrecord_p.h b/src/imports/nfc/qdeclarativendeftextrecord_p.h
deleted file mode 100644
index dc5ac1f5..00000000
--- a/src/imports/nfc/qdeclarativendeftextrecord_p.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QDECLARATIVENDEFTEXTRECORD_P_H
-#define QDECLARATIVENDEFTEXTRECORD_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 <qqmlndefrecord.h>
-
-#include <qndefnfctextrecord.h>
-
-QT_USE_NAMESPACE
-
-class QDeclarativeNdefTextRecord : public QQmlNdefRecord
-{
- Q_OBJECT
-
- Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
- Q_PROPERTY(QString locale READ locale WRITE setLocale NOTIFY localeChanged)
- Q_PROPERTY(LocaleMatch localeMatch READ localeMatch NOTIFY localeMatchChanged)
-
-public:
- enum LocaleMatch {
- LocaleMatchedNone,
- LocaleMatchedEnglish,
- LocaleMatchedLanguage,
- LocaleMatchedLanguageAndCountry
- };
- Q_ENUM(LocaleMatch)
-
- explicit QDeclarativeNdefTextRecord(QObject *parent = 0);
- Q_INVOKABLE QDeclarativeNdefTextRecord(const QNdefRecord &record, QObject *parent = 0);
- ~QDeclarativeNdefTextRecord();
-
- QString text() const;
- void setText(const QString &text);
-
- QString locale() const;
- void setLocale(const QString &locale);
-
- LocaleMatch localeMatch() const;
-
-signals:
- void textChanged();
- void localeChanged();
- void localeMatchChanged();
-};
-
-#endif // QDECLARATIVENDEFTEXTRECORD_P_H
diff --git a/src/imports/nfc/qdeclarativendefurirecord.cpp b/src/imports/nfc/qdeclarativendefurirecord.cpp
deleted file mode 100644
index b1f49712..00000000
--- a/src/imports/nfc/qdeclarativendefurirecord.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qdeclarativendefurirecord_p.h"
-
-#include <QtCore/QUrl>
-
-/*!
- \qmltype NdefUriRecord
- \since 5.2
- \brief Represents an NFC RTD-URI NDEF record.
-
- \ingroup nfc-qml
- \inqmlmodule QtNfc
-
- \inherits NdefRecord
-
- \sa QNdefNfcUriRecord
-
- The NdefUriRecord type can contain a uniform resource identifier.
-*/
-
-/*!
- \qmlproperty string NdefUriRecord::uri
-
- This property hold the URI stored in this URI record.
-*/
-
-Q_DECLARE_NDEFRECORD(QDeclarativeNdefUriRecord, QNdefRecord::NfcRtd, "U")
-
-QDeclarativeNdefUriRecord::QDeclarativeNdefUriRecord(QObject *parent)
-: QQmlNdefRecord(QNdefNfcUriRecord(), parent)
-{
-}
-
-QDeclarativeNdefUriRecord::QDeclarativeNdefUriRecord(const QNdefRecord &record, QObject *parent)
-: QQmlNdefRecord(QNdefNfcUriRecord(record), parent)
-{
-}
-
-QDeclarativeNdefUriRecord::~QDeclarativeNdefUriRecord()
-{
-}
-
-QString QDeclarativeNdefUriRecord::uri() const
-{
- QNdefNfcUriRecord uriRecord(record());
-
- return uriRecord.uri().toString();
-}
-
-void QDeclarativeNdefUriRecord::setUri(const QString &uri)
-{
- QNdefNfcUriRecord uriRecord(record());
-
- if (uriRecord.uri() == uri)
- return;
-
- uriRecord.setUri(uri);
- setRecord(uriRecord);
- emit uriChanged();
-}
diff --git a/src/imports/nfc/qdeclarativendefurirecord_p.h b/src/imports/nfc/qdeclarativendefurirecord_p.h
deleted file mode 100644
index 8f00567e..00000000
--- a/src/imports/nfc/qdeclarativendefurirecord_p.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QDECLARATIVENDEFURIRECORD_P_H
-#define QDECLARATIVENDEFURIRECORD_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 <qqmlndefrecord.h>
-
-#include <qndefnfcurirecord.h>
-
-#include <QtCore/QMetaType>
-
-QT_USE_NAMESPACE
-
-class QDeclarativeNdefUriRecord : public QQmlNdefRecord
-{
- Q_OBJECT
-
- Q_PROPERTY(QString uri READ uri WRITE setUri NOTIFY uriChanged)
-
-public:
- explicit QDeclarativeNdefUriRecord(QObject *parent = 0);
- Q_INVOKABLE QDeclarativeNdefUriRecord(const QNdefRecord &record, QObject *parent = 0);
- ~QDeclarativeNdefUriRecord();
-
- QString uri() const;
- void setUri(const QString &uri);
-
-signals:
- void uriChanged();
-};
-
-#endif // QDECLARATIVENDEFURIRECORD_P_H
diff --git a/src/imports/nfc/qdeclarativenearfield.cpp b/src/imports/nfc/qdeclarativenearfield.cpp
deleted file mode 100644
index c6c53ba4..00000000
--- a/src/imports/nfc/qdeclarativenearfield.cpp
+++ /dev/null
@@ -1,360 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qdeclarativenearfield_p.h"
-#include "qdeclarativendeffilter_p.h"
-#include "qdeclarativendeftextrecord_p.h"
-#include "qdeclarativendefurirecord_p.h"
-#include "qdeclarativendefmimerecord_p.h"
-
-#include <qndefmessage.h>
-#include <qndefnfctextrecord.h>
-#include <qndefnfcurirecord.h>
-
-#include <QtNfc/QNearFieldTarget>
-
-/*!
- \qmltype NearField
- \instantiates QDeclarativeNearField
- \since 5.2
- \brief Provides access to NDEF messages stored on NFC Forum tags.
-
- \ingroup nfc-qml
- \inqmlmodule QtNfc
-
- \sa NdefFilter
- \sa NdefRecord
-
- \sa QNearFieldManager
- \sa QNdefMessage
- \sa QNdefRecord
-
- The NearField type can be used to read NDEF messages from NFC Forum tags. Set the \l filter
- and \l orderMatch properties to match the required NDEF messages. Once an NDEF message is
- successfully read from a tag the \l messageRecords property is updated.
-
- \note For platforms using neard, filtering is currently not implemented. For more information
- on neard see \l QNearFieldManager.
-
- \snippet doc_src_qtnfc.qml QML register for messages
-*/
-
-/*!
- \qmlproperty list<NdefRecord> NearField::messageRecords
-
- This property contains the list of NDEF records in the last NDEF message read.
-*/
-
-/*!
- \qmlproperty list<NdefFilter> NearField::filter
-
- This property holds the NDEF filter constraints. The \l messageRecords property will only be
- set to NDEF messages which match the filter. If no filter is set, a message handler for
- all NDEF messages will be registered.
-
- \note Filtering is not supported when using neard.
-
- \l QNearFieldManager::registerNdefMessageHandler()
-*/
-
-/*!
- \qmlproperty bool NearField::orderMatch
-
- This property indicates whether the order of records should be taken into account when matching
- messages. This is not supported when using neard.
-
- The default of orderMatch is false.
-*/
-
-/*!
- \qmlproperty bool NearField::polling
- \since 5.5
-
- This property indicates if the underlying adapter is currently in polling state. If set to \c true
- the adapter will start polling and stop polling if set to \c false.
-
- \note On platforms using neard, the adapter will stop polling as soon as a tag has been detected.
- For more information see \l QNearFieldManager.
-*/
-
-/*!
- \qmlsignal NearField::tagFound()
- \since 5.5
-
- This signal will be emitted when a tag has been detected.
-*/
-
-/*!
- \qmlsignal NearField::tagRemoved()
- \since 5.5
-
- This signal will be emitted when a tag has been removed.
-*/
-
-QDeclarativeNearField::QDeclarativeNearField(QObject *parent)
- : QObject(parent),
- m_orderMatch(false),
- m_componentCompleted(false),
- m_messageUpdating(false),
- m_manager(new QNearFieldManager(this)),
- m_messageHandlerId(-1),
- m_polling(false)
-{
- connect(m_manager, SIGNAL(targetDetected(QNearFieldTarget*)),
- this, SLOT(_q_handleTargetDetected(QNearFieldTarget*)));
- connect(m_manager, SIGNAL(targetLost(QNearFieldTarget*)),
- this, SLOT(_q_handleTargetLost(QNearFieldTarget*)));
-}
-
-QQmlListProperty<QQmlNdefRecord> QDeclarativeNearField::messageRecords()
-{
- return QQmlListProperty<QQmlNdefRecord>(this, 0,
- &QDeclarativeNearField::append_messageRecord,
- &QDeclarativeNearField::count_messageRecords,
- &QDeclarativeNearField::at_messageRecord,
- &QDeclarativeNearField::clear_messageRecords);
-
-}
-
-QQmlListProperty<QDeclarativeNdefFilter> QDeclarativeNearField::filter()
-{
- return QQmlListProperty<QDeclarativeNdefFilter>(this, 0,
- &QDeclarativeNearField::append_filter,
- &QDeclarativeNearField::count_filters,
- &QDeclarativeNearField::at_filter,
- &QDeclarativeNearField::clear_filter);
-}
-
-bool QDeclarativeNearField::orderMatch() const
-{
- return m_orderMatch;
-}
-
-void QDeclarativeNearField::setOrderMatch(bool on)
-{
- if (m_orderMatch == on)
- return;
-
- m_orderMatch = on;
- emit orderMatchChanged();
-}
-
-void QDeclarativeNearField::componentComplete()
-{
- m_componentCompleted = true;
-
- registerMessageHandler();
-}
-
-bool QDeclarativeNearField::polling() const
-{
- return m_polling;
-}
-
-void QDeclarativeNearField::setPolling(bool on)
-{
- if (m_polling == on)
- return;
-
- if (on) {
- if (m_manager->startTargetDetection()) {
- m_polling = true;
- emit pollingChanged();
- }
- } else {
- m_manager->stopTargetDetection();
- m_polling = false;
- emit pollingChanged();
- }
-}
-
-void QDeclarativeNearField::registerMessageHandler()
-{
- if (m_messageHandlerId != -1)
- m_manager->unregisterNdefMessageHandler(m_messageHandlerId);
-
- QNdefFilter ndefFilter;
- ndefFilter.setOrderMatch(m_orderMatch);
- for (const QDeclarativeNdefFilter *filter : qAsConst(m_filterList)) {
- const QString type = filter->type();
- uint min = filter->minimum() < 0 ? UINT_MAX : filter->minimum();
- uint max = filter->maximum() < 0 ? UINT_MAX : filter->maximum();
-
- ndefFilter.appendRecord(static_cast<QNdefRecord::TypeNameFormat>(filter->typeNameFormat()), type.toUtf8(), min, max);
- }
-
- m_messageHandlerId = m_manager->registerNdefMessageHandler(ndefFilter, this, SLOT(_q_handleNdefMessage(QNdefMessage)));
-
- // FIXME: if a message handler has been registered we just assume that constant polling is done
- if (m_messageHandlerId >= 0) {
- m_polling = true;
- emit pollingChanged();
- }
-}
-
-void QDeclarativeNearField::_q_handleNdefMessage(const QNdefMessage &message)
-{
- m_messageUpdating = true;
-
- QQmlListReference listRef(this, "messageRecords");
-
- listRef.clear();
-
- for (const QNdefRecord &record : message)
- listRef.append(qNewDeclarativeNdefRecordForNdefRecord(record));
-
- m_messageUpdating = false;
-
- emit messageRecordsChanged();
-}
-
-void QDeclarativeNearField::_q_handleTargetLost(QNearFieldTarget *target)
-{
- Q_UNUSED(target);
- // FIXME: only notify that polling stopped when there is no registered message handler
- if (m_messageHandlerId == -1) {
- m_polling = false;
- emit pollingChanged();
- }
-
- emit tagRemoved();
-}
-
-void QDeclarativeNearField::_q_handleTargetDetected(QNearFieldTarget *target)
-{
- Q_UNUSED(target);
-
- if (m_messageHandlerId == -1) {
- connect(target, SIGNAL(ndefMessageRead(QNdefMessage)),
- this, SLOT(_q_handleNdefMessage(QNdefMessage)));
- target->readNdefMessages();
- }
-
- emit tagFound();
-}
-
-void QDeclarativeNearField::append_messageRecord(QQmlListProperty<QQmlNdefRecord> *list,
- QQmlNdefRecord *record)
-{
- QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object);
- if (!nearField)
- return;
-
- record->setParent(nearField);
- nearField->m_message.append(record);
- if (!nearField->m_messageUpdating)
- emit nearField->messageRecordsChanged();
-}
-
-int QDeclarativeNearField::count_messageRecords(QQmlListProperty<QQmlNdefRecord> *list)
-{
- QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object);
- if (!nearField)
- return 0;
-
- return nearField->m_message.count();
-}
-
-QQmlNdefRecord *QDeclarativeNearField::at_messageRecord(QQmlListProperty<QQmlNdefRecord> *list,
- int index)
-{
- QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object);
- if (!nearField)
- return 0;
-
- return nearField->m_message.at(index);
-}
-
-void QDeclarativeNearField::clear_messageRecords(QQmlListProperty<QQmlNdefRecord> *list)
-{
- QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object);
- if (nearField) {
- qDeleteAll(nearField->m_message);
- nearField->m_message.clear();
- if (!nearField->m_messageUpdating)
- emit nearField->messageRecordsChanged();
- }
-}
-
-void QDeclarativeNearField::append_filter(QQmlListProperty<QDeclarativeNdefFilter> *list,
- QDeclarativeNdefFilter *filter)
-{
- QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object);
- if (!nearField)
- return;
-
- filter->setParent(nearField);
- nearField->m_filterList.append(filter);
- emit nearField->filterChanged();
-
- if (nearField->m_componentCompleted)
- nearField->registerMessageHandler();
-}
-
-int QDeclarativeNearField::count_filters(QQmlListProperty<QDeclarativeNdefFilter> *list)
-{
- QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object);
- if (!nearField)
- return 0;
-
- return nearField->m_filterList.count();
-}
-
-QDeclarativeNdefFilter *QDeclarativeNearField::at_filter(QQmlListProperty<QDeclarativeNdefFilter> *list,
- int index)
-{
- QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object);
- if (!nearField)
- return 0;
-
- return nearField->m_filterList.at(index);
-}
-
-void QDeclarativeNearField::clear_filter(QQmlListProperty<QDeclarativeNdefFilter> *list)
-{
- QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object);
- if (!nearField)
- return;
-
- qDeleteAll(nearField->m_filterList);
- nearField->m_filterList.clear();
- emit nearField->filterChanged();
- if (nearField->m_componentCompleted)
- nearField->registerMessageHandler();
-}
diff --git a/src/imports/nfc/qdeclarativenearfield_p.h b/src/imports/nfc/qdeclarativenearfield_p.h
deleted file mode 100644
index ad26da8d..00000000
--- a/src/imports/nfc/qdeclarativenearfield_p.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QDECLARATIVENEARFIELD_P_H
-#define QDECLARATIVENEARFIELD_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 <QtQml/qqml.h>
-#include <QtQml/QQmlParserStatus>
-#include <QtNfc/QNearFieldManager>
-
-#include "qqmlndefrecord.h"
-
-
-QT_USE_NAMESPACE
-
-class QDeclarativeNdefFilter;
-class QDeclarativeNearField : public QObject, public QQmlParserStatus
-{
- Q_OBJECT
-
- Q_PROPERTY(QQmlListProperty<QQmlNdefRecord> messageRecords READ messageRecords NOTIFY messageRecordsChanged)
- Q_PROPERTY(QQmlListProperty<QDeclarativeNdefFilter> filter READ filter NOTIFY filterChanged)
- Q_PROPERTY(bool orderMatch READ orderMatch WRITE setOrderMatch NOTIFY orderMatchChanged)
- Q_PROPERTY(bool polling READ polling WRITE setPolling NOTIFY pollingChanged REVISION 1)
-
- Q_INTERFACES(QQmlParserStatus)
-
-public:
- explicit QDeclarativeNearField(QObject *parent = 0);
-
- QQmlListProperty<QQmlNdefRecord> messageRecords();
-
- QQmlListProperty<QDeclarativeNdefFilter> filter();
-
- bool orderMatch() const;
- void setOrderMatch(bool on);
-
- // From QDeclarativeParserStatus
- void classBegin() { }
- void componentComplete();
-
- bool polling() const;
- void setPolling(bool on);
-
-signals:
- void messageRecordsChanged();
- void filterChanged();
- void orderMatchChanged();
- Q_REVISION(1) void pollingChanged();
-
- Q_REVISION(1) void tagFound();
- Q_REVISION(1) void tagRemoved();
-
-private slots:
- void _q_handleNdefMessage(const QNdefMessage &message);
- void _q_handleTargetLost(QNearFieldTarget*);
- void _q_handleTargetDetected(QNearFieldTarget*);
-
-private:
- QList<QQmlNdefRecord *> m_message;
- QList<QDeclarativeNdefFilter *> m_filterList;
- bool m_orderMatch;
- bool m_componentCompleted;
- bool m_messageUpdating;
-
- QNearFieldManager *m_manager;
- int m_messageHandlerId;
- bool m_polling;
-
- void registerMessageHandler();
-
- static void append_messageRecord(QQmlListProperty<QQmlNdefRecord> *list,
- QQmlNdefRecord *record);
- static int count_messageRecords(QQmlListProperty<QQmlNdefRecord> *list);
- static QQmlNdefRecord *at_messageRecord(QQmlListProperty<QQmlNdefRecord> *list,
- int index);
- static void clear_messageRecords(QQmlListProperty<QQmlNdefRecord> *list);
-
- static void append_filter(QQmlListProperty<QDeclarativeNdefFilter> *list,
- QDeclarativeNdefFilter *filter);
- static int count_filters(QQmlListProperty<QDeclarativeNdefFilter> *list);
- static QDeclarativeNdefFilter *at_filter(QQmlListProperty<QDeclarativeNdefFilter> *list,
- int index);
- static void clear_filter(QQmlListProperty<QDeclarativeNdefFilter> *list);
-};
-
-#endif // QDECLARATIVENEARFIELD_P_H
diff --git a/src/imports/nfc/qmldir b/src/imports/nfc/qmldir
deleted file mode 100644
index 0025f3e6..00000000
--- a/src/imports/nfc/qmldir
+++ /dev/null
@@ -1,4 +0,0 @@
-module QtNfc
-plugin declarative_nfc
-classname QNfcQmlPlugin
-typeinfo plugins.qmltypes
diff --git a/src/nfc/ApiChangesQt6.txt b/src/nfc/ApiChangesQt6.txt
new file mode 100644
index 00000000..10a50014
--- /dev/null
+++ b/src/nfc/ApiChangesQt6.txt
@@ -0,0 +1,18 @@
+This document lists the API changed done to QtNFC between Qt 5.15 and Qt 6.
+
+- Removed function QNearFieldTarget::url(). No replacement available as the function was never implemented.
+- Removed function QNearFieldTarget::sendCommands(...). No replacement available as the function needs to be implemented by the API user.
+- Renamed function QNearFieldManager::isAvailable() to QNearFieldManager::isEnabled().
+- Removed functions QNearFieldTarget::keepConnection() and QNearFieldTarget::setKeepConnection(...). Keeping the connection is the default behavior now.
+- Removed QML API. No replacement available because the support has been discontinued.
+- Removed functions QNearFieldTarget::(un)registerNdefMessageHandler(...). No replacement available.
+- Removed QNearFieldShareManager/QNearFieldShareTarget. No replacement available.
+- Removed function QNearFieldTarget::isProcessingCommand(). No replacement available as the function is not implemented.
+- Removed functions setResponseForRequest, handleResponse and reportError from QNearFieldTarget. No replacement available as this is for internal use only.
+- Added NfcTagType4A and NfcTagType4B to QNearFieldTarget::Type.
+- Changed the type of typeInfo in QNdefNfcSmartPosterRecord from QByteArray to QString.
+- Removed TargetAccessModes, setTargetAccessModes and targetAccessModes from QNearFieldManager. No replacement available.
+- Removed ndefMessagesWritten signal. A requestCompleted signal is used instead.
+- Added QNdefRecord::clear() method.
+- QNdefFilter::appendRecord now returns bool to indicate if the record is added or not.
+- Added QNdefFilter::match() to check if a message matches the filter.
diff --git a/src/nfc/CMakeLists.txt b/src/nfc/CMakeLists.txt
new file mode 100644
index 00000000..de2b927f
--- /dev/null
+++ b/src/nfc/CMakeLists.txt
@@ -0,0 +1,125 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## Nfc Module:
+#####################################################################
+
+qt_internal_add_module(Nfc
+ SOURCES
+ qndeffilter.cpp qndeffilter.h
+ qndefmessage.cpp qndefmessage.h
+ qndefnfcsmartposterrecord.cpp qndefnfcsmartposterrecord.h qndefnfcsmartposterrecord_p.h
+ qndefnfctextrecord.cpp qndefnfctextrecord.h
+ qndefnfcurirecord.cpp qndefnfcurirecord.h
+ qndefrecord.cpp qndefrecord.h qndefrecord_p.h
+ qnearfieldmanager.cpp qnearfieldmanager.h qnearfieldmanager_p.h
+ qnearfieldtarget.cpp qnearfieldtarget.h qnearfieldtarget_p.cpp qnearfieldtarget_p.h
+ qtnfcglobal.h qtnfcglobal_p.h
+ DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
+ PUBLIC_LIBRARIES
+ Qt::Core
+ GENERATE_CPP_EXPORTS
+)
+
+## Scopes:
+#####################################################################
+
+if(ANDROID AND (ANDROID AND NOT ANDROID_EMBEDDED))
+ set_property(TARGET Nfc APPEND PROPERTY QT_ANDROID_BUNDLED_JAR_DEPENDENCIES
+ jar/Qt${QtConnectivity_VERSION_MAJOR}AndroidNfc.jar:org.qtproject.qt.android.nfc.QtNfc
+ )
+ set_property(TARGET Nfc APPEND PROPERTY QT_ANDROID_PERMISSIONS
+ android.permission.NFC
+ )
+ set(NFC_BACKEND_AVAILABLE ON)
+endif()
+
+qt_internal_extend_target(Nfc CONDITION ANDROID AND NOT ANDROID_EMBEDDED
+ SOURCES
+ android/androidjninfc.cpp android/androidjninfc_p.h
+ android/androidmainnewintentlistener.cpp android/androidmainnewintentlistener_p.h
+ qnearfieldmanager_android.cpp qnearfieldmanager_android_p.h
+ qnearfieldtarget_android.cpp qnearfieldtarget_android_p.h
+ DEFINES
+ ANDROID_NFC
+ QT_ANDROID_NFC
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+)
+
+if(IOS)
+ # special case begin
+ set(NFC_BACKEND_AVAILABLE ON)
+ qt_disable_apple_app_extension_api_only(Nfc)
+ qt_internal_find_apple_system_framework(FWCoreNFC CoreNFC)
+ # special case end
+endif()
+
+qt_internal_extend_target(Nfc CONDITION IOS
+ SOURCES
+ ios/qiostagreaderdelegate.mm ios/qiostagreaderdelegate_p.h
+ ios/qiosnfcndefsessiondelegate.mm ios/qiosnfcndefsessiondelegate_p.h
+ ios/qiosndefnotifier.cpp ios/qiosndefnotifier_p.h
+ qnearfieldmanager_ios.mm qnearfieldmanager_ios_p.h
+ qnearfieldtarget_ios.mm qnearfieldtarget_ios_p.h
+ DEFINES
+ IOS_NFC
+ LIBRARIES
+ ${FWCoreNFC}
+ Qt::CorePrivate
+)
+
+if(QT_FEATURE_pcsclite)
+ set(NFC_BACKEND_AVAILABLE ON)
+endif()
+
+qt_internal_extend_target(Nfc CONDITION QT_FEATURE_pcsclite
+ SOURCES
+ qnearfieldmanager_pcsc.cpp qnearfieldmanager_pcsc_p.h
+ qnearfieldtarget_pcsc.cpp qnearfieldtarget_pcsc_p.h
+ qapduutils.cpp qapduutils_p.h
+ pcsc/qpcsc.cpp pcsc/qpcsc_p.h
+ pcsc/qpcscmanager.cpp pcsc/qpcscmanager_p.h
+ pcsc/qpcscslot.cpp pcsc/qpcscslot_p.h
+ pcsc/qpcsccard.cpp pcsc/qpcsccard_p.h
+ ndef/qndefaccessfsm_p.h
+ ndef/qnfctagtype4ndeffsm.cpp ndef/qnfctagtype4ndeffsm_p.h
+ DEFINES
+ PCSC_NFC
+ LIBRARIES
+ PkgConfig::PCSCLITE
+)
+
+if(QT_FEATURE_neard)
+ set(NFC_BACKEND_AVAILABLE ON)
+endif()
+
+qt_internal_extend_target(Nfc CONDITION QT_FEATURE_neard
+ SOURCES
+ qnearfieldmanager_neard.cpp qnearfieldmanager_neard_p.h
+ qnearfieldtarget_neard_p.cpp qnearfieldtarget_neard_p.h
+ neard/neard_helper.cpp neard/neard_helper_p.h
+ neard/neard_dbus_types_p.h
+ DBUS_INTERFACE_SOURCES
+ neard/org.freedesktop.dbus.objectmanager.xml
+ neard/org.freedesktop.dbus.properties.xml
+ neard/org.neard.Adapter.xml
+ neard/org.neard.Tag.xml
+ DBUS_INTERFACE_FLAGS
+ -i neard/neard_dbus_types_p.h
+ DEFINES
+ NEARD_NFC
+ LIBRARIES
+ Qt::DBus
+)
+
+qt_internal_extend_target(Nfc CONDITION NOT NFC_BACKEND_AVAILABLE
+ SOURCES
+ qnearfieldmanager_generic.cpp qnearfieldmanager_generic_p.h
+)
+qt_internal_add_docs(Nfc
+ doc/qtnfc.qdocconf
+)
diff --git a/src/nfc/android/androidjninfc.cpp b/src/nfc/android/androidjninfc.cpp
index 9a1c5227..3f226985 100644
--- a/src/nfc/android/androidjninfc.cpp
+++ b/src/nfc/android/androidjninfc.cpp
@@ -1,102 +1,52 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Centria research and development
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 Centria research and development
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "androidjninfc_p.h"
-#include <android/log.h>
+QT_BEGIN_NAMESPACE
-#include "androidmainnewintentlistener_p.h"
-
-#include "qglobal.h"
-#include "qbytearray.h"
-#include "qdebug.h"
-
-static const char *nfcClassName = "org/qtproject/qt5/android/nfc/QtNfc";
-
-static AndroidNfc::MainNfcNewIntentListener mainListener;
-
-QT_BEGIN_ANDROIDNFC_NAMESPACE
+namespace QtNfc {
bool startDiscovery()
{
- return QAndroidJniObject::callStaticMethod<jboolean>(nfcClassName,"start");
+ return QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::QtNfc>::className(), "startDiscovery");
}
-bool isAvailable()
+bool isEnabled()
{
- return QAndroidJniObject::callStaticMethod<jboolean>(nfcClassName,"isAvailable");
+ return QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::QtNfc>::className(), "isEnabled");
}
bool isSupported()
{
- return QAndroidJniObject::callStaticMethod<jboolean>(nfcClassName,"isSupported");
+ return QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::QtNfc>::className(), "isSupported");
}
bool stopDiscovery()
{
- return QAndroidJniObject::callStaticMethod<jboolean>(nfcClassName,"stop");
+ return QJniObject::callStaticMethod<jboolean>(
+ QtJniTypes::Traits<QtJniTypes::QtNfc>::className(), "stopDiscovery");
}
-QAndroidJniObject getStartIntent()
+QJniObject getStartIntent()
{
- QAndroidJniObject ret = QAndroidJniObject::callStaticObjectMethod(nfcClassName, "getStartIntent", "()Landroid/content/Intent;");
- return ret;
+ return QJniObject::callStaticMethod<QtJniTypes::Intent>(
+ QtJniTypes::Traits<QtJniTypes::QtNfc>::className(), "getStartIntent");
}
-bool registerListener(AndroidNfcListenerInterface *listener)
+QJniObject getTag(const QJniObject &intent)
{
- return mainListener.registerListener(listener);
+ return QJniObject::callStaticMethod<QtJniTypes::Parcellable>(
+ QtJniTypes::Traits<QtJniTypes::QtNfc>::className(), "getTag",
+ intent.object<QtJniTypes::Intent>());
}
-bool unregisterListener(AndroidNfcListenerInterface *listener)
-{
- return mainListener.unregisterListener(listener);
-}
-
-QAndroidJniObject getTag(const QAndroidJniObject &intent)
-{
- QAndroidJniObject extraTag = QAndroidJniObject::getStaticObjectField("android/nfc/NfcAdapter", "EXTRA_TAG", "Ljava/lang/String;");
- QAndroidJniObject tag = intent.callObjectMethod("getParcelableExtra", "(Ljava/lang/String;)Landroid/os/Parcelable;", extraTag.object<jstring>());
- return tag;
-}
+} // namespace QtNfc
-QT_END_ANDROIDNFC_NAMESPACE
+QT_END_NAMESPACE
Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
{
diff --git a/src/nfc/android/androidjninfc_p.h b/src/nfc/android/androidjninfc_p.h
index 60e9a107..476e0519 100644
--- a/src/nfc/android/androidjninfc_p.h
+++ b/src/nfc/android/androidjninfc_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Centria research and development
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 Centria research and development
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROIDJNINFC_H
#define ANDROIDJNINFC_H
@@ -52,30 +16,29 @@
#include "qglobal.h"
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniObject>
+#include <QtCore/qjnitypes.h>
-#define QT_USE_ANDROIDNFC_NAMESPACE using namespace ::AndroidNfc;
-#define QT_BEGIN_ANDROIDNFC_NAMESPACE namespace AndroidNfc {
-#define QT_END_ANDROIDNFC_NAMESPACE }
+QT_BEGIN_NAMESPACE
-QT_BEGIN_ANDROIDNFC_NAMESPACE
+Q_DECLARE_JNI_CLASS(QtNfc, "org/qtproject/qt/android/nfc/QtNfc")
+Q_DECLARE_JNI_CLASS(QtNfcBroadcastReceiver, "org/qtproject/qt/android/nfc/QtNfcBroadcastReceiver")
-class AndroidNfcListenerInterface
-{
-public:
- virtual ~AndroidNfcListenerInterface(){}
- virtual void newIntent(QAndroidJniObject intent) = 0;
-};
+Q_DECLARE_JNI_TYPE(StringArray, "[Ljava/lang/String;")
+Q_DECLARE_JNI_CLASS(Intent, "android/content/Intent")
+Q_DECLARE_JNI_CLASS(Parcellable, "android/os/Parcelable")
+Q_DECLARE_JNI_CLASS(NdefMessage, "android/nfc/NdefMessage")
+
+namespace QtNfc {
bool startDiscovery();
bool stopDiscovery();
-QAndroidJniObject getStartIntent();
-bool isAvailable();
+QJniObject getStartIntent();
+bool isEnabled();
bool isSupported();
-bool registerListener(AndroidNfcListenerInterface *listener);
-bool unregisterListener(AndroidNfcListenerInterface *listener);
-QAndroidJniObject getTag(const QAndroidJniObject &intent);
+QJniObject getTag(const QJniObject &intent);
+} // namespace QtNfc
-QT_END_ANDROIDNFC_NAMESPACE
+QT_END_NAMESPACE
#endif
diff --git a/src/nfc/android/androidmainnewintentlistener.cpp b/src/nfc/android/androidmainnewintentlistener.cpp
index 2076453d..cebf92da 100644
--- a/src/nfc/android/androidmainnewintentlistener.cpp
+++ b/src/nfc/android/androidmainnewintentlistener.cpp
@@ -1,78 +1,45 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 BasysKom GmbH
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 BasysKom GmbH
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "androidmainnewintentlistener_p.h"
-#include "qdebug.h"
+#include "android/androidjninfc_p.h"
#include <QtGui/QGuiApplication>
-#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtCore/QJniObject>
-QT_BEGIN_ANDROIDNFC_NAMESPACE
+QT_BEGIN_NAMESPACE
-MainNfcNewIntentListener::MainNfcNewIntentListener()
- : listeners(), listenersLock(), paused(true), receiving(false)
+QMainNfcNewIntentListener::QMainNfcNewIntentListener() : paused(true), receiving(false)
{
QtAndroidPrivate::registerNewIntentListener(this);
QtAndroidPrivate::registerResumePauseListener(this);
}
-MainNfcNewIntentListener::~MainNfcNewIntentListener()
+QMainNfcNewIntentListener::~QMainNfcNewIntentListener()
{
QtAndroidPrivate::unregisterNewIntentListener(this);
QtAndroidPrivate::unregisterResumePauseListener(this);
}
-bool MainNfcNewIntentListener::handleNewIntent(JNIEnv */*env*/, jobject intent)
+bool QMainNfcNewIntentListener::handleNewIntent(JNIEnv * /*env*/, jobject intent)
{
+ // Only intents with a tag are relevant
+ if (!QtNfc::getTag(intent).isValid())
+ return false;
+
listenersLock.lockForRead();
- for (AndroidNfc::AndroidNfcListenerInterface *listener : qAsConst(listeners)) {
- listener->newIntent(QAndroidJniObject(intent));
+ for (auto listener : std::as_const(listeners)) {
+ listener->newIntent(QJniObject(intent));
}
listenersLock.unlock();
return true;
}
-bool MainNfcNewIntentListener::registerListener(AndroidNfcListenerInterface *listener)
+bool QMainNfcNewIntentListener::registerListener(QAndroidNfcListenerInterface *listener)
{
static bool firstListener = true;
if (firstListener) {
- QAndroidJniObject intent = AndroidNfc::getStartIntent();
+ QJniObject intent = QtNfc::getStartIntent();
if (intent.isValid()) {
listener->newIntent(intent);
}
@@ -87,7 +54,7 @@ bool MainNfcNewIntentListener::registerListener(AndroidNfcListenerInterface *lis
return true;
}
-bool MainNfcNewIntentListener::unregisterListener(AndroidNfcListenerInterface *listener)
+bool QMainNfcNewIntentListener::unregisterListener(QAndroidNfcListenerInterface *listener)
{
listenersLock.lockForWrite();
listeners.removeOne(listener);
@@ -96,24 +63,24 @@ bool MainNfcNewIntentListener::unregisterListener(AndroidNfcListenerInterface *l
return true;
}
-void MainNfcNewIntentListener::handleResume()
+void QMainNfcNewIntentListener::handleResume()
{
paused = false;
updateReceiveState();
}
-void MainNfcNewIntentListener::handlePause()
+void QMainNfcNewIntentListener::handlePause()
{
paused = true;
updateReceiveState();
}
-void MainNfcNewIntentListener::updateReceiveState()
+void QMainNfcNewIntentListener::updateReceiveState()
{
if (paused) {
// We were paused while receiving, so we stop receiving.
if (receiving) {
- AndroidNfc::stopDiscovery();
+ QtNfc::stopDiscovery();
receiving = false;
}
return;
@@ -122,15 +89,15 @@ void MainNfcNewIntentListener::updateReceiveState()
// We reach here, so we are not paused.
listenersLock.lockForRead();
// We have nfc listeners and do not receive. Switch on.
- if (listeners.count() && !receiving)
- receiving = AndroidNfc::startDiscovery();
+ if (!listeners.isEmpty() && !receiving)
+ receiving = QtNfc::startDiscovery();
// we have no nfc listeners and do receive. Switch off.
- if (!listeners.count() && receiving) {
- AndroidNfc::stopDiscovery();
+ if (listeners.isEmpty() && receiving) {
+ QtNfc::stopDiscovery();
receiving = false;
}
listenersLock.unlock();
}
-QT_END_ANDROIDNFC_NAMESPACE
+QT_END_NAMESPACE
diff --git a/src/nfc/android/androidmainnewintentlistener_p.h b/src/nfc/android/androidmainnewintentlistener_p.h
index acdd01ac..eb3c5217 100644
--- a/src/nfc/android/androidmainnewintentlistener_p.h
+++ b/src/nfc/android/androidmainnewintentlistener_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 BasysKom GmbH
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 BasysKom GmbH
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef ANDROIDMAINNEWINTENTLISTENER_P_H_
#define ANDROIDMAINNEWINTENTLISTENER_P_H_
@@ -55,21 +19,30 @@
#include "qlist.h"
#include "qreadwritelock.h"
-#include "androidjninfc_p.h"
-QT_BEGIN_ANDROIDNFC_NAMESPACE
+QT_BEGIN_NAMESPACE
-class MainNfcNewIntentListener : public QtAndroidPrivate::NewIntentListener, QtAndroidPrivate::ResumePauseListener
+class QJniObject;
+
+class QAndroidNfcListenerInterface
+{
+public:
+ virtual ~QAndroidNfcListenerInterface() = default;
+ virtual void newIntent(QJniObject intent) = 0;
+};
+
+class QMainNfcNewIntentListener : public QtAndroidPrivate::NewIntentListener,
+ QtAndroidPrivate::ResumePauseListener
{
public:
- MainNfcNewIntentListener();
- ~MainNfcNewIntentListener();
+ QMainNfcNewIntentListener();
+ ~QMainNfcNewIntentListener();
//QtAndroidPrivate::NewIntentListener
bool handleNewIntent(JNIEnv *env, jobject intent);
- bool registerListener(AndroidNfcListenerInterface *listener);
- bool unregisterListener(AndroidNfcListenerInterface *listener);
+ bool registerListener(QAndroidNfcListenerInterface *listener);
+ bool unregisterListener(QAndroidNfcListenerInterface *listener);
//QtAndroidPrivate::ResumePauseListener
void handleResume();
@@ -77,13 +50,13 @@ public:
private:
void updateReceiveState();
-protected:
- QList<AndroidNfc::AndroidNfcListenerInterface*> listeners;
+
+ QList<QAndroidNfcListenerInterface *> listeners;
QReadWriteLock listenersLock;
bool paused;
bool receiving;
};
-QT_END_ANDROIDNFC_NAMESPACE
+QT_END_NAMESPACE
#endif /* ANDROIDMAINNEWINTENTLISTENER_P_H_ */
diff --git a/src/nfc/configure.cmake b/src/nfc/configure.cmake
new file mode 100644
index 00000000..08448333
--- /dev/null
+++ b/src/nfc/configure.cmake
@@ -0,0 +1,12 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_find_package(PCSCLITE PROVIDED_TARGETS PkgConfig::PCSCLITE)
+
+qt_feature("pcsclite" PUBLIC
+ LABEL "Use the PCSCLite library to access NFC devices"
+ CONDITION PCSCLITE_FOUND)
+
+qt_feature("neard" PUBLIC
+ LABEL "Use neard to access NFC devices"
+ CONDITION LINUX AND NOT QT_FEATURE_pcsclite)
diff --git a/src/nfc/doc/qtnfc.qdocconf b/src/nfc/doc/qtnfc.qdocconf
index e4f10f0e..10aede7f 100644
--- a/src/nfc/doc/qtnfc.qdocconf
+++ b/src/nfc/doc/qtnfc.qdocconf
@@ -15,18 +15,11 @@ qhp.QtNfc.virtualFolder = qtnfc
qhp.QtNfc.indexTitle = Qt NFC
qhp.QtNfc.indexRoot =
-qhp.QtNfc.filterAttributes = qtnfc $QT_VERSION qtrefdoc
-qhp.QtNfc.customFilters.Qt.name = QtNfc $QT_VERSION
-qhp.QtNfc.customFilters.Qt.filterAttributes = qtnfc $QT_VERSION
-qhp.QtNfc.subprojects = overviews classes qml examples
+qhp.QtNfc.subprojects = overviews classes examples
qhp.QtNfc.subprojects.classes.title = C++ Classes
qhp.QtNfc.subprojects.classes.indexTitle = Qt NFC C++ Classes
qhp.QtNfc.subprojects.classes.selectors = class fake:headerfile
qhp.QtNfc.subprojects.classes.sortPages = true
-qhp.QtNfc.subprojects.qml.title = QML Types
-qhp.QtNfc.subprojects.qml.indexTitle = Qt NFC QML Types
-qhp.QtNfc.subprojects.qml.selectors = fake:headerfile
-qhp.QtNfc.subprojects.qml.sortPages = true
qhp.QtNfc.subprojects.overviews.title = Overviews
qhp.QtNfc.subprojects.overviews.indexTitle = Qt NFC Overview
qhp.QtNfc.subprojects.overviews.selectors = fake:page,group,module
@@ -36,20 +29,22 @@ qhp.QtNfc.subprojects.examples.selectors = fake:example
tagfile = ../../../doc/qtnfc/qtnfc.tags
-depends += qtcore qtdoc
+depends += qtcore qtwidgets qtdoc qmake qtcmake
-headerdirs += .. \
- ../../imports/nfc
+headerdirs += ..
-sourcedirs += .. \
- ../../imports/nfc \
+sourcedirs += ..
exampledirs += ../../../examples/nfc \
snippets/
-
imagedirs += images
+manifestmeta.highlighted.names = \
+ "QtNfc/Annotated URL"
+
navigation.landingpage = "Qt NFC"
navigation.cppclassespage = "Qt NFC C++ Classes"
-navigation.qmltypespage = "Qt NFC QML Types"
+
+# Enforce zero documentation warnings
+warninglimit = 0
diff --git a/src/nfc/doc/snippets/doc_src_qtnfc.cpp b/src/nfc/doc/snippets/doc_src_qtnfc.cpp
deleted file mode 100644
index 760d65fd..00000000
--- a/src/nfc/doc/snippets/doc_src_qtnfc.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
-** 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$
-**
-****************************************************************************/
-
-#include <QtCore/QObject>
-//! [include]
-#include <QtNfc/QNearFieldManager>
-//! [include]
-#include <QtNfc/QNdefMessage>
-
-//! [namespace]
-QT_USE_NAMESPACE
-//! [namespace]
-
-class MyClass : public QObject
-{
- Q_OBJECT
-public:
- MyClass() : QObject()
- {
-//formatting adjusted to improve usage in docs
-//! [handleNdefMessage]
-QNearFieldManager *manager = new QNearFieldManager(this);
-manager->registerNdefMessageHandler(this,
- SLOT(handleNdefMessage(QNdefMessage,QNearFieldTarget*)));
-//! [handleNdefMessage]
- }
-
-public Q_SLOTS:
- void handleNdefMessage(QNdefMessage,QNearFieldTarget*)
- {
- }
-};
-
-#include "doc_src_qtnfc.moc"
-
diff --git a/src/nfc/doc/snippets/doc_src_qtnfc.qml b/src/nfc/doc/snippets/doc_src_qtnfc.qml
deleted file mode 100644
index e7a45e89..00000000
--- a/src/nfc/doc/snippets/doc_src_qtnfc.qml
+++ /dev/null
@@ -1,65 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
-** 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 QtNfc 5.12
-//! [import]
-
-Item {
-//! [QML register for messages]
- NearField {
- filter: [ NdefFilter { type: "U"; typeNameFormat: NdefRecord.NfcRtd; minimum: 1; maximum: 1 } ]
- orderMatch: false
-
- onMessageRecordsChanged: displayMessage()
- }
-//! [QML register for messages]
-}
diff --git a/src/nfc/doc/snippets/foorecord.cpp b/src/nfc/doc/snippets/foorecord.cpp
deleted file mode 100644
index 4fecd712..00000000
--- a/src/nfc/doc/snippets/foorecord.cpp
+++ /dev/null
@@ -1,124 +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$
-**
-****************************************************************************/
-
-#include "foorecord.h"
-#include <qndefrecord.h>
-
-//! [Declare foo record]
-Q_DECLARE_NDEFRECORD(QQmlNdefFooRecord, QNdefRecord::ExternalRtd, "com.example:f")
-//! [Declare foo record]
-
-//! [createFooRecord]
-static inline QNdefRecord createFooRecord()
-{
- QNdefRecord foo;
- foo.setTypeNameFormat(QNdefRecord::ExternalRtd);
- foo.setType("com.example:f");
- foo.setPayload(QByteArray(sizeof(int), char(0)));
- return foo;
-}
-//! [createFooRecord]
-
-//! [copyFooRecord]
-static inline QNdefRecord copyFooRecord(const QNdefRecord &record)
-{
- if (record.typeNameFormat() != QNdefRecord::ExternalRtd)
- return createFooRecord();
- if (record.type() != "com.example:f")
- return createFooRecord();
-
- return record;
-}
-//! [copyFooRecord]
-
-//! [Constructors]
-QQmlNdefFooRecord::QQmlNdefFooRecord(QObject *parent)
-: QQmlNdefRecord(createFooRecord(), parent)
-{
-}
-
-QQmlNdefFooRecord::QQmlNdefFooRecord(const QNdefRecord &record, QObject *parent)
-: QQmlNdefRecord(copyFooRecord(record), parent)
-{
-}
-//! [Constructors]
-
-QQmlNdefFooRecord::~QQmlNdefFooRecord()
-{
-}
-
-int QQmlNdefFooRecord::foo() const
-{
- QByteArray payload = record().payload();
-
- int value = payload.at(0) << 24 |
- payload.at(1) << 16 |
- payload.at(2) << 8 |
- payload.at(3) << 0;
-
- return value;
-}
-
-void QQmlNdefFooRecord::setFoo(int value)
-{
- if (foo() == value)
- return;
-
- QByteArray payload;
- payload[0] = (value >> 24) & 0xff;
- payload[1] = (value >> 16) & 0xff;
- payload[2] = (value >> 8) & 0xff;
- payload[3] = (value >> 0) & 0xff;
-
- QNdefRecord r = record();
- r.setPayload(payload);
- setRecord(r);
- emit fooChanged();
-}
diff --git a/src/nfc/doc/snippets/foorecord.h b/src/nfc/doc/snippets/foorecord.h
deleted file mode 100644
index c2501287..00000000
--- a/src/nfc/doc/snippets/foorecord.h
+++ /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$
-**
-****************************************************************************/
-
-#ifndef FOORECORD_H
-#define FOORECORD_H
-
-#include <qqmlndefrecord.h>
-
-QT_USE_NAMESPACE
-
-//! [Foo declaration]
-class QQmlNdefFooRecord : public QQmlNdefRecord
-{
- Q_OBJECT
-
- Q_PROPERTY(int foo READ foo WRITE setFoo NOTIFY fooChanged)
-
-public:
- explicit QQmlNdefFooRecord(QObject *parent = 0);
- Q_INVOKABLE QQmlNdefFooRecord(const QNdefRecord &record, QObject *parent = 0);
- ~QQmlNdefFooRecord();
-
- int foo() const;
- void setFoo(int value);
-
-signals:
- void fooChanged();
-};
-//! [Foo declaration]
-
-#endif // FOORECORD_H
diff --git a/src/nfc/doc/snippets/main.cpp b/src/nfc/doc/snippets/main.cpp
index 6f2bb0d7..fb6724d5 100644
--- a/src/nfc/doc/snippets/main.cpp
+++ b/src/nfc/doc/snippets/main.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
int main(int /*argc*/, char ** /*argv*/)
{
diff --git a/src/nfc/doc/snippets/nfc.cpp b/src/nfc/doc/snippets/nfc.cpp
index 82297682..a1192bec 100644
--- a/src/nfc/doc/snippets/nfc.cpp
+++ b/src/nfc/doc/snippets/nfc.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 <QtNfc/qndefrecord.h>
#include <QtNfc/qndefnfctextrecord.h>
diff --git a/src/nfc/doc/snippets/snippets.pro b/src/nfc/doc/snippets/snippets.pro
deleted file mode 100644
index 437782e4..00000000
--- a/src/nfc/doc/snippets/snippets.pro
+++ /dev/null
@@ -1,13 +0,0 @@
-TEMPLATE = app
-TARGET = nfc_cppsnippet
-QT = core
-#! [project modification]
-QT += nfc
-#! [project modification]
-
-SOURCES += main.cpp \
- doc_src_qtnfc.cpp \
- nfc.cpp \
- foorecord.cpp
-
-HEADERS += foorecord.h
diff --git a/src/nfc/doc/src/examples.qdoc b/src/nfc/doc/src/examples.qdoc
index 1eb410e3..a126763e 100644
--- a/src/nfc/doc/src/examples.qdoc
+++ b/src/nfc/doc/src/examples.qdoc
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
-** 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) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
-\ingroup all-examples
\page nfc-examples.html
\title Qt NFC Examples
\brief Examples for the Qt NFC module.
@@ -46,18 +21,5 @@ in their own documentation, but they are also accessible from here.
\li \l{ndefeditor}{NDEF Editor}
\li Create new or modify existing NDEF messages on NFC Forum Tags.
\endtable
-
-\section2 QML Examples
-\table 80%
- \header
- \li Example
- \li Description
- \row
- \li \l{corkboard} {CorkBoard}
- \li Displays NDEF text tags on a corkboard.
- \row
- \li \l{poster}{QML Poster}
- \li Displays URLs stored on NFC Forum Tags.
-\endtable
*/
diff --git a/src/nfc/doc/src/nfc-android.qdoc b/src/nfc/doc/src/nfc-android.qdoc
index d28f78ee..e2ca5401 100644
--- a/src/nfc/doc/src/nfc-android.qdoc
+++ b/src/nfc/doc/src/nfc-android.qdoc
@@ -1,29 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 BasysKom GmbH
-** 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) 2015 BasysKom GmbH
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\ingroup connectivity-nfc
@@ -33,13 +10,18 @@
\title Qt NFC on Android
\brief Notes on Nfc for Android.
-\section1 Automatically launching NDEF message handlers on Android
-Android, the registration of NDEF message handlers is done via the
-\l{http://developer.android.com/guide/topics/manifest/manifest-intro.html}{Android manifest file}.
-This means the application has to provide an AndroidManifest.xml file with proper
-\l{http://developer.android.com/guide/topics/connectivity/nfc/nfc.html#manifest}{NFC intent-filter.}
+\section1 Automatically Launching NDEF Message Handlers on Android
-\code
+Android provides the possibility to automatically launch the application when
+touching the NDEF tag.
+
+This can be achieved by providing an
+\l {https://developer.android.com/guide/topics/manifest/manifest-intro.html}
+{Android manifest file} (AndroidManifest.xml) with proper
+\l{https://developer.android.com/guide/topics/connectivity/nfc/nfc.html#manifest}
+{NFC intent-filter}.
+
+\badcode
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
@@ -47,23 +29,36 @@ This means the application has to provide an AndroidManifest.xml file with prope
</intent-filter>
\endcode
-When the application is started it has to register an message handler with
-\l {QNearFieldManager::}{registerNdefMessageHandler()}
-The first NDEF message arriving in the handler is the message that started the application.
-See the \l {corkboard}{CorkBoard} application for an example.
+With this intent-filter enabled, the application will be automatically started
+once the NDEF NFC tag is touched.
+
+\note It's important to design your application in such a way that all the GUI
+is connected to the NFC classes before the target detection is actually started.
+Otherwise it will be impossible to show the information from the tag that caused
+application startup.
+
+\note It's important to touch the tag long enough for the application to start
+and read the information. If the tag is lost during application startup, no data
+will be available, and the tag needs to be touched again.
+
+See \l {annotatedurl}{Annotated URL} application as an example.
+
+\section2 Supported Tag Types
-\section2 Note:
Supported tag types in Android are
-\l{http://developer.android.com/reference/android/nfc/NfcAdapter.html#ACTION_NDEF_DISCOVERED}{NDEF_DISCOVERED}
-and
-\l{http://developer.android.com/reference/android/nfc/NfcAdapter.html#ACTION_TECH_DISCOVERED}{ACTION_TAG_DISCOVERED}
-with
-\l{http://developer.android.com/reference/android/nfc/tech/TagTechnology.html}{TagTechnology}
-NdefFormatable or Ndef.
-If the application register other types in the
-\l{http://developer.android.com/guide/topics/manifest/manifest-intro.html}{Android manifest file}
-the application will be started, but the tag will never get delivered to the handler.
-The handler should be registered as early as possible. If the application has not registered a handler, the application
-will be started every time a new tag is in range and the Android device end up running multiple instances of the application.
+\l {https://developer.android.com/reference/android/nfc/NfcAdapter.html#ACTION_NDEF_DISCOVERED}
+{ACTION_NDEF_DISCOVERED},
+\l {https://developer.android.com/reference/android/nfc/NfcAdapter.html#ACTION_TAG_DISCOVERED}
+{ACTION_TAG_DISCOVERED} and
+\l {https://developer.android.com/reference/android/nfc/NfcAdapter.html#ACTION_TECH_DISCOVERED}
+{ACTION_TECH_DISCOVERED} with
+\l {https://developer.android.com/reference/android/nfc/tech/TagTechnology.html}
+{TagTechnology} \e NdefFormatable or \e Ndef.
+
+If the application registers other types in the
+\l {https://developer.android.com/guide/topics/manifest/manifest-intro.html}
+{Android manifest file}, the application will be started, but the tag will never
+be processed.
+
*/
diff --git a/src/nfc/doc/src/nfc-cpp.qdoc b/src/nfc/doc/src/nfc-cpp.qdoc
index 00fb8aa5..0fef1d6b 100644
--- a/src/nfc/doc/src/nfc-cpp.qdoc
+++ b/src/nfc/doc/src/nfc-cpp.qdoc
@@ -1,33 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
-** 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) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\module QtNfc
\ingroup modules
+\qtcmakepackage Nfc
\qtvariable nfc
\title Qt NFC C++ Classes
@@ -35,9 +13,18 @@
The \l{Qt NFC} C++ API enables an application to access NFC Forum Tags.
-To use the C++ library in your application, add the following configuration
-option to your \c .pro file:
+\include module-use.qdocinc using qt module
+
+\badcode
+find_package(Qt6 REQUIRED COMPONENTS Nfc)
+target_link_libraries(mytarget PRIVATE Qt::Nfc)
+\endcode
+
+\include module-use.qdocinc building with qmake
+
+\badcode
+QT += nfc
+\endcode
-\snippet snippets.pro project modification
*/
diff --git a/src/nfc/doc/src/nfc-features.qdoc b/src/nfc/doc/src/nfc-features.qdoc
new file mode 100644
index 00000000..65c31f04
--- /dev/null
+++ b/src/nfc/doc/src/nfc-features.qdoc
@@ -0,0 +1,64 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtnfc-features.html
+\title Supported NFC Features
+\ingroup connectivity-nfc
+\inmodule QtNfc
+\brief Summary of supported NFC features on different platforms.
+
+Qt NFC provides two options for reading and writing the data. These options are
+reflected in the \l {QNearFieldTarget::}{AccessMethod} enum.
+
+\list
+ \li \l {QNearFieldTarget::}{NdefAccess} - using NDEF messages via
+ \l {QNearFieldTarget::}{readNdefMessages()} and
+ \l {QNearFieldTarget::}{writeNdefMessages()}.
+ \li \l {QNearFieldTarget::}{TagTypeSpecificAccess} - sending custom commands
+ using \l {QNearFieldTarget::}{sendCommand()} and getting the results via
+ \l {QNearFieldTarget::}{requestResponse()}.
+\endlist
+
+\l {QNearFieldTarget::}{TagTypeSpecificAccess} implies that the
+user might need to send different data based on the NFC Tag Type. Tag types
+recognized by Qt NFC are defined in the \l {QNearFieldTarget::}{Type} enum.
+
+Qt NFC support for different access methods and tag types varies depending on
+the platform. The table below shows currently supported subsets of features
+for every platform.
+
+\table
+ \header
+ \li Platform
+ \li Recognized Tag Types
+ \li NDEF Support
+ \li Tag Specific Access
+ \row
+ \li \l {Qt NFC on Android}{Android}
+ \li All from the \l {QNearFieldTarget::}{Type} enum
+ \li Yes
+ \li Yes
+ \row
+ \li iOS
+ \li \list
+ \li \l {QNearFieldTarget::}{NfcTagType4}
+ \li \l {QNearFieldTarget::}{NfcTagType4A}
+ \li \l {QNearFieldTarget::}{NfcTagType4B}
+ \li \l {QNearFieldTarget::}{ProprietaryTag}
+ \endlist
+ \li No
+ \li Yes - for supported tag types
+ \row
+ \li Linux, Windows, macOS
+
+ (implemented using \l {PC/SC in Qt NFC}{PC/SC})
+ \li \list
+ \li \l {QNearFieldTarget::}{NfcTagType4}
+ \li \l {QNearFieldTarget::}{ProprietaryTag}
+ \endlist
+ \li Yes - for \l {QNearFieldTarget::}{NfcTagType4}
+ \li Yes - for \l {QNearFieldTarget::}{ProprietaryTag}
+\endtable
+
+*/
diff --git a/src/nfc/doc/src/nfc-index.qdoc b/src/nfc/doc/src/nfc-index.qdoc
index 21f775a6..662fea09 100644
--- a/src/nfc/doc/src/nfc-index.qdoc
+++ b/src/nfc/doc/src/nfc-index.qdoc
@@ -1,30 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
-** 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) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtnfc-index.html
@@ -34,55 +10,42 @@
The NFC API provides connectivity between NFC enabled devices.
-Currently the API is supported on \l{Qt for Android}{Android},
-and \l{Qt for Linux/X11}{Linux} using \l {https://01.org/linux-nfc}{Neard} v0.14 or later.
+Currently, the API is supported on \l{Qt for Android}{Android}, \l{Qt for
+iOS}{iOS} and \l{Qt for Linux}{Linux} using
+\l {https://github.com/linux-nfc/neard}{Neard} v0.14 or later.
+This module also provides limited access to readers supporting
+\l{PC/SC in Qt NFC}{PC/SC} specification on Linux, macOS, and Windows.
-\section1 Overview
+NFC is a short-range (less than 20 centimeters) wireless technology
+with a maximum transfer rate of 424 Kbps. NFC is ideal for transferring
+small packets of data when two devices are placed together.
-NFC is an extremely short-range (less than 20 centimeters) wireless technology and has a
-maximum transfer rate of 424 kbit/s. NFC is ideal for transferring small packets of data when two
-devices are touched together.
+The NFC module provides APIs for interacting with NFC Forum Tags and NFC Forum
+Devices. It can detect targets and losses, register NDEF message handlers, read
+and write NDEF messages on NFC Forum Tags, and send tag-specific commands.
-The NFC API provides APIs for interacting with NFC Forum Tags and NFC Forum Devices, including
-target detection and loss, registering NDEF message handlers, reading and writing NDEF messages
-on NFC Forum Tags and sending tag specific commands.
+\section1 Using the Module
+\include {module-use.qdocinc} {using the c++ api} {NFC}
-\section1 Getting Started
+\section2 Building with CMake
-To use the C++ library in your application, add the following configuration
-option to your \c .pro file:
+\include {module-use.qdocinc} {building with cmake} {Nfc}
-\snippet snippets.pro project modification
+\section2 Building with qmake
-To use the classes of the module in your application you need the following
-import statement in your \c .qml file:
+\include {module-use.qdocinc} {building_with_qmake} {nfc}
-\snippet doc_src_qtnfc.qml import
+\section1 Articles and Guides
-\section1 Licenses
-
-Qt NFC is available under commercial licenses from \l{The Qt Company}.
-In addition, it is available under free software licenses. Since Qt 5.4,
-these free software licenses are
-\l{GNU Lesser General Public License, version 3}, or
-the \l{GNU General Public License, version 2}.
-See \l{Qt Licensing} for further details.
-
-\section1 Related Information
-
-\section2 Guides
\list
\li \l {Qt NFC Overview}
+ \li \l {Supported NFC Features}
+ \li \l {Qt NFC on Android}
+ \li \l {PC/SC in Qt NFC}
\endlist
-\section2 Reference
-\list
- \li \l {Qt NFC QML Types}{QML Types}
- \li \l {Qt NFC C++ Classes}{C++ Classes}
-\endlist
-
-\section2 Logging Categories
+\section1 Logging Categories
The \l QtNfc module exports the following
\l {Configuring Categories}{logging categories}:
@@ -96,17 +59,30 @@ The \l QtNfc module exports the following
\li Enables logging of the Neard/Linux implementation
\endtable
-\section2 Examples
+\section1 Examples
+
\list
- \li QML
- \list
- \li \l {corkboard}{CorkBoard}
- \li \l {poster}{QML Poster}
- \endlist
- \li C++
- \list
- \li \l {annotatedurl}{Annotated URL}
- \li \l {ndefeditor}{NDEF Editor}
- \endlist
+ \li \l {annotatedurl}{Annotated URL}
+ \li \l {ndefeditor}{NDEF Editor}
\endlist
+
+\section1 Reference
+
+\list
+ \li \l {Qt NFC C++ Classes}{C++ Classes}
+\endlist
+
+\section1 Module Evolution
+
+\l {Changes to Qt NFC} lists important changes in the module API and
+functionality that were done for the Qt 6 series of Qt.
+
+\section1 Licenses
+
+Qt NFC is available under commercial licenses from \l{The Qt Company}.
+In addition, it is available under free software licenses. Since Qt 5.4,
+these free software licenses are
+\l{GNU Lesser General Public License, version 3}, or
+the \l{GNU General Public License, version 2}.
+See \l{Qt Licensing} for further details.
*/
diff --git a/src/nfc/doc/src/nfc-overview.qdoc b/src/nfc/doc/src/nfc-overview.qdoc
index 6ac5c1dc..81e7212c 100644
--- a/src/nfc/doc/src/nfc-overview.qdoc
+++ b/src/nfc/doc/src/nfc-overview.qdoc
@@ -1,36 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
-** 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) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\ingroup technology-apis
\title Qt NFC Overview
\page qtnfc-overview.html
\brief Provides access to NFC enabled devices.
+\ingroup explanations-networkingandconnectivity
\tableofcontents
@@ -45,8 +22,19 @@ With the Qt NFC API typical use cases are:
The following sections describe how to use Qt NFC C++ classes and QML types for the above use cases.
-\note On Android, Qt Nfc only works in foreground applications. Android services are not supported which is due to
-API limitations on the Android side.
+\note On Android, the detection of new NFC tags only works in foreground applications. Android
+services do not support this because of API limitations on the Android side. The only way to use a
+\l{https://developer.android.com/reference/android/nfc/Tag}{Tag} in a service is to provide an
+\l{https://developer.android.com/guide/components/aidl}{AIDL} interface accepting the Tag and forward
+it to Qt as shown in the following example.
+
+\code
+ public void setTag(Tag pTag) {
+ Intent newIntent = new Intent();
+ newIntent.putExtra(NfcAdapter.EXTRA_TAG, pTag);
+ QtNative.onNewIntent(newIntent);
+ }
+\endcode
\section1 C++ Overview
@@ -62,29 +50,78 @@ a tag comes into or leaves the range. The passed \l QNearFieldTarget parameter a
as primary interaction point for each detected tag. The detection does not actually start though until
\l QNearFieldManager::startTargetDetection() has been called.
-\snippet ndefeditor/mainwindow.cpp QNearFieldManager init
-\snippet ndefeditor/mainwindow.cpp QNearFieldManager start detection
+\code
+m_manager = new QNearFieldManager(this);
+connect(m_manager, &QNearFieldManager::targetDetected,
+ this, &MainWindow::targetDetected);
+connect(m_manager, &QNearFieldManager::targetLost,
+ this, &MainWindow::targetLost);
+m_manager->startTargetDetection(QNearFieldTarget::NdefAccess);
+\endcode
Finally the detection can be stopped:
-\snippet ndefeditor/mainwindow.cpp QNearFieldManager stop detection
+\code
+m_manager->stopTargetDetection();
+\endcode
Although each \l QNearFieldTarget instance is owned by its related \l QNearFieldManager
instance it can be beneficial to manually delete each instance. Otherwise they would continue to
exist until the \l QNearFieldManager instance is deleted. The best way to do that would be in response
to the \l QNearFieldManager::targetLost() signal:
-\snippet ndefeditor/mainwindow.cpp QNearFieldTarget lost
+\code
+void MainWindow::targetLost(QNearFieldTarget *target)
+{
+ target->deleteLater();
+}
+\endcode
\note The target object should only be deleted via deleteLater() if it is deleted inside the slot.
+\section2 Connecting NFC Tags
+
+All functions of \l QNearFieldTarget that require a connection will create one by its own.
+An active connection will prevent other instances to create a connection because only one
+connection at the time is allowed.
+
+Qt 5 disconnected the tag at the end of the functions to allow other instances to connect.
+QNearFieldManager::setKeepConnection() allowed to change this behavior.
+
+Since Qt 6, \l QNearFieldTarget keeps the connection by default. The connection is only closed
+when the \l QNearFieldTarget is destroyed or \l QNearFieldManager::disconnect() is called.
+
\section2 Reading and Writing NDEF Messages
The \l QNearFieldTarget instance returned by \l QNearFieldManager::targetDetected() signal
is used to interact with the tag. Reading and writing a message is an asynchronous operation.
The \l QNearFieldTarget::RequestId class associates individual operations and their results.
-\snippet ndefeditor/mainwindow.cpp QNearFieldTarget detected
+\code
+void MainWindow::targetDetected(QNearFieldTarget *target)
+{
+ switch (m_touchAction) {
+ case NoAction:
+ break;
+ case ReadNdef:
+ connect(target, &QNearFieldTarget::ndefMessageRead, this, &MainWindow::ndefMessageRead);
+ connect(target, &QNearFieldTarget::error, this, &MainWindow::targetError);
+
+ m_request = target->readNdefMessages();
+ if (!m_request.isValid()) // cannot read messages
+ targetError(QNearFieldTarget::NdefReadError, m_request);
+ break;
+ case WriteNdef:
+ connect(target, &QNearFieldTarget::requestCompleted, this, &MainWindow::ndefMessageWritten);
+ connect(target, &QNearFieldTarget::error, this, &MainWindow::targetError);
+
+ m_request = target->writeNdefMessages(QList<QNdefMessage>() << ndefMessage());
+ if (!m_request.isValid()) // cannot write messages
+ targetError(QNearFieldTarget::NdefWriteError, m_request);
+ break;
+ }
+}
+\endcode
Once the \l QNearFieldTarget::readNdefMessages() request was successfully processed, the
\l QNearFieldTarget::ndefMessageRead() signal is emitted. Each returned \l QNdefMessage
@@ -92,62 +129,7 @@ may consist of zero or more \l QNdefRecord entries, which can be identified by t
For more information about processing of records, see the \l QNdefRecord class documentation.
As the above code demonstrates, writing of NDEF messages is triggered via
\l QNearFieldTarget::writeNdefMessages(). The successful completion of the write operation
-is indicated by the emission of the \l QNearFieldTarget::ndefMessagesWritten() signal. Any
-type of error during read or write is indicated via \l QNearFieldTarget::error().
-
-\section2 Registering NDEF Message Handlers
-
-The above described method (of reading NDEF messages) directly connects to the platform's NFC infrastructure.
-However on some platforms (in particular mobile platforms) this may not actually trigger the target slot
-if the application is currently running in the background. This is not desirable in cases where an
-application wants to be activated if the platform detects a tag of particular type.
-For this purpose the Qt NFC API provides the possibility to register an NDEF message handler. The handler
-is called by the operating system, when the detected NDEF message matches the given filter criteria.
-Depending on the platform it may even be possible to start the application that registered the handler.
-
-\note This feature is not available on all platforms and, in addition to the code snippets below,
-may require further platform specific setup.
-
-\snippet annotatedurl/annotatedurl.cpp QNearFieldManager register handler
-
-For comparison an application that uses an empty NDEF filter (match all behavior) in combination with
-\l QNearFieldManager::registerNdefMessageHandler() would behave similarly to another application that uses
-\l QNearFieldTarget::readNdefMessages() while being in the forground. For more information about
-registration details of NDEF message handlers, see the
-\l {QNearFieldManager#automatically-launching-ndef-message-handlers}{QNearFieldManager} class description.
-
-The content of \c handleMessage() may look like the snippet below. Any incoming NDEF message of type
-\c text or \c uri will be processed:
-
-\snippet annotatedurl/annotatedurl.cpp handleMessage 1
-\snippet annotatedurl/annotatedurl.cpp handleMessage 2
-\snippet annotatedurl/annotatedurl.cpp handleMessage 3
-\snippet annotatedurl/annotatedurl.cpp handleMessage 4
-
-\section2 Sharing Files and Messages
-
-Since Qt 5.3, Qt NFC provides a generic NFC share feature. If both devices support the same protocol,
-the feature can be used to share files or NDEF messages. The advantage is that the two involved partners
-can quickly establish a connection via NFC but transfer the data through, for example, Bluetooth or Wifi.
-Effectively, this combines the low configuration effort of NFC with high data rate communication bearers
-which usually require a much more complex setup.
-
-\note The API does not make any guarantees about the actual communication bearer used during the transfer.
-The bearer is chosen based on the device's capabilities and the properties of the to-be-shared data.
-
-\l QNearFieldShareManager and \l QNearFieldShareTarget are responsible for accessing the NFC share feature.
-
-\section1 QML Overview
-
-The QML API only supports a very small subset of the Qt NFC feature set. This section outlines the available QML features.
-
-\section2 Reading NDEF Messages
-
-The user can specify NDEF filters and use those filters to register for the automatic reception of NDEF
-messages which match those filters. The \l NearField::messageRecords property contains the list of NDEF records
-of the last NDEF message read matching the given filters.
-
-\snippet doc_src_qtnfc.qml QML register for messages
-
-If no filter is set, the message handler will match all incoming NDEF messages.
+is indicated by the emission of the \l QNearFieldTarget::requestCompleted() signal with the
+corresponding request id. Any type of error during read or write is indicated via
+\l QNearFieldTarget::error().
*/
diff --git a/src/nfc/doc/src/nfc-pcsc.qdoc b/src/nfc/doc/src/nfc-pcsc.qdoc
new file mode 100644
index 00000000..532f0311
--- /dev/null
+++ b/src/nfc/doc/src/nfc-pcsc.qdoc
@@ -0,0 +1,34 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtnfc-pcsc.html
+\title PC/SC in Qt NFC
+\ingroup connectivity-nfc
+\inmodule QtNfc
+\since 6.4
+\brief Notes on PC/SC support in Qt Nfc.
+
+PC/SC support is provided using native APIs on macOS and Windows, and using
+\l{https://pcsclite.apdu.fr/}{PCSCLite} library on other platforms. The API
+can be used for accessing both wired and wireless smartcards and storage cards.
+
+\section1 Limitations
+
+\list
+ \li The current API does not provide means to distinguish between separate
+ readers/slots.
+ \li NDEF access is only provided for NFC Type 4 tags.
+ \li Other applications starting transactions on cards may block Qt applications
+ from using Qt Nfc API.
+ \li QNearFieldTarget::sendCommand() used with a PC/SC target starts
+ a transaction that remains active until QNearFieldTarget::disconnect()
+ is called. This transaction prevents other applications from accessing
+ this target.
+ \li The backend is polling for new tags, that means that there
+ may be a delay up to the full polling interval before new tags are reported.
+ The default polling interval is 100 milliseconds. It can be adjusted
+ by setting environment valiable \c{QT_NFC_POLL_INTERVAL_MS} to an integer
+ value in milliseconds.
+\endlist
+*/
diff --git a/src/nfc/doc/src/nfc-qml.qdoc b/src/nfc/doc/src/nfc-qml.qdoc
deleted file mode 100644
index 48ae3bd2..00000000
--- a/src/nfc/doc/src/nfc-qml.qdoc
+++ /dev/null
@@ -1,43 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Aaron McCarthy <mccarthy.aaron@gmail.com>
-** 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$
-**
-****************************************************************************/
-
-
-/*!
-
-\qmlmodule QtNfc \QtVer
-\title Qt NFC QML Types
-\ingroup qmlmodules
-\brief Provides QML types for accessing NFC Forum Tags.
-
-To use the classes of the module in your application, you need the following
-import statement in your \c .qml file:
-
-\qml \QtVer
-import QtNfc \1
-\endqml
-*/
-
diff --git a/src/nfc/doc/src/qt6-changes.qdoc b/src/nfc/doc/src/qt6-changes.qdoc
new file mode 100644
index 00000000..5b25571e
--- /dev/null
+++ b/src/nfc/doc/src/qt6-changes.qdoc
@@ -0,0 +1,149 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qtnfc-changes-qt6.html
+ \title Changes to Qt NFC
+ \ingroup changes-qt-5-to-6
+ \brief Migrate Qt NFC 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 Qt NFC, and provide guidance
+ to handle them.
+
+ \section1 New Features and Methods
+
+ \section2 Added \l QNdefRecord::clear()
+
+ Use this method to clear an NDEF record.
+
+ \section2 Added \l QNdefFilter::match()
+
+ Use this method to check if a \l QNdefMessage matches the given filter.
+ The method returns \c true in case of successful match and \c false
+ otherwise.
+
+ \section2 Extended \l QNearFieldTarget::Type
+
+ The enum was extended with two more types:
+ \list
+ \li \l QNearFieldTarget::NfcTagType4A
+ \li \l QNearFieldTarget::NfcTagType4B
+ \endlist
+
+ \section1 Changes in the Features and Methods
+
+ \section2 Renamed QNearFieldManager::isAvailable()
+
+ The \c QNearFieldManager::isAvailable() was renamed to
+ \l QNearFieldManager::isEnabled().
+
+ \section2 Added access method argument to \l QNearFieldManager::isSupported
+
+ The \c accessMethod argument allows to check if a specific feature is
+ supported. This is relevant because different platforms or versions of
+ operating systems can support different options.
+
+ \section2 Added access method argument to \l QNearFieldManager::startTargetDetection
+
+ The \c accessMethod argument allows to scan for NFC tags with the given
+ access method.
+
+ \section2 Changed \l QNdefNfcSmartPosterRecord::typeInfo from \l QByteArray to \l QString
+
+ According to NDEF Smart Poster specification, the type is a UTF-8 formatted
+ string.
+ This affects the \l QNdefNfcSmartPosterRecord::typeInfo() and
+ \l QNdefNfcSmartPosterRecord::setTypeInfo() methods.
+
+ \section2 Updated return type of \l QNdefFilter::appendRecord
+
+ \l QNdefFilter::appendRecord now performs a basic validation of input
+ parameters and returns a boolean value indicating if the record is appended
+ to the filter or not.
+
+ \section1 Removed Features and Methods
+
+ \section2 Removed QNearFieldTarget::url
+
+ The method was never implemented in the existing subclasses of
+ \l QNearFieldTarget.
+
+ \section2 Removed QNearFieldTarget::sendCommands
+
+ In Qt 5, the method was not very helpful because it didn't provide a way to
+ track the results of intermediate commands. Normally, an additional command
+ needs to be sent only when the previous command is successfully executed.
+
+ The correct approach would be to manually create a queue of commands,
+ use \l QNearFieldTarget::sendCommand to send a command and
+ \l QNearFieldTarget::requestCompleted or \l QNearFieldTarget::error to
+ handle the results of each command individually.
+
+ \section2 Removed QNearFieldTarget::keepConnection
+
+ The methods \c QNearFieldTarget::keepConnection() and
+ \c QNearFieldTarget::setKeepConnection() were removed. Keeping the
+ connection is the default behavior for now.
+
+ \section2 Removed QNearFieldTarget::isProcessingCommand
+
+ The method was never implemented and always returned \c false.
+
+ \section2 Made QNearFieldTarget::setResponseForRequest private API
+
+ The method should not be exposed as a public API. Use
+ \l QNearFieldTarget::ndefMessageRead or \l QNearFieldTarget::requestResponse
+ to read the data from an NFC tag.
+
+ \section2 Removed QNearFieldTarget::handleResponse
+
+ The method was removed as it just forwarded the call to
+ \c QNearFieldManager::setResponseForRequest, which became private API.
+
+ \section2 Made QNearFieldTarget::reportError private API
+
+ A \l QNearFieldTarget::error signal can be used instead.
+
+ \section2 Removed QNearFieldTarget::ndefMessagesWritten signal
+
+ The \l QNearFieldTarget::requestCompleted signal is used for both NDEF
+ messages and custom commands. The \c id parameter can be used to check which
+ request is actually completed.
+
+ \section2 Removed QNearFieldManager::(un)registerNdefMessageHandler
+
+ The methods \c QNearFieldTarget::registerNdefMessageHandler and
+ \c QNearFieldTarget::unregisterNdefMessageHandler were removed.
+
+ Use \l QNearFieldTarget::ndefMessageRead() and \l QNdefFilter::match() to
+ detect the NDEF messages and filter the required ones.
+
+ \note The application can still be automatically started once the NDEF Tag
+ is touched. The \l {annotatedurl}{Annotated URL} example shows how to
+ achieve it on Android.
+
+ \section2 Removed QNearFieldManager::TargetAccessModes
+
+ The \c TargetAccessModes enum was removed together with the getter and
+ setter methods (\c QNearFieldManager::setTargetAccessModes() and
+ \c {QNearFieldManager::targetAccessModes()}).
+
+ The feature is not supported on Android and iOS platforms.
+
+ \section2 Removed QNearFieldShareManager and QNearFieldShareTarget
+
+ File sharing via NFC is deprecated on Android in API 29. Other technologies
+ should be used instead.
+
+ \section2 Removed QML API
+
+ The support for QML API is discontinued.
+
+*/
diff --git a/src/nfc/ios/qiosndefnotifier.cpp b/src/nfc/ios/qiosndefnotifier.cpp
new file mode 100644
index 00000000..20e01f06
--- /dev/null
+++ b/src/nfc/ios/qiosndefnotifier.cpp
@@ -0,0 +1,11 @@
+// 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 "qiosndefnotifier_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(QT_IOS_NFC, "qt.nfc.ios")
+
+QT_END_NAMESPACE
+
diff --git a/src/nfc/ios/qiosndefnotifier_p.h b/src/nfc/ios/qiosndefnotifier_p.h
new file mode 100644
index 00000000..fadade42
--- /dev/null
+++ b/src/nfc/ios/qiosndefnotifier_p.h
@@ -0,0 +1,56 @@
+// 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 QIOSNDEFNOTIFIER_P_H
+#define QIOSNDEFNOTIFIER_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/qglobal.h>
+#include <QtCore/qobject.h>
+
+#include <QtCore/qloggingcategory.h>
+
+#include "qnearfieldmanager.h"
+#include "qnearfieldtarget.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNdefMessage;
+class QString;
+
+class QNfcNdefNotifier : public QObject
+{
+ Q_OBJECT
+
+public:
+ QNfcNdefNotifier() = default;
+
+Q_SIGNALS:
+ void tagDetected(void *tag);
+ void invalidateWithError(bool restart);
+ void tagLost(void *tag);
+
+ void tagError(QNearFieldTarget::Error code, QNearFieldTarget::RequestId request);
+
+ void ndefMessageWritten(QNearFieldTarget::RequestId request);
+ void ndefMessageRead(const QNdefMessage &message, QNearFieldTarget::RequestId request);
+
+private:
+ Q_DISABLE_COPY_MOVE(QNfcNdefNotifier);
+};
+
+Q_DECLARE_LOGGING_CATEGORY(QT_IOS_NFC)
+
+QT_END_NAMESPACE
+
+#endif //QIOSNDEFNOTIFIER_P_H
diff --git a/src/nfc/ios/qiosnfcndefsessiondelegate.mm b/src/nfc/ios/qiosnfcndefsessiondelegate.mm
new file mode 100644
index 00000000..4db39edf
--- /dev/null
+++ b/src/nfc/ios/qiosnfcndefsessiondelegate.mm
@@ -0,0 +1,298 @@
+// 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 "qiosnfcndefsessiondelegate_p.h"
+#include "qiosndefnotifier_p.h"
+
+#include "qndefmessage.h"
+
+#include <QtCore/qscopeguard.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qdebug.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+dispatch_queue_t qt_Nfc_Queue()
+{
+ static dispatch_queue_t nfcQueue = []{
+ auto queue = dispatch_queue_create("qt-NFC-queue", DISPATCH_QUEUE_SERIAL);
+ if (!queue)
+ qCWarning(QT_IOS_NFC, "Failed to create the QtNfc's dispatch queue");
+ return queue;
+ }();
+ static const auto queueGuard = qScopeGuard([]{
+ if (nfcQueue)
+ dispatch_release(nfcQueue);
+ });
+ return nfcQueue;
+}
+
+QT_END_NAMESPACE
+
+QT_USE_NAMESPACE
+
+@implementation QIosNfcNdefSessionDelegate
+{
+ std::unique_ptr<QNfcNdefNotifier> notifier;
+ QString alertMessage;
+ NFCNDEFStatus tagStatus;
+ NSUInteger capacity;
+ QNearFieldTarget::RequestId requestId;
+}
+
+-(instancetype)initWithNotifier:(QNfcNdefNotifier *)aNotifier
+{
+ Q_ASSERT(aNotifier);
+
+ if (self = [super init]) {
+ auto queue = qt_Nfc_Queue();
+ if (!queue)
+ return self;
+
+ tagStatus = NFCNDEFStatusNotSupported;
+ capacity = 0;
+ notifier.reset(aNotifier);
+ }
+
+ return self;
+}
+
+-(void)dealloc
+{
+ [self abort];
+ [super dealloc];
+}
+
+-(QNfcNdefNotifier *)ndefNotifier
+{
+ return notifier.get();
+}
+
+-(void)abort
+{
+ notifier.reset(nullptr);
+ [self reset];
+}
+
+-(bool)startSession
+{
+ if (self.session)
+ return true;
+
+ auto queue = qt_Nfc_Queue();
+ Q_ASSERT(queue);
+ self.session = [[NFCNDEFReaderSession alloc] initWithDelegate:self queue:queue invalidateAfterFirstRead:NO];
+ if (alertMessage.size())
+ self.session.alertMessage = alertMessage.toNSString();
+
+ if (!self.session)
+ return false;
+
+ qCDebug(QT_IOS_NFC, "Starting NFC NDEF reader session");
+ [self.session beginSession];
+ return true;
+}
+
+-(void)reset
+{
+ self.session = nil; // Strong property, releases.
+ self.ndefTag = nil; // Strong property, releases.
+ requestId = {};
+ tagStatus = NFCNDEFStatusNotSupported;
+ capacity = 0;
+}
+
+-(void)stopSession:(const QString &)message
+{
+ if (!self.session)
+ return;
+
+ if (self.ndefTag && notifier.get())
+ emit notifier->tagLost(self.ndefTag);
+
+ if (message.size())
+ [self.session invalidateSessionWithErrorMessage:message.toNSString()];
+ else
+ [self.session invalidateSession];
+
+ [self reset];
+}
+
+-(void)setAlertMessage:(const QString &)message
+{
+ alertMessage = message;
+}
+
+-(void)readerSession:(NFCNDEFReaderSession *)session
+ didInvalidateWithError:(NSError *)error
+{
+ if (session != self.session) // If we stopped the session, this maybe the case.
+ return;
+
+ if (!notifier.get()) // Aborted.
+ return;
+
+ NSLog(@"session did invalidate with error %@", error);
+
+ if (error.code != NFCReaderSessionInvalidationErrorUserCanceled && error.code != NFCReaderErrorUnsupportedFeature) {
+ if (self.ndefTag)
+ emit notifier->tagError(QNearFieldTarget::TimeoutError, {});
+
+ emit notifier->invalidateWithError(true);
+ [self reset];
+ }
+
+ // Native errors:
+ //
+ // NFCReaderErrorRadioDisabled
+ // NFCReaderErrorUnsupportedFeature
+ // NFCReaderErrorSecurityViolation
+ // NFCReaderErrorInvalidParameter
+ // NFCReaderErrorParameterOutOfBound
+ // NFCReaderErrorInvalidParameterLength
+ // NFCReaderTransceiveErrorTagConnectionLost
+ // NFCReaderTransceiveErrorRetryExceeded
+ // NFCReaderTransceiveErrorSessionInvalidated
+ // NFCReaderTransceiveErrorTagNotConnected
+ // NFCReaderTransceiveErrorPacketTooLong
+ // NFCReaderSessionInvalidationErrorUserCanceled
+ // NFCReaderSessionInvalidationErrorSessionTimeout
+ // NFCReaderSessionInvalidationErrorSessionTerminatedUnexpectedly
+ // NFCReaderSessionInvalidationErrorSystemIsBusy
+ // NFCReaderSessionInvalidationErrorFirstNDEFTagRead
+ // NFCTagCommandConfigurationErrorInvalidParameters
+ // NFCNdefReaderSessionErrorTagNotWritable
+ // NFCNdefReaderSessionErrorTagUpdateFailure
+ // NFCNdefReaderSessionErrorTagSizeTooSmall
+ //NFCNdefReaderSessionErrorZeroLengthMessage
+
+ // And these are what Qt has ...
+ /*
+ enum Error {
+ NoError,
+ UnknownError,
+ UnsupportedError,
+ TargetOutOfRangeError,
+ NoResponseError,
+ ChecksumMismatchError,
+ InvalidParametersError,
+ ConnectionError,
+ NdefReadError,
+ NdefWriteError,
+ CommandError,
+ TimeoutError
+ };
+ */
+ // TODO: try to map those native errors to Qt ones ...
+}
+
+-(void)readerSession:(NFCNDEFReaderSession *)session
+ didDetectNDEFs:(NSArray<NFCNDEFMessage *> *)messages
+{
+ Q_UNUSED(session);
+ Q_UNUSED(messages);
+ // It's intentionally a noop and should never be called, because
+ // we implement the other method, giving us access to a tag.
+ Q_UNREACHABLE();
+}
+
+-(void)restartPolling
+{
+ if (!self.session)
+ return;
+
+ auto queue = qt_Nfc_Queue();
+ Q_ASSERT(queue);
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
+ int64_t(100./1000. * NSEC_PER_SEC)),//100 ms
+ queue,
+ ^{
+ [self.session restartPolling];
+ });
+}
+
+-(void)tag:(id<NFCNDEFTag>)tag didUpdateNDEFStatus:(NFCNDEFStatus)status
+ capacity:(NSUInteger)aCapacity error:(NSError *)error
+{
+ if (!notifier.get()) // Aborted.
+ return;
+
+ if (tag != self.ndefTag)
+ return;
+
+ if (error) {
+ NSLog(@"Querying NDEF tag's status failed: %@, restarting polling ...", error);
+ self.ndefTag = nil;
+ return [self restartPolling];
+ }
+
+ tagStatus = status;
+ capacity = aCapacity;
+
+ if (status == NFCNDEFStatusNotSupported) {
+ qCDebug(QT_IOS_NFC, "The discovered tag does not support NDEF.");
+ return [self restartPolling];
+ }
+
+ if (status == NFCNDEFStatusReadWrite)
+ qCDebug(QT_IOS_NFC, "NDEF read/write capable tag found");
+
+ if (status == NFCNDEFStatusReadOnly)
+ qCDebug(QT_IOS_NFC, "The discovered tag is read only");
+
+ qCInfo(QT_IOS_NFC) << "The max message size for the tag is:" << capacity;
+
+ [self.session connectToTag:self.ndefTag completionHandler:^(NSError * _Nullable error) {
+ if (!error) {
+ if (notifier.get())
+ emit notifier->tagDetected(self.ndefTag);
+ } else {
+ NSLog(@"Failed to connect to NDEF-capable tag, error: %@", error);
+ [self restartPolling];
+ }
+ }];
+}
+
+
+-(void)readerSession:(NFCNDEFReaderSession *)session
+ didDetectTags:(NSArray<__kindof id<NFCNDEFTag>> *)tags
+{
+ if (!notifier.get())
+ return; // Aborted by Qt.
+
+ if (session != self.session) // We stopped _that_ session.
+ return;
+
+ if (tags.count != 1) {
+ qCWarning(QT_IOS_NFC, "Unexpected number of NDEF tags, restarting ...");
+ [self restartPolling];
+ return;
+ }
+
+ NSLog(@"detected a tag! %@", tags[0]);
+
+ id<NFCNDEFTag> tag = tags[0];
+ self.ndefTag = tag; // Strong reference, retains.
+ tagStatus = NFCNDEFStatusNotSupported;
+ capacity = 0;
+
+ [self.ndefTag queryNDEFStatusWithCompletionHandler:
+ ^(NFCNDEFStatus status, NSUInteger aCapacity, NSError * _Nullable error) {
+ [self tag:tag didUpdateNDEFStatus:status capacity:aCapacity error:error];
+ }];
+}
+
+-(void)readerSessionDidBecomeActive:(NFCNDEFReaderSession *)session
+{
+ if (session != self.session)
+ return [session invalidateSession];
+
+ qCInfo(QT_IOS_NFC, "session is active now");
+}
+
+@end
+
diff --git a/src/nfc/ios/qiosnfcndefsessiondelegate_p.h b/src/nfc/ios/qiosnfcndefsessiondelegate_p.h
new file mode 100644
index 00000000..5ec1c12b
--- /dev/null
+++ b/src/nfc/ios/qiosnfcndefsessiondelegate_p.h
@@ -0,0 +1,88 @@
+// 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 QIOSNFCNDEFSESSIONDELEFATE_P_H
+#define QIOSNFCNDEFSESSIONDELEFATE_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/qglobal.h>
+
+#include <QtCore/private/qcore_mac_p.h>
+
+#include "qnearfieldmanager.h"
+#include "qnearfieldtarget.h"
+
+#include <Foundation/Foundation.h>
+#include <CoreNFC/CoreNFC.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldManagerPrivateImpl;
+class QNfcNdefNotifier;
+class QNearFieldTarget;
+class QNdefMessage;
+class QString;
+
+dispatch_queue_t qt_Nfc_Queue();
+
+QT_END_NAMESPACE
+
+QT_USE_NAMESPACE
+
+@interface QT_MANGLE_NAMESPACE(QIosNfcNdefSessionDelegate) : NSObject<NFCNDEFReaderSessionDelegate>
+
+@property (strong, nonatomic) NFCNDEFReaderSession *session;
+@property (strong, nonatomic) id<NFCNDEFTag> ndefTag;
+
+
+-(instancetype)initWithNotifier:(QNfcNdefNotifier *)aNotifier;
+-(void)dealloc;
+
+-(QNfcNdefNotifier *)ndefNotifier;
+
+-(void)setAlertMessage:(const QString &)message;
+
+// Those methods to be called on the session.sessionQueue:
+-(bool)startSession;
+-(void)stopSession:(const QString &)message;
+-(void)abort;
+
+// Delegate's methods, implementing the protocol NFCNDEFReaderSessionDelegate.
+// Those methods not to be called by the Qt.
+
+// "Gets called when a session becomes invalid. At this point the client is expected to
+// discard the returned session object."
+-(void)readerSession:(NFCNDEFReaderSession *)session
+ didInvalidateWithError:(NSError *)error;
+
+// "Gets called when the reader detects NFC tag(s) with NDEF messages in the polling sequence.
+// Polling is automatically restarted once the detected tag is removed from the reader's read
+// range. This method is only get call if the optional -readerSession:didDetectTags: method
+// is not implemented."
+-(void)readerSession:(NFCNDEFReaderSession *)session
+ didDetectNDEFs:(NSArray<NFCNDEFMessage *> *)messages;
+
+// "Gets called when the reader detects NDEF tag(s) in the RF field. Presence of this method
+// overrides -readerSession:didDetectNDEFs: and enables read-write capability for the session."
+-(void)readerSession:(NFCNDEFReaderSession *)session
+ didDetectTags:(NSArray<__kindof id<NFCNDEFTag>> *)tags;
+
+// "Gets called when the NFC reader session has become active. RF is enabled and reader is
+// scanning for tags."
+-(void)readerSessionDidBecomeActive:(NFCNDEFReaderSession *)session;
+
+@end
+
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QIosNfcNdefSessionDelegate);
+
+#endif // QIOSNFCNDEFSESSIONDELEFATE_P_H
diff --git a/src/nfc/ios/qiostagreaderdelegate.mm b/src/nfc/ios/qiostagreaderdelegate.mm
new file mode 100644
index 00000000..fd7db020
--- /dev/null
+++ b/src/nfc/ios/qiostagreaderdelegate.mm
@@ -0,0 +1,110 @@
+// Copyright (C) 2020 Governikus GmbH & Co. KG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qiostagreaderdelegate_p.h"
+
+#include "qnearfieldmanager_ios_p.h"
+
+#import <CoreNFC/NFCError.h>
+#import <CoreNFC/NFCTag.h>
+
+QT_USE_NAMESPACE
+
+@implementation QT_MANGLE_NAMESPACE(QIosTagReaderDelegate)
+
+- (instancetype)initWithListener:(QNearFieldManagerPrivateImpl *)listener
+{
+ self = [super init];
+ if (self) {
+ self.listener = listener;
+ self.sessionStoppedByApplication = false;
+ self.message = nil;
+ self.session = nil;
+ }
+
+ return self;
+}
+
+- (void)startSession
+{
+ if (self.session && !self.sessionStoppedByApplication) {
+ [self.session invalidateSession];
+ self.sessionStoppedByApplication = true;
+ }
+
+ if (self.sessionStoppedByApplication) {
+ Q_EMIT self.listener->didInvalidateWithError(true);
+ return;
+ }
+
+ self.session = [[[NFCTagReaderSession alloc] initWithPollingOption:NFCPollingISO14443 delegate:self queue:nil] autorelease];
+ if (self.session) {
+ if (self.message)
+ self.session.alertMessage = self.message;
+ [self.session beginSession];
+ } else {
+ Q_EMIT self.listener->didInvalidateWithError(true);
+ }
+}
+
+- (void)stopSession:(QString)message
+{
+ if (self.session && !self.sessionStoppedByApplication) {
+ if (message.isNull())
+ [self.session invalidateSession];
+ else
+ [self.session invalidateSessionWithErrorMessage:message.toNSString()];
+ self.sessionStoppedByApplication = true;
+ }
+}
+
+- (void)alertMessage:(QString)message
+{
+ if (self.session && !self.sessionStoppedByApplication)
+ self.session.alertMessage = message.toNSString();
+ else
+ self.message = message.toNSString();
+}
+
+- (void)tagReaderSessionDidBecomeActive:(NFCTagReaderSession*)session
+{
+ if (session != self.session)
+ [session invalidateSession];
+}
+
+- (void)tagReaderSession:(NFCTagReaderSession*)session didInvalidateWithError:(NSError*)error
+{
+ if (session != self.session)
+ return;
+
+ self.session = nil;
+ if (self.sessionStoppedByApplication) {
+ self.sessionStoppedByApplication = false;
+ return;
+ }
+
+ const bool doRestart =
+ !(error.code == NFCReaderError::NFCReaderSessionInvalidationErrorUserCanceled
+ || error.code == NFCReaderError::NFCReaderErrorUnsupportedFeature);
+ Q_EMIT self.listener->didInvalidateWithError(doRestart);
+}
+
+- (void)tagReaderSession:(NFCTagReaderSession*)session didDetectTags:(NSArray<__kindof id<NFCTag>>*)tags
+{
+ if (session != self.session)
+ return;
+
+ bool foundTag = false;
+ for (id<NFCTag> tag in tags) {
+ if (tag.type == NFCTagTypeISO7816Compatible) {
+ foundTag = true;
+ [tag retain];
+ Q_EMIT self.listener->tagDiscovered(tag);
+ }
+ }
+
+ if (!foundTag)
+ [session restartPolling];
+}
+
+@end
diff --git a/src/nfc/ios/qiostagreaderdelegate_p.h b/src/nfc/ios/qiostagreaderdelegate_p.h
new file mode 100644
index 00000000..7defcd44
--- /dev/null
+++ b/src/nfc/ios/qiostagreaderdelegate_p.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2020 Governikus GmbH & Co. KG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QIOSTAGREADERDELEGATE_P_H
+#define QIOSTAGREADERDELEGATE_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 <QString>
+
+#import <CoreNFC/NFCReaderSession.h>
+#import <CoreNFC/NFCTagReaderSession.h>
+#import <Foundation/Foundation.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldManagerPrivateImpl;
+
+QT_END_NAMESPACE
+
+API_AVAILABLE(ios(13.0))
+@interface QT_MANGLE_NAMESPACE(QIosTagReaderDelegate)
+ : NSObject<NFCTagReaderSessionDelegate>
+
+@property QNearFieldManagerPrivateImpl *listener;
+@property bool sessionStoppedByApplication;
+@property (nonatomic, strong) NSString *message;
+@property (nonatomic, strong) NFCTagReaderSession *session;
+
+- (instancetype)initWithListener:(QNearFieldManagerPrivateImpl *)listener;
+
+- (void)startSession;
+- (void)stopSession:(QString)message;
+
+- (void)alertMessage:(QString)message;
+
+@end
+
+#endif // QIOSTAGREADERDELEGATE_P_H
diff --git a/src/nfc/ndef/qndefaccessfsm_p.h b/src/nfc/ndef/qndefaccessfsm_p.h
new file mode 100644
index 00000000..2a175bcc
--- /dev/null
+++ b/src/nfc/ndef/qndefaccessfsm_p.h
@@ -0,0 +1,103 @@
+// 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 QNDEFACCESSFSM_P_H
+#define QNDEFACCESSFSM_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 "qndefmessage.h"
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Base class for FSMs that can be used to exchange NDEF messages with cards.
+
+ The user may call one of these methods to start a task:
+
+ - detectNdefSupport()
+ - readMessages()
+ - writeMessages()
+
+ The user is then expected to perform actions indicated by Action type.
+*/
+class QNdefAccessFsm
+{
+ Q_DISABLE_COPY_MOVE(QNdefAccessFsm)
+public:
+ QNdefAccessFsm() = default;
+ virtual ~QNdefAccessFsm() = default;
+
+ enum Action {
+ // The requested task has successfully completed. New tasks can be started.
+ Done,
+ // The requested task has failed. New tasks can be started.
+ Failed,
+ // An NDEF message was successfully read. The user must call getMessage().
+ GetMessage,
+ // The user's call was unexpected. The FSM may be in an invalid state.
+ Unexpected,
+ // The user must call getCommand() and then send the returned command to the card.
+ SendCommand,
+ // The user must call provideResponse() with the result of the last sent command.
+ ProvideResponse
+ };
+
+ /*
+ Returns a command to send to the card.
+
+ This method must be called if the FMS has requested SendCommand action.
+
+ Next action will be ProvideResponse or Unexpected.
+ */
+ virtual QByteArray getCommand(Action &nextAction) = 0;
+
+ /*
+ This method must be called by the user to provide response for
+ a completed command.
+
+ An empty QByteArray can be provided to indicate that the command
+ has failed.
+ */
+ virtual Action provideResponse(const QByteArray &response) = 0;
+
+ /*
+ Returns an NDEF message that was read from the card.
+
+ This method must be called if the FSM has requested GetMessage action.
+ */
+ virtual QNdefMessage getMessage(Action &nextAction) = 0;
+
+ /*
+ Start NDEF support detection.
+ */
+ virtual Action detectNdefSupport() = 0;
+
+ /*
+ Start reading NDEF messages.
+
+ This call also performs NDEF support detection if it was not performed
+ earlier.
+ */
+ virtual Action readMessages() = 0;
+
+ /*
+ Start writing the given messages to the card.
+
+ This call also performs NDEF detection if is was not performed earlier.
+ */
+ virtual Action writeMessages(const QList<QNdefMessage> &messages) = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNDEFACCESSFSM_P_H
diff --git a/src/nfc/ndef/qnfctagtype4ndeffsm.cpp b/src/nfc/ndef/qnfctagtype4ndeffsm.cpp
new file mode 100644
index 00000000..c21608e4
--- /dev/null
+++ b/src/nfc/ndef/qnfctagtype4ndeffsm.cpp
@@ -0,0 +1,374 @@
+// 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 "qnfctagtype4ndeffsm_p.h"
+#include <QtCore/QtEndian>
+#include <QtCore/QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(QT_NFC_T4T, "qt.nfc.t4t")
+
+/*
+ NDEF support for NFC Type 4 tags.
+
+ Based on Type 4 Tag Operation Specification, Version 2.0 (T4TOP 2.0).
+*/
+
+QByteArray QNfcTagType4NdefFsm::getCommand(QNdefAccessFsm::Action &nextAction)
+{
+ // ID of the NDEF Tag Application
+ static constexpr uint8_t NtagApplicationIdV2[] { 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 };
+ // Capability container file ID.
+ static constexpr uint8_t CapabilityContainerId[] { 0xE1, 0x03 };
+ // Shortcut for specifying zero length of NDEF message data.
+ static constexpr uint8_t ZeroLength[] { 0x00, 0x00 };
+
+ nextAction = ProvideResponse;
+
+ switch (m_currentState) {
+ case SelectApplicationForProbe:
+ case SelectApplicationForRead:
+ case SelectApplicationForWrite:
+ return QCommandApdu::build(0x00, QCommandApdu::Select, 0x04, 0x00,
+ QByteArrayView::fromArray(NtagApplicationIdV2), 256);
+ case SelectCCFile:
+ return QCommandApdu::build(0x00, QCommandApdu::Select, 0x00, 0x0C,
+ QByteArrayView::fromArray(CapabilityContainerId));
+ case ReadCCFile:
+ return QCommandApdu::build(0x00, QCommandApdu::ReadBinary, 0x00, 0x00, {}, 15);
+ case SelectNdefFileForRead:
+ case SelectNdefFileForWrite:
+ return QCommandApdu::build(0x00, QCommandApdu::Select, 0x00, 0x0C, m_ndefFileId);
+ case ReadNdefMessageLength:
+ return QCommandApdu::build(0x00, QCommandApdu::ReadBinary, 0x00, 0x00, {}, 2);
+ case ReadNdefMessage: {
+ uint16_t readSize = qMin(m_fileSize, m_maxReadSize);
+
+ return QCommandApdu::build(0x00, QCommandApdu::ReadBinary, m_fileOffset >> 8,
+ m_fileOffset & 0xFF, {}, readSize);
+ }
+ case ClearNdefLength:
+ m_fileOffset = 2;
+ m_fileSize = m_ndefData.size();
+ return QCommandApdu::build(0x00, QCommandApdu::UpdateBinary, 0x00, 0x00,
+ QByteArrayView::fromArray(ZeroLength));
+ case WriteNdefFile: {
+ uint16_t updateSize = qMin(m_fileSize, m_maxUpdateSize);
+ uint16_t fileOffset = m_fileOffset;
+
+ m_fileOffset += updateSize;
+ m_fileSize -= updateSize;
+
+ return QCommandApdu::build(0x00, QCommandApdu::UpdateBinary, fileOffset >> 8,
+ fileOffset & 0xFF, m_ndefData.mid(fileOffset - 2, updateSize));
+ }
+ case WriteNdefLength: {
+ QByteArray data(2, Qt::Uninitialized);
+ qToUnaligned(qToBigEndian<uint16_t>(m_ndefData.size()), data.data());
+
+ return QCommandApdu::build(0x00, QCommandApdu::UpdateBinary, 0x00, 0x00, data);
+ }
+ default:
+ nextAction = Unexpected;
+ return {};
+ }
+}
+
+QNdefMessage QNfcTagType4NdefFsm::getMessage(QNdefAccessFsm::Action &nextAction)
+{
+ if (m_currentState == NdefMessageRead) {
+ auto message = QNdefMessage::fromByteArray(m_ndefData);
+ m_ndefData.clear();
+ m_currentState = NdefSupportDetected;
+ nextAction = Done;
+ return message;
+ }
+
+ nextAction = Unexpected;
+ return {};
+}
+
+QNdefAccessFsm::Action QNfcTagType4NdefFsm::detectNdefSupport()
+{
+ switch (m_currentState) {
+ case SelectApplicationForProbe:
+ m_targetState = NdefSupportDetected;
+ return SendCommand;
+ case NdefSupportDetected:
+ return Done;
+ case NdefNotSupported:
+ return Failed;
+ default:
+ return Unexpected;
+ }
+}
+
+QNdefAccessFsm::Action QNfcTagType4NdefFsm::readMessages()
+{
+ switch (m_currentState) {
+ case SelectApplicationForProbe:
+ m_targetState = NdefMessageRead;
+ return SendCommand;
+ case NdefSupportDetected:
+ m_currentState = SelectApplicationForRead;
+ m_targetState = NdefMessageRead;
+ return SendCommand;
+ case NdefNotSupported:
+ return Failed;
+ default:
+ return Unexpected;
+ }
+}
+
+QNdefAccessFsm::Action QNfcTagType4NdefFsm::writeMessages(const QList<QNdefMessage> &messages)
+{
+ // Only one message per tag is supported
+ if (messages.isEmpty() || messages.size() > 1)
+ return Failed;
+
+ auto messageData = messages.first().toByteArray();
+ if (messageData.size() > m_maxNdefSize - 2)
+ return Failed;
+
+ m_ndefData = messageData;
+
+ m_targetState = NdefMessageWritten;
+
+ switch (m_currentState) {
+ case SelectApplicationForProbe:
+ return SendCommand;
+
+ case NdefNotSupported:
+ return Failed;
+
+ case NdefSupportDetected:
+ if (!m_writable)
+ return Failed;
+
+ m_currentState = SelectApplicationForWrite;
+ return SendCommand;
+
+ default:
+ return Unexpected;
+ };
+}
+
+QNdefAccessFsm::Action QNfcTagType4NdefFsm::provideResponse(const QByteArray &response)
+{
+ QResponseApdu apdu(response);
+
+ switch (m_currentState) {
+ case SelectApplicationForProbe:
+ return handleSimpleResponse(apdu, SelectCCFile, NdefNotSupported);
+ case SelectCCFile:
+ return handleSimpleResponse(apdu, ReadCCFile, NdefNotSupported);
+ case ReadCCFile:
+ return handleReadCCResponse(apdu);
+
+ case SelectApplicationForRead:
+ return handleSimpleResponse(apdu, SelectNdefFileForRead, NdefSupportDetected);
+ case SelectNdefFileForRead:
+ return handleSimpleResponse(apdu, ReadNdefMessageLength, NdefSupportDetected);
+ case ReadNdefMessageLength:
+ return handleReadFileLengthResponse(apdu);
+ case ReadNdefMessage:
+ return handleReadFileResponse(apdu);
+
+ case SelectApplicationForWrite:
+ return handleSimpleResponse(apdu, SelectNdefFileForWrite, NdefSupportDetected);
+ case SelectNdefFileForWrite:
+ return handleSimpleResponse(apdu, ClearNdefLength, NdefSupportDetected);
+ case ClearNdefLength:
+ return handleSimpleResponse(apdu, WriteNdefFile, NdefSupportDetected);
+ case WriteNdefFile:
+ return handleWriteNdefFileResponse(apdu);
+ case WriteNdefLength:
+ return handleSimpleResponse(apdu, NdefSupportDetected, NdefSupportDetected, Done);
+
+ default:
+ return Unexpected;
+ }
+}
+
+QNdefAccessFsm::Action QNfcTagType4NdefFsm::handleSimpleResponse(
+ const QResponseApdu &response, QNfcTagType4NdefFsm::State okState,
+ QNfcTagType4NdefFsm::State failedState, QNdefAccessFsm::Action okAction)
+{
+ if (!response.isOk()) {
+ m_currentState = failedState;
+ return Failed;
+ }
+
+ m_currentState = okState;
+ return okAction;
+}
+
+QNdefAccessFsm::Action QNfcTagType4NdefFsm::handleReadCCResponse(const QResponseApdu &response)
+{
+ m_currentState = NdefNotSupported;
+
+ if (!response.isOk())
+ return Failed;
+
+ if (response.data().size() < 15) {
+ qCDebug(QT_NFC_T4T) << "Invalid response size";
+ return Failed;
+ }
+
+ qsizetype idx = 0;
+ auto readU8 = [&data = response.data(), &idx]() {
+ return static_cast<uint8_t>(data.at(idx++));
+ };
+ auto readU16 = [&data = response.data(), &idx]() {
+ Q_ASSERT(idx >= 0 && idx <= data.size() - 2);
+ uint16_t res = qFromBigEndian(qFromUnaligned<uint16_t>(data.constData() + idx));
+ idx += 2;
+ return res;
+ };
+ auto readBytes = [&data = response.data(), &idx](qsizetype count) {
+ auto res = data.sliced(idx, count);
+ idx += count;
+ return res;
+ };
+ auto ccLen = readU16();
+ if (ccLen < 15) {
+ qCDebug(QT_NFC_T4T) << "CC length is too small";
+ return Failed;
+ }
+ auto mapping = readU8();
+ if ((mapping & 0xF0) != 0x20) {
+ qCDebug(QT_NFC_T4T) << "Unsupported mapping:" << Qt::hex << mapping;
+ return Failed;
+ }
+ m_maxReadSize = readU16();
+ if (m_maxReadSize < 0xF) {
+ qCDebug(QT_NFC_T4T) << "Invalid maxReadSize" << m_maxReadSize;
+ return Failed;
+ }
+
+ m_maxUpdateSize = readU16();
+ auto tlvTag = readU8();
+ if (tlvTag != 0x04) {
+ qCDebug(QT_NFC_T4T) << "Invalid TLV tag";
+ return Failed;
+ }
+ auto tlvSize = readU8();
+ if (tlvSize == 0xFF || tlvSize < 6) {
+ qCDebug(QT_NFC_T4T) << "Invalid TLV size";
+ return Failed;
+ }
+ m_ndefFileId = readBytes(2);
+
+ m_maxNdefSize = readU16();
+ if (m_maxNdefSize < 2) {
+ qCDebug(QT_NFC_T4T) << "No space for NDEF file length";
+ return Failed;
+ }
+
+ /*
+ The specification defined value 0 for read access and write access
+ fields to mean that access is granted without any security, all
+ other values are either reserved, proprietary, or indicate than no
+ access is granted at all. Here all non-zero value are handled as
+ no access is granted.
+ */
+ auto readAccess = readU8();
+ if (readAccess != 0) {
+ qCDebug(QT_NFC_T4T) << "No read access";
+ return Failed;
+ }
+ auto writeAccess = readU8();
+ // It's not possible to atomically clear the length field if update
+ // size is < 2, so handle such tags as read-only. This also simplifies
+ // the update logic (no need to ever split ClearNdefLength/WriteNdefLength
+ // states)
+ m_writable = writeAccess == 0 && m_maxUpdateSize >= 2;
+
+ m_currentState = NdefSupportDetected;
+
+ if (m_targetState == NdefSupportDetected) {
+ return Done;
+ } else if (m_targetState == NdefMessageRead) {
+ // Skip extra application select
+ m_currentState = SelectNdefFileForRead;
+ return SendCommand;
+ } else if (m_targetState == NdefMessageWritten) {
+ if (m_writable) {
+ if (m_ndefData.size() > m_maxNdefSize - 2) {
+ qCDebug(QT_NFC_T4T) << "Message is too large";
+ return Failed;
+ }
+
+ // Skip extra application select
+ m_currentState = SelectNdefFileForWrite;
+ return SendCommand;
+ } else {
+ return Failed;
+ }
+ }
+
+ return Unexpected;
+}
+
+QNdefAccessFsm::Action
+QNfcTagType4NdefFsm::handleReadFileLengthResponse(const QResponseApdu &response)
+{
+ if (!response.isOk() || response.data().size() < 2) {
+ m_currentState = NdefSupportDetected;
+ return Failed;
+ }
+
+ m_fileSize = qFromBigEndian(qFromUnaligned<uint16_t>(response.data().constData()));
+ if (m_fileSize > m_maxNdefSize - 2) {
+ m_currentState = NdefSupportDetected;
+ return Failed;
+ }
+
+ m_fileOffset = 2;
+ m_ndefData.clear();
+
+ if (m_fileSize == 0) {
+ m_currentState = NdefMessageRead;
+ return GetMessage;
+ }
+
+ m_currentState = ReadNdefMessage;
+ return SendCommand;
+}
+
+QNdefAccessFsm::Action QNfcTagType4NdefFsm::handleReadFileResponse(const QResponseApdu &response)
+{
+ if (!response.isOk() || response.data().size() == 0) {
+ m_currentState = NdefSupportDetected;
+ return Failed;
+ }
+
+ auto readSize = qMin<qsizetype>(m_fileSize, response.data().size());
+ m_ndefData.append(response.data().first(readSize));
+ m_fileOffset += readSize;
+ m_fileSize -= readSize;
+
+ if (m_fileSize == 0) {
+ m_currentState = NdefMessageRead;
+ return GetMessage;
+ }
+
+ return SendCommand;
+}
+
+QNdefAccessFsm::Action
+QNfcTagType4NdefFsm::handleWriteNdefFileResponse(const QResponseApdu &response)
+{
+ if (!response.isOk()) {
+ m_currentState = NdefSupportDetected;
+ return Failed;
+ }
+
+ if (m_fileSize == 0)
+ m_currentState = WriteNdefLength;
+
+ return SendCommand;
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/ndef/qnfctagtype4ndeffsm_p.h b/src/nfc/ndef/qnfctagtype4ndeffsm_p.h
new file mode 100644
index 00000000..0ec8c378
--- /dev/null
+++ b/src/nfc/ndef/qnfctagtype4ndeffsm_p.h
@@ -0,0 +1,82 @@
+// 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 QNFCTAGTYPE4NDEFFSM_P_H
+#define QNFCTAGTYPE4NDEFFSM_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 "qndefaccessfsm_p.h"
+#include "qapduutils_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNfcTagType4NdefFsm : public QNdefAccessFsm
+{
+public:
+ QByteArray getCommand(Action &nextAction) override;
+ QNdefMessage getMessage(Action &nextAction) override;
+ Action provideResponse(const QByteArray &response) override;
+
+ Action detectNdefSupport() override;
+ Action readMessages() override;
+ Action writeMessages(const QList<QNdefMessage> &messages) override;
+
+private:
+ enum State {
+ SelectApplicationForProbe,
+ SelectCCFile,
+ ReadCCFile,
+ NdefSupportDetected,
+ NdefNotSupported,
+
+ SelectApplicationForRead,
+ SelectNdefFileForRead,
+ ReadNdefMessageLength,
+ ReadNdefMessage,
+ NdefMessageRead,
+
+ SelectApplicationForWrite,
+ SelectNdefFileForWrite,
+ ClearNdefLength,
+ WriteNdefFile,
+ WriteNdefLength,
+ NdefMessageWritten // Only for target state, it is never actually reached
+ };
+
+ State m_currentState = SelectApplicationForProbe;
+ State m_targetState = SelectApplicationForProbe;
+
+ // Initialized during the detection phase
+ uint16_t m_maxReadSize;
+ uint16_t m_maxUpdateSize;
+ QByteArray m_ndefFileId;
+ uint16_t m_maxNdefSize = 0xFFFF;
+ bool m_writable;
+
+ // Used during the read and write operations
+ uint16_t m_fileSize;
+ uint16_t m_fileOffset;
+ QByteArray m_ndefData;
+
+ Action handleSimpleResponse(const QResponseApdu &response, State okState, State failedState,
+ Action okAction = SendCommand);
+
+ Action handleReadCCResponse(const QResponseApdu &response);
+ Action handleReadFileLengthResponse(const QResponseApdu &response);
+ Action handleReadFileResponse(const QResponseApdu &response);
+ Action handleWriteNdefFileResponse(const QResponseApdu &response);
+};
+
+QT_END_NAMESPACE
+
+#endif // QNFCTAGTYPE4NDEFFSM_P_H
diff --git a/src/nfc/neard/adapter.cpp b/src/nfc/neard/adapter.cpp
deleted file mode 100644
index d626678a..00000000
--- a/src/nfc/neard/adapter.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -v org.neard.Adapter.xml -p adapter_p -v
- *
- * 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 "adapter_p.h"
-
-/*
- * Implementation of interface class OrgNeardAdapterInterface
- */
-
-OrgNeardAdapterInterface::OrgNeardAdapterInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgNeardAdapterInterface::~OrgNeardAdapterInterface()
-{
-}
diff --git a/src/nfc/neard/adapter_p.h b/src/nfc/neard/adapter_p.h
deleted file mode 100644
index 76817705..00000000
--- a/src/nfc/neard/adapter_p.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -v org.neard.Adapter.xml -p adapter_p -v
- *
- * qdbusxml2cpp is Copyright (C) 2015 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_1410940487
-#define ADAPTER_P_H_1410940487
-
-#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.neard.Adapter
- */
-class OrgNeardAdapterInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.neard.Adapter"; }
-
-public:
- OrgNeardAdapterInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
-
- ~OrgNeardAdapterInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<> StartPollLoop(const QString &name)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(name);
- return asyncCallWithArgumentList(QStringLiteral("StartPollLoop"), argumentList);
- }
-
- inline QDBusPendingReply<> StopPollLoop()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("StopPollLoop"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
-};
-
-namespace org {
- namespace neard {
- typedef ::OrgNeardAdapterInterface Adapter;
- }
-}
-#endif
diff --git a/src/nfc/neard/agent.cpp b/src/nfc/neard/agent.cpp
deleted file mode 100644
index faa48043..00000000
--- a/src/nfc/neard/agent.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -v org.neard.Agent.xml -p agent_p -v
- *
- * 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 "agent_p.h"
-
-/*
- * Implementation of interface class OrgNeardHandoverAgentInterface
- */
-
-OrgNeardHandoverAgentInterface::OrgNeardHandoverAgentInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgNeardHandoverAgentInterface::~OrgNeardHandoverAgentInterface()
-{
-}
-
-/*
- * Implementation of interface class OrgNeardNDEFAgentInterface
- */
-
-OrgNeardNDEFAgentInterface::OrgNeardNDEFAgentInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgNeardNDEFAgentInterface::~OrgNeardNDEFAgentInterface()
-{
-}
diff --git a/src/nfc/neard/agent_p.h b/src/nfc/neard/agent_p.h
deleted file mode 100644
index 7e40ffaf..00000000
--- a/src/nfc/neard/agent_p.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -v org.neard.Agent.xml -p agent_p -v
- *
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef AGENT_P_H_1410442485
-#define AGENT_P_H_1410442485
-
-#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.neard.HandoverAgent
- */
-class OrgNeardHandoverAgentInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.neard.HandoverAgent"; }
-
-public:
- OrgNeardHandoverAgentInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
-
- ~OrgNeardHandoverAgentInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<> PushOOB(const QVariantMap &values)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(values);
- return asyncCallWithArgumentList(QStringLiteral("PushOOB"), argumentList);
- }
-
- inline QDBusPendingReply<> Release()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("Release"), argumentList);
- }
-
- inline QDBusPendingReply<QVariantMap> RequestOOB(const QVariantMap &values)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(values);
- return asyncCallWithArgumentList(QStringLiteral("RequestOOB"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
-};
-
-/*
- * Proxy class for interface org.neard.NDEFAgent
- */
-class OrgNeardNDEFAgentInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.neard.NDEFAgent"; }
-
-public:
- OrgNeardNDEFAgentInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
-
- ~OrgNeardNDEFAgentInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<> GetNDEF(const QVariantMap &values)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(values);
- return asyncCallWithArgumentList(QStringLiteral("GetNDEF"), argumentList);
- }
-
- inline QDBusPendingReply<> Release()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("Release"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
-};
-
-namespace org {
- namespace neard {
- typedef ::OrgNeardHandoverAgentInterface HandoverAgent;
- typedef ::OrgNeardNDEFAgentInterface NDEFAgent;
- }
-}
-#endif
diff --git a/src/nfc/neard/dbusobjectmanager.cpp b/src/nfc/neard/dbusobjectmanager.cpp
deleted file mode 100644
index 7b3f8356..00000000
--- a/src/nfc/neard/dbusobjectmanager.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -v dbus-object-manager.xml -p dbusobjectmanager -v
- *
- * 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 "dbusobjectmanager_p.h"
-
-/*
- * Implementation of interface class OrgFreedesktopDBusObjectManagerInterface
- */
-
-OrgFreedesktopDBusObjectManagerInterface::OrgFreedesktopDBusObjectManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgFreedesktopDBusObjectManagerInterface::~OrgFreedesktopDBusObjectManagerInterface()
-{
-}
-
diff --git a/src/nfc/neard/dbusobjectmanager_p.h b/src/nfc/neard/dbusobjectmanager_p.h
deleted file mode 100644
index 64d11449..00000000
--- a/src/nfc/neard/dbusobjectmanager_p.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -v -i neard_helper_p.h org.freedesktop.dbus.objectmanager.xml -p dbusobjectmanager_p -v
- *
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef DBUSOBJECTMANAGER_H_1409928664
-#define DBUSOBJECTMANAGER_H_1409928664
-
-#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 "neard_helper_p.h"
-
-/*
- * Proxy class for interface org.freedesktop.DBus.ObjectManager
- */
-class OrgFreedesktopDBusObjectManagerInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.freedesktop.DBus.ObjectManager"; }
-
-public:
- OrgFreedesktopDBusObjectManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
-
- ~OrgFreedesktopDBusObjectManagerInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<ManagedObjectList> GetManagedObjects()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("GetManagedObjects"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
- void InterfacesAdded(const QDBusObjectPath &object, InterfaceList interfaces);
- void InterfacesRemoved(const QDBusObjectPath &object, const QStringList &interfaces);
-};
-
-namespace org {
- namespace freedesktop {
- namespace DBus {
- typedef ::OrgFreedesktopDBusObjectManagerInterface ObjectManager;
- }
- }
-}
-#endif
diff --git a/src/nfc/neard/dbusproperties.cpp b/src/nfc/neard/dbusproperties.cpp
deleted file mode 100644
index 554b83d6..00000000
--- a/src/nfc/neard/dbusproperties.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -v dbus-properties.xml -p dbusproperties -v
- *
- * 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 "dbusproperties_p.h" // HAND_EDIT
-
-/*
- * Implementation of interface class OrgFreedesktopDBusPropertiesInterface
- */
-
-OrgFreedesktopDBusPropertiesInterface::OrgFreedesktopDBusPropertiesInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgFreedesktopDBusPropertiesInterface::~OrgFreedesktopDBusPropertiesInterface()
-{
-}
-
diff --git a/src/nfc/neard/dbusproperties_p.h b/src/nfc/neard/dbusproperties_p.h
deleted file mode 100644
index ebca6278..00000000
--- a/src/nfc/neard/dbusproperties_p.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -v org.freedesktop.dbus.properties.xml -p dbusproperties_p -v
- *
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef DBUSPROPERTIES_H_1409915780
-#define DBUSPROPERTIES_H_1409915780
-
-#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.freedesktop.DBus.Properties
- */
-class OrgFreedesktopDBusPropertiesInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.freedesktop.DBus.Properties"; }
-
-public:
- OrgFreedesktopDBusPropertiesInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
-
- ~OrgFreedesktopDBusPropertiesInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<QDBusVariant> Get(const QString &interface, const QString &name)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(interface) << QVariant::fromValue(name);
- return asyncCallWithArgumentList(QStringLiteral("Get"), argumentList);
- }
-
- inline QDBusPendingReply<QVariantMap> GetAll(const QString &interface)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(interface);
- return asyncCallWithArgumentList(QStringLiteral("GetAll"), argumentList);
- }
-
- inline QDBusPendingReply<> Set(const QString &interface, const QString &name, const QDBusVariant &value)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(interface) << QVariant::fromValue(name) << QVariant::fromValue(value);
- return asyncCallWithArgumentList(QStringLiteral("Set"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
- void PropertiesChanged(const QString &interface, const QVariantMap &changed_properties, const QStringList &invalidated_properties);
-};
-
-namespace org {
- namespace freedesktop {
- namespace DBus {
- typedef ::OrgFreedesktopDBusPropertiesInterface Properties;
- }
- }
-}
-#endif
diff --git a/src/nfc/neard/manager.cpp b/src/nfc/neard/manager.cpp
deleted file mode 100644
index e1d72c6e..00000000
--- a/src/nfc/neard/manager.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -v org.neard.Manager.xml -p manager_p -v
- *
- * 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 "manager_p.h"
-
-/*
- * Implementation of interface class OrgNeardManagerInterface
- */
-
-OrgNeardManagerInterface::OrgNeardManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgNeardManagerInterface::~OrgNeardManagerInterface()
-{
-}
diff --git a/src/nfc/neard/manager_p.h b/src/nfc/neard/manager_p.h
deleted file mode 100644
index 921c177b..00000000
--- a/src/nfc/neard/manager_p.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -v org.neard.Manager.xml -p manager_p -v
- *
- * qdbusxml2cpp is Copyright (C) 2015 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_1410442485
-#define MANAGER_P_H_1410442485
-
-#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.neard.Manager
- */
-class OrgNeardManagerInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.neard.Manager"; }
-
-public:
- OrgNeardManagerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
-
- ~OrgNeardManagerInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<QVariantMap> GetProperties()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("GetProperties"), argumentList);
- }
-
- inline QDBusPendingReply<> RegisterHandoverAgent(const QDBusObjectPath &path)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(path);
- return asyncCallWithArgumentList(QStringLiteral("RegisterHandoverAgent"), argumentList);
- }
-
- inline QDBusPendingReply<> RegisterNDEFAgent(const QDBusObjectPath &path, const QString &type)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(path) << QVariant::fromValue(type);
- return asyncCallWithArgumentList(QStringLiteral("RegisterNDEFAgent"), argumentList);
- }
-
- inline QDBusPendingReply<> SetProperty(const QString &name, const QDBusVariant &value)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(name) << QVariant::fromValue(value);
- return asyncCallWithArgumentList(QStringLiteral("SetProperty"), argumentList);
- }
-
- inline QDBusPendingReply<> UnregisterHandoverAgent(const QDBusObjectPath &path)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(path);
- return asyncCallWithArgumentList(QStringLiteral("UnregisterHandoverAgent"), argumentList);
- }
-
- inline QDBusPendingReply<> UnregisterNDEFAgent(const QDBusObjectPath &path, const QString &type)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(path) << QVariant::fromValue(type);
- return asyncCallWithArgumentList(QStringLiteral("UnregisterNDEFAgent"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
- void AdapterAdded(const QDBusObjectPath &adapter);
- void AdapterRemoved(const QDBusObjectPath &adapter);
- void PropertyChanged(const QString &name, const QDBusVariant &value);
-};
-
-namespace org {
- namespace neard {
- typedef ::OrgNeardManagerInterface Manager;
- }
-}
-#endif
diff --git a/src/nfc/neard/neard.pri b/src/nfc/neard/neard.pri
deleted file mode 100644
index 8120a784..00000000
--- a/src/nfc/neard/neard.pri
+++ /dev/null
@@ -1,22 +0,0 @@
-HEADERS += neard/adapter_p.h \
- neard/manager_p.h \
- neard/tag_p.h \
- neard/agent_p.h \
- neard/dbusproperties_p.h \
- neard/dbusobjectmanager_p.h \
- neard/neard_helper_p.h
-
-SOURCES += neard/adapter.cpp \
- neard/manager.cpp \
- neard/tag.cpp \
- neard/agent.cpp \
- neard/dbusproperties.cpp \
- neard/dbusobjectmanager.cpp \
- neard/neard_helper.cpp
-
-OTHER_FILES += neard/org.freedesktop.dbus.objectmanager.xml \
- neard/org.freedesktop.dbus.properties.xml \
- neard/org.neard.Adapter.xml \
- neard/org.neard.Agent.xml \
- neard/org.neard.Manager.xml \
- neard/org.neard.Tag.xml
diff --git a/src/nfc/neard/neard_dbus_types_p.h b/src/nfc/neard/neard_dbus_types_p.h
new file mode 100644
index 00000000..b85b3252
--- /dev/null
+++ b/src/nfc/neard/neard_dbus_types_p.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 BasysKom GmbH.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef NEARD_DBUS_TYPES_P_H
+#define NEARD_DBUS_TYPES_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 <QMetaType>
+#include <QDBusObjectPath>
+
+typedef QMap<QString, QVariantMap> InterfaceList;
+typedef QMap<QDBusObjectPath, InterfaceList> ManagedObjectList;
+
+Q_DECLARE_METATYPE(InterfaceList)
+Q_DECLARE_METATYPE(ManagedObjectList)
+
+#endif // NEARD_DBUS_TYPES_P_H
diff --git a/src/nfc/neard/neard_helper.cpp b/src/nfc/neard/neard_helper.cpp
index 90781a5b..3cd65bab 100644
--- a/src/nfc/neard/neard_helper.cpp
+++ b/src/nfc/neard/neard_helper.cpp
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 BasysKom GmbH.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 BasysKom GmbH.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QDBusMetaType>
#include "neard_helper_p.h"
-#include "dbusobjectmanager_p.h"
+#include "objectmanager_interface.h"
QT_BEGIN_NAMESPACE
diff --git a/src/nfc/neard/neard_helper_p.h b/src/nfc/neard/neard_helper_p.h
index e3258d5d..9964e547 100644
--- a/src/nfc/neard/neard_helper_p.h
+++ b/src/nfc/neard/neard_helper_p.h
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 BasysKom GmbH.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 BasysKom GmbH.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef NEARD_HELPER_P_H
#define NEARD_HELPER_P_H
@@ -52,14 +16,7 @@
// We mean it.
//
-#include <QMetaType>
-#include <QDBusObjectPath>
-
-typedef QMap<QString, QVariantMap> InterfaceList;
-typedef QMap<QDBusObjectPath, InterfaceList> ManagedObjectList;
-
-Q_DECLARE_METATYPE(InterfaceList)
-Q_DECLARE_METATYPE(ManagedObjectList)
+#include "neard_dbus_types_p.h"
class OrgFreedesktopDBusObjectManagerInterface;
diff --git a/src/nfc/neard/org.freedesktop.dbus.objectmanager.xml b/src/nfc/neard/org.freedesktop.dbus.objectmanager.xml
index ae16f410..43427725 100644
--- a/src/nfc/neard/org.freedesktop.dbus.objectmanager.xml
+++ b/src/nfc/neard/org.freedesktop.dbus.objectmanager.xml
@@ -9,7 +9,7 @@
<signal name="InterfacesAdded">
<arg name="object" type="o"/>
<arg name="interfaces" type="a{sa{sv}}"/>
- <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="InterfaceList"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="InterfaceList"/>
</signal>
<signal name="InterfacesRemoved">
<arg name="object" type="o"/>
diff --git a/src/nfc/neard/org.freedesktop.dbus.properties.xml b/src/nfc/neard/org.freedesktop.dbus.properties.xml
index 1449d567..6e22c586 100644
--- a/src/nfc/neard/org.freedesktop.dbus.properties.xml
+++ b/src/nfc/neard/org.freedesktop.dbus.properties.xml
@@ -20,7 +20,7 @@
<signal name="PropertiesChanged">
<arg name="interface" type="s"/>
<arg name="changed_properties" type="a{sv}"/>
- <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
+ <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
<arg name="invalidated_properties" type="as"/>
</signal>
</interface>
diff --git a/src/nfc/neard/org.neard.Agent.xml b/src/nfc/neard/org.neard.Agent.xml
deleted file mode 100644
index 5ec0e487..00000000
--- a/src/nfc/neard/org.neard.Agent.xml
+++ /dev/null
@@ -1,26 +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.neard.NDEFAgent">
- <method name="GetNDEF">
- <arg name="values" type="a{sv}" direction="in"/>
- <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
- </method>
- <method name="Release">
- </method>
- </interface>
- <interface name="org.neard.HandoverAgent">
- <method name="RequestOOB">
- <arg name="values" type="a{sv}" direction="in"/>
- <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
- <arg name="result" type="a{sv}" direction="out"/>
- <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
- </method>
- <method name="PushOOB">
- <arg name="values" type="a{sv}" direction="in"/>
- <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
- </method>
- <method name="Release">
- </method>
- </interface>
-</node>
diff --git a/src/nfc/neard/org.neard.Manager.xml b/src/nfc/neard/org.neard.Manager.xml
deleted file mode 100644
index 1ed92378..00000000
--- a/src/nfc/neard/org.neard.Manager.xml
+++ /dev/null
@@ -1,38 +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.neard.Manager">
- <method name="GetProperties">
- <arg name="properties" type="a{sv}" direction="out"/>
- <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
- </method>
- <method name="SetProperty">
- <arg name="name" type="s" direction="in"/>
- <arg name="value" type="v" direction="in"/>
- </method>
- <method name="RegisterHandoverAgent">
- <arg name="path" type="o" direction="in"/>
- </method>
- <method name="UnregisterHandoverAgent">
- <arg name="path" type="o" direction="in"/>
- </method>
- <method name="RegisterNDEFAgent">
- <arg name="path" type="o" direction="in"/>
- <arg name="type" type="s" direction="in"/>
- </method>
- <method name="UnregisterNDEFAgent">
- <arg name="path" type="o" direction="in"/>
- <arg name="type" type="s" direction="in"/>
- </method>
- <signal name="PropertyChanged">
- <arg name="name" type="s"/>
- <arg name="value" type="v"/>
- </signal>
- <signal name="AdapterAdded">
- <arg name="adapter" type="o"/>
- </signal>
- <signal name="AdapterRemoved">
- <arg name="adapter" type="o"/>
- </signal>
- </interface>
-</node>
diff --git a/src/nfc/neard/tag.cpp b/src/nfc/neard/tag.cpp
deleted file mode 100644
index 918f7f2d..00000000
--- a/src/nfc/neard/tag.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -v org.neard.Tag.xml -p tag_p -v
- *
- * 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 "tag_p.h"
-
-/*
- * Implementation of interface class OrgNeardTagInterface
- */
-
-OrgNeardTagInterface::OrgNeardTagInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
- : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
-{
-}
-
-OrgNeardTagInterface::~OrgNeardTagInterface()
-{
-}
diff --git a/src/nfc/neard/tag_p.h b/src/nfc/neard/tag_p.h
deleted file mode 100644
index c9a3aad3..00000000
--- a/src/nfc/neard/tag_p.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * This file was generated by qdbusxml2cpp version 0.8
- * Command line was: qdbusxml2cpp -v org.neard.Tag.xml -p tag_p -v
- *
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
- *
- * This is an auto-generated file.
- * Do not edit! All changes made to it will be lost.
- */
-
-#ifndef TAG_P_H_1410941369
-#define TAG_P_H_1410941369
-
-#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.neard.Tag
- */
-class OrgNeardTagInterface: public QDBusAbstractInterface
-{
- Q_OBJECT
-public:
- static inline const char *staticInterfaceName()
- { return "org.neard.Tag"; }
-
-public:
- OrgNeardTagInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
-
- ~OrgNeardTagInterface();
-
-public Q_SLOTS: // METHODS
- inline QDBusPendingReply<QByteArray> GetRawNDEF()
- {
- QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QStringLiteral("GetRawNDEF"), argumentList);
- }
-
- inline QDBusPendingReply<> Write(const QVariantMap &attributes)
- {
- QList<QVariant> argumentList;
- argumentList << QVariant::fromValue(attributes);
- return asyncCallWithArgumentList(QStringLiteral("Write"), argumentList);
- }
-
-Q_SIGNALS: // SIGNALS
-};
-
-namespace org {
- namespace neard {
- typedef ::OrgNeardTagInterface Tag;
- }
-}
-#endif
diff --git a/src/nfc/nfc.pro b/src/nfc/nfc.pro
deleted file mode 100644
index c6ae147d..00000000
--- a/src/nfc/nfc.pro
+++ /dev/null
@@ -1,134 +0,0 @@
-TARGET = QtNfc
-QT = core
-DEFINES += QT_NO_FOREACH
-
-QMAKE_DOCS = $$PWD/doc/qtnfc.qdocconf
-OTHER_FILES += doc/src/*.qdoc # show .qdoc files in Qt Creator
-
-HEADERS += \
- qtnfcglobal.h \
- qnearfieldmanager.h \
- qnearfieldtarget.h \
- qndefrecord.h \
- qndefnfctextrecord.h \
- qndefmessage.h \
- qndeffilter.h \
- qndefnfcurirecord.h \
- qqmlndefrecord.h \
- qndefnfcsmartposterrecord.h \
- qnearfieldsharemanager.h \
- qnearfieldsharetarget.h \
- qtnfcglobal_p.h \
- qllcpsocket_p.h \
- qllcpserver_p.h \
- qndefrecord_p.h \
- qnearfieldtarget_p.h \
- qnearfieldmanager_p.h \
- qnearfieldtagtype1_p.h \
- qnearfieldtagtype2_p.h \
- qnearfieldtagtype3_p.h \
- qnearfieldtagtype4_p.h \
- qtlv_p.h \
- qndefnfcsmartposterrecord_p.h \
- qnearfieldsharemanager_p.h \
- qnearfieldsharetarget_p.h
-
-SOURCES += \
- qnearfieldmanager.cpp \
- qnearfieldtarget.cpp \
- qndefrecord.cpp \
- qndefnfctextrecord.cpp \
- qndefmessage.cpp \
- qndeffilter.cpp \
- qndefnfcurirecord.cpp \
- qnearfieldtagtype1.cpp \
- qnearfieldtagtype2.cpp \
- qnearfieldtagtype3.cpp \
- qllcpsocket.cpp \
- qnearfieldtagtype4.cpp \
- qtlv.cpp \
- qllcpserver.cpp \
- qqmlndefrecord.cpp \
- qndefnfcsmartposterrecord.cpp \
- qnearfieldsharemanager.cpp \
- qnearfieldsharetarget.cpp \
- qnfc.cpp
-
-linux:!android:qtHaveModule(dbus) {
- NFC_BACKEND_AVAILABLE = yes
-
- QT_PRIVATE += dbus
-
- DEFINES += NEARD_NFC
-
- HEADERS += \
- qllcpsocket_p_p.h \
- qllcpserver_p_p.h \
- qnearfieldmanager_neard_p.h \
- qnearfieldsharemanagerimpl_p.h \
- qnearfieldsharetargetimpl_p.h \
- qnearfieldtarget_neard_p.h
-
- SOURCES += \
- qllcpsocket_p.cpp \
- qllcpserver_p.cpp \
- qnearfieldsharemanagerimpl_p.cpp \
- qnearfieldsharetargetimpl_p.cpp \
- qnearfieldmanager_neard.cpp \
- qnearfieldtarget_neard_p.cpp
-
- include(neard/neard.pri)
-
-} else:android:!android-embedded {
- NFC_BACKEND_AVAILABLE = yes
- DEFINES += QT_ANDROID_NFC
- ANDROID_PERMISSIONS = \
- android.permission.NFC
- ANDROID_BUNDLED_JAR_DEPENDENCIES = \
- jar/QtNfc.jar:org.qtproject.qt5.android.nfc.QtNfc
- DEFINES += ANDROID_NFC
- QT_PRIVATE += core-private gui androidextras
-
- HEADERS += \
- qllcpserver_android_p.h \
- qllcpsocket_android_p.h \
- android/androidjninfc_p.h \
- qnearfieldmanager_android_p.h \
- qnearfieldtarget_android_p.h \
- qnearfieldsharemanagerimpl_p.h \
- qnearfieldsharetargetimpl_p.h \
- android/androidmainnewintentlistener_p.h
-
-
- SOURCES += \
- qllcpserver_android_p.cpp \
- qllcpsocket_android_p.cpp \
- android/androidjninfc.cpp \
- qnearfieldmanager_android.cpp \
- qnearfieldtarget_android.cpp \
- qnearfieldtarget_android_p.cpp \
- qnearfieldsharemanagerimpl_p.cpp \
- qnearfieldsharetargetimpl_p.cpp \
- android/androidmainnewintentlistener.cpp
-}
-
-isEmpty(NFC_BACKEND_AVAILABLE) {
- message("Unsupported NFC platform, will not build a working QtNfc library.")
-
- HEADERS += \
- qllcpsocket_p_p.h \
- qllcpserver_p_p.h \
- qnearfieldmanagerimpl_p.h \
- qnearfieldsharemanagerimpl_p.h \
- qnearfieldsharetargetimpl_p.h
-
- SOURCES += \
- qllcpsocket_p.cpp \
- qllcpserver_p.cpp \
- qnearfieldmanagerimpl_p.cpp \
- qnearfieldsharemanagerimpl_p.cpp \
- qnearfieldsharetargetimpl_p.cpp \
- qnearfieldtarget_p.cpp
-}
-
-load(qt_module)
diff --git a/src/nfc/pcsc/qpcsc.cpp b/src/nfc/pcsc/qpcsc.cpp
new file mode 100644
index 00000000..ec8bdd23
--- /dev/null
+++ b/src/nfc/pcsc/qpcsc.cpp
@@ -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
+
+#include "qpcsc_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+namespace QPcsc {
+
+QString errorMessage(LONG error)
+{
+#ifdef Q_OS_WIN
+ return (u"0x%1"_s).arg(error, 8, 16, QLatin1Char('0'));
+#else
+ return QString::fromUtf8(pcsc_stringify_error(error));
+#endif
+}
+
+} // namespace QPcsc
+
+qsizetype QPcscSlotName::nameSize(QPcscSlotName::CPtr p)
+{
+#ifdef Q_OS_WIN
+ return wcslen(p);
+#else
+ return strlen(p);
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/pcsc/qpcsc_p.h b/src/nfc/pcsc/qpcsc_p.h
new file mode 100644
index 00000000..fba1085f
--- /dev/null
+++ b/src/nfc/pcsc/qpcsc_p.h
@@ -0,0 +1,72 @@
+// 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 QPCSC_P_H
+#define QPCSC_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.
+//
+
+#ifdef Q_OS_WIN
+# include <qt_windows.h>
+#endif
+#include <QtCore/QtGlobal>
+#ifdef Q_OS_DARWIN
+# include <PCSC/winscard.h>
+# include <PCSC/wintypes.h>
+#else
+# include <winscard.h>
+#endif
+#include <QtCore/QByteArray>
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+
+namespace QPcsc {
+struct RawCommandResult
+{
+ LONG ret = SCARD_E_READER_UNAVAILABLE;
+ QByteArray response;
+
+ bool isOk() const { return ret == SCARD_S_SUCCESS; }
+};
+
+QString errorMessage(LONG error);
+
+} // namespace QPcsc
+
+class QPcscSlotName : public
+#ifdef Q_OS_WIN
+ QString
+#else
+ QByteArray
+#endif
+{
+public:
+#ifdef Q_OS_WIN
+ using CPtr = LPCWSTR;
+ using Ptr = LPWSTR;
+ explicit QPcscSlotName(CPtr p) : QString(reinterpret_cast<const QChar *>(p)) { }
+#else
+ using CPtr = LPCSTR;
+ using Ptr = LPSTR;
+ explicit QPcscSlotName(CPtr p) : QByteArray(p) { }
+#endif
+
+ CPtr ptr() const noexcept { return reinterpret_cast<CPtr>(constData()); }
+ Ptr ptr() { return reinterpret_cast<Ptr>(data()); }
+
+ static qsizetype nameSize(CPtr p);
+};
+
+QT_END_NAMESPACE
+
+#endif // QPCSC_P_H
diff --git a/src/nfc/pcsc/qpcsccard.cpp b/src/nfc/pcsc/qpcsccard.cpp
new file mode 100644
index 00000000..e06ac6f0
--- /dev/null
+++ b/src/nfc/pcsc/qpcsccard.cpp
@@ -0,0 +1,419 @@
+// 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 "qpcsccard_p.h"
+#include "ndef/qnfctagtype4ndeffsm_p.h"
+#include "qapduutils_p.h"
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QTimer>
+
+#if defined(Q_OS_DARWIN)
+# define SCARD_ATTR_MAXINPUT 0x0007A007
+#elif !defined(Q_OS_WIN)
+# include <reader.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_NFC_PCSC)
+
+/*
+ Windows SCardBeginTransaction() documentation says the following:
+
+ If a transaction is held on the card for more than five seconds with no
+ operations happening on that card, then the card is reset. Calling any
+ of the Smart Card and Reader Access Functions or Direct Card Access
+ Functions on the card that is transacted results in the timer being
+ reset to continue allowing the transaction to be used.
+
+ We use a timer to ensure that transactions do not timeout unexpectedly.
+*/
+static constexpr int KeepAliveIntervalMs = 2500;
+
+/*
+ Start a temporary transaction if a persistent transaction was not already
+ started due to call to onSendCommandRequest().
+
+ If a temporary transaction was initiated, it is ended when this object is
+ destroyed.
+*/
+QPcscCard::Transaction::Transaction(QPcscCard *card) : m_card(card)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+ if (!m_card->isValid() || m_card->m_inAutoTransaction)
+ return;
+
+ auto ret = SCardBeginTransaction(m_card->m_handle);
+ if (ret != SCARD_S_SUCCESS) {
+ qCWarning(QT_NFC_PCSC) << "SCardBeginTransaction failed:" << QPcsc::errorMessage(ret);
+ m_card->invalidate();
+ return;
+ }
+
+ m_initiated = true;
+}
+
+QPcscCard::Transaction::~Transaction()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+ if (!m_initiated || !m_card->isValid())
+ return;
+
+ auto ret = SCardEndTransaction(m_card->m_handle, SCARD_LEAVE_CARD);
+
+ if (ret != SCARD_S_SUCCESS) {
+ qCWarning(QT_NFC_PCSC) << "SCardEndTransaction failed:" << QPcsc::errorMessage(ret);
+ m_card->invalidate();
+ }
+}
+
+QPcscCard::QPcscCard(SCARDHANDLE handle, DWORD protocol, QObject *parent)
+ : QObject(parent), m_handle(handle)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ m_keepAliveTimer = new QTimer(this);
+ m_keepAliveTimer->setInterval(KeepAliveIntervalMs);
+ connect(m_keepAliveTimer, &QTimer::timeout, this, &QPcscCard::onKeepAliveTimeout);
+
+ m_ioPci.dwProtocol = protocol;
+ m_ioPci.cbPciLength = sizeof(m_ioPci);
+
+ // Assume that everything is NFC Tag Type 4 for now
+ m_tagDetectionFsm = std::make_unique<QNfcTagType4NdefFsm>();
+
+ performNdefDetection();
+}
+
+QPcscCard::~QPcscCard()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+ invalidate();
+}
+
+void QPcscCard::performNdefDetection()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ if (!m_isValid)
+ return;
+
+ Transaction transaction(this);
+
+ auto action = m_tagDetectionFsm->detectNdefSupport();
+
+ while (action == QNdefAccessFsm::SendCommand) {
+ auto command = m_tagDetectionFsm->getCommand(action);
+
+ if (action == QNdefAccessFsm::ProvideResponse) {
+ auto result = sendCommand(command, NoAutoTransaction);
+ action = m_tagDetectionFsm->provideResponse(result.response);
+ }
+ }
+
+ qCDebug(QT_NFC_PCSC) << "NDEF detection result" << action;
+
+ m_supportsNdef = action == QNdefAccessFsm::Done;
+ qCDebug(QT_NFC_PCSC) << "NDEF supported:" << m_supportsNdef;
+}
+
+/*
+ Release the resource associated with the card and notify the NFC target
+ about disconnection. The card is deleted when automatic deletion is enabled.
+*/
+void QPcscCard::invalidate()
+{
+ if (!m_isValid)
+ return;
+
+ SCardDisconnect(m_handle, m_inAutoTransaction ? SCARD_RESET_CARD : SCARD_LEAVE_CARD);
+
+ m_isValid = false;
+ m_inAutoTransaction = false;
+
+ Q_EMIT disconnected();
+ Q_EMIT invalidated();
+
+ if (m_autodelete)
+ deleteLater();
+}
+
+/*
+ Send the given command to the card.
+
+ Start an automatic transaction if autoTransaction is StartAutoTransaction
+ and it is not already started. This automatic transaction lasts until the
+ invalidate() or onDisconnectRequest() is called.
+
+ The automatic transaction is used to ensure that other applications do not
+ interfere with commands sent by the user application.
+
+ If autoTransaction is NoAutoTransaction, then the calling code should ensure
+ that either the command is atomic or that a temporary transaction is started
+ using Transaction object.
+*/
+QPcsc::RawCommandResult QPcscCard::sendCommand(const QByteArray &command,
+ QPcscCard::AutoTransaction autoTransaction)
+{
+ if (!m_isValid)
+ return {};
+
+ if (!m_inAutoTransaction && autoTransaction == StartAutoTransaction) {
+ qCDebug(QT_NFC_PCSC) << "Starting transaction";
+
+ // FIXME: Is there a timeout on this?
+ auto ret = SCardBeginTransaction(m_handle);
+ if (ret != SCARD_S_SUCCESS) {
+ qCWarning(QT_NFC_PCSC) << "SCardBeginTransaction failed:" << QPcsc::errorMessage(ret);
+ invalidate();
+ return {};
+ }
+ m_inAutoTransaction = true;
+ m_keepAliveTimer->start();
+ }
+
+ QPcsc::RawCommandResult result;
+ result.response.resize(0xFFFF + 2);
+ DWORD recvLength = result.response.size();
+
+ qCDebug(QT_NFC_PCSC) << "TX:" << command.toHex(':');
+
+ result.ret = SCardTransmit(m_handle, &m_ioPci, reinterpret_cast<LPCBYTE>(command.constData()),
+ command.size(), nullptr,
+ reinterpret_cast<LPBYTE>(result.response.data()), &recvLength);
+ if (result.ret != SCARD_S_SUCCESS) {
+ qCWarning(QT_NFC_PCSC) << "SCardTransmit failed:" << QPcsc::errorMessage(result.ret);
+ result.response.clear();
+ invalidate();
+ } else {
+ result.response.resize(recvLength);
+ qCDebug(QT_NFC_PCSC) << "RX:" << result.response.toHex(':');
+ }
+
+ return result;
+}
+
+void QPcscCard::onKeepAliveTimeout()
+{
+ if (!m_isValid || !m_inAutoTransaction) {
+ m_keepAliveTimer->stop();
+ return;
+ }
+
+ checkCardPresent();
+}
+
+QByteArray QPcscCard::readUid()
+{
+ QByteArray command = QCommandApdu::build(0xFF, QCommandApdu::GetData, 0x00, 0x00, {}, 256);
+
+ // Atomic command, no need for transaction.
+ QResponseApdu res(sendCommand(command, NoAutoTransaction).response);
+ if (!res.isOk())
+ return {};
+ return res.data();
+}
+
+void QPcscCard::onReadNdefMessagesRequest(const QNearFieldTarget::RequestId &request)
+{
+ if (!m_isValid) {
+ Q_EMIT requestCompleted(request, QNearFieldTarget::ConnectionError, {});
+ return;
+ }
+
+ if (!m_supportsNdef) {
+ Q_EMIT requestCompleted(request, QNearFieldTarget::UnsupportedError, {});
+ return;
+ }
+
+ Transaction transaction(this);
+
+ QList<QNdefMessage> messages;
+
+ auto nextState = m_tagDetectionFsm->readMessages();
+
+ while (true) {
+ if (nextState == QNdefAccessFsm::SendCommand) {
+ auto command = m_tagDetectionFsm->getCommand(nextState);
+
+ if (nextState == QNdefAccessFsm::ProvideResponse) {
+ auto result = sendCommand(command, NoAutoTransaction);
+ nextState = m_tagDetectionFsm->provideResponse(result.response);
+ }
+ } else if (nextState == QNdefAccessFsm::GetMessage) {
+ auto message = m_tagDetectionFsm->getMessage(nextState);
+ Q_EMIT ndefMessageRead(message);
+ } else {
+ break;
+ }
+ }
+
+ qCDebug(QT_NFC_PCSC) << "Final state:" << nextState;
+ auto errorCode = (nextState == QNdefAccessFsm::Done) ? QNearFieldTarget::NoError
+ : QNearFieldTarget::NdefReadError;
+ Q_EMIT requestCompleted(request, errorCode, {});
+}
+
+/*
+ Ends the persistent transaction and resets the card if sendCommand() was
+ used by user.
+
+ Resetting the card ensures that the current state of the card does not get
+ shared with other processes.
+*/
+void QPcscCard::onDisconnectRequest()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ if (!m_isValid)
+ return;
+
+ LONG ret;
+ if (m_inAutoTransaction) {
+ // NOTE: PCSCLite does not automatically release transaction in
+ // SCardReconnect(): https://salsa.debian.org/rousseau/PCSC/-/issues/11
+ ret = SCardEndTransaction(m_handle, SCARD_RESET_CARD);
+ if (ret != SCARD_S_SUCCESS) {
+ qCWarning(QT_NFC_PCSC) << "SCardEndTransaction failed:" << QPcsc::errorMessage(ret);
+ invalidate();
+ return;
+ }
+
+ m_inAutoTransaction = false;
+ }
+
+ DWORD activeProtocol;
+ ret = SCardReconnect(m_handle, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
+ SCARD_LEAVE_CARD, &activeProtocol);
+ if (ret != SCARD_S_SUCCESS) {
+ qCWarning(QT_NFC_PCSC) << "SCardReconnect failed:" << QPcsc::errorMessage(ret);
+ invalidate();
+ return;
+ }
+
+ Q_EMIT disconnected();
+}
+
+void QPcscCard::onTargetDestroyed()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+ invalidate();
+}
+
+void QPcscCard::onSendCommandRequest(const QNearFieldTarget::RequestId &request,
+ const QByteArray &command)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ if (!m_isValid) {
+ Q_EMIT requestCompleted(request, QNearFieldTarget::ConnectionError, {});
+ return;
+ }
+
+ auto result = sendCommand(command, StartAutoTransaction);
+ if (result.isOk())
+ Q_EMIT requestCompleted(request, QNearFieldTarget::NoError, result.response);
+ else
+ Q_EMIT requestCompleted(request, QNearFieldTarget::CommandError, {});
+}
+
+void QPcscCard::onWriteNdefMessagesRequest(const QNearFieldTarget::RequestId &request,
+ const QList<QNdefMessage> &messages)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ if (!m_isValid) {
+ Q_EMIT requestCompleted(request, QNearFieldTarget::ConnectionError, {});
+ return;
+ }
+
+ if (!m_supportsNdef) {
+ Q_EMIT requestCompleted(request, QNearFieldTarget::UnsupportedError, {});
+ return;
+ }
+
+ Transaction transaction(this);
+
+ auto nextState = m_tagDetectionFsm->writeMessages(messages);
+
+ while (nextState == QNdefAccessFsm::SendCommand) {
+ auto command = m_tagDetectionFsm->getCommand(nextState);
+ if (nextState == QNdefAccessFsm::ProvideResponse) {
+ auto result = sendCommand(command, NoAutoTransaction);
+ nextState = m_tagDetectionFsm->provideResponse(result.response);
+ }
+ }
+
+ auto errorCode = (nextState == QNdefAccessFsm::Done) ? QNearFieldTarget::NoError
+ : QNearFieldTarget::NdefWriteError;
+ Q_EMIT requestCompleted(request, errorCode, {});
+}
+
+/*
+ Enable automatic card deletion when the connection is closed by the user
+ or the card otherwise becomes unavailable.
+
+ The automatic deletion is prevented initially so that
+ QNearFieldManagerPrivate can safely establish connections between this
+ object and a QNearFieldTargetPrivate proxy.
+*/
+void QPcscCard::enableAutodelete()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ m_autodelete = true;
+ if (!m_isValid)
+ deleteLater();
+}
+
+/*
+ Check if the card is still present in the reader.
+
+ Invalidates the object if card is not present.
+*/
+bool QPcscCard::checkCardPresent()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ if (!m_isValid)
+ return false;
+
+ DWORD state;
+ auto ret = SCardStatus(m_handle, nullptr, nullptr, &state, nullptr, nullptr, nullptr);
+ if (ret != SCARD_S_SUCCESS) {
+ qCWarning(QT_NFC_PCSC) << "SCardStatus failed:" << QPcsc::errorMessage(ret);
+ invalidate();
+ return false;
+ }
+
+ qCDebug(QT_NFC_PCSC) << "State:" << Qt::hex << state;
+
+ return (state & SCARD_PRESENT) != 0;
+}
+
+int QPcscCard::readMaxInputLength()
+{
+ if (!m_isValid)
+ return 0;
+
+ // Maximum standard APDU length
+ static constexpr int DefaultMaxInputLength = 261;
+
+ uint32_t maxInput;
+ DWORD attrSize = sizeof(maxInput);
+ auto ret = SCardGetAttrib(m_handle, SCARD_ATTR_MAXINPUT, reinterpret_cast<LPBYTE>(&maxInput),
+ &attrSize);
+ if (ret != SCARD_S_SUCCESS) {
+ qCDebug(QT_NFC_PCSC) << "SCardGetAttrib failed:" << QPcsc::errorMessage(ret);
+ return DefaultMaxInputLength;
+ }
+
+ if (attrSize != sizeof(maxInput)) {
+ qCWarning(QT_NFC_PCSC) << "Unexpected attribute size for SCARD_ATTR_MAXINPUT:" << attrSize;
+ return DefaultMaxInputLength;
+ }
+
+ return static_cast<int>(maxInput);
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/pcsc/qpcsccard_p.h b/src/nfc/pcsc/qpcsccard_p.h
new file mode 100644
index 00000000..0fe580e2
--- /dev/null
+++ b/src/nfc/pcsc/qpcsccard_p.h
@@ -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
+
+#ifndef QPCSCCARD_P_H
+#define QPCSCCARD_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 "qpcsc_p.h"
+#include "qndefmessage.h"
+#include "qnearfieldtarget.h"
+#include "ndef/qndefaccessfsm_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QTimer;
+
+class QPcscCard : public QObject
+{
+ Q_OBJECT
+public:
+ QPcscCard(SCARDHANDLE handle, DWORD protocol, QObject *parent = nullptr);
+ ~QPcscCard();
+
+ bool isValid() const { return m_isValid; }
+ void invalidate();
+
+ bool checkCardPresent();
+ Q_INVOKABLE void enableAutodelete();
+
+ QByteArray readUid();
+ int readMaxInputLength();
+
+ bool supportsNdef() const { return m_supportsNdef; }
+
+private:
+ SCARDHANDLE m_handle;
+ SCARD_IO_REQUEST m_ioPci;
+ bool m_isValid = true;
+ bool m_supportsNdef;
+ bool m_autodelete = false;
+ // Indicates that an _automatic_ transaction was started
+ bool m_inAutoTransaction = false;
+ QTimer *m_keepAliveTimer;
+
+ std::unique_ptr<QNdefAccessFsm> m_tagDetectionFsm;
+
+ enum AutoTransaction { NoAutoTransaction, StartAutoTransaction };
+
+ QPcsc::RawCommandResult sendCommand(const QByteArray &command, AutoTransaction autoTransaction);
+ void performNdefDetection();
+
+ class Transaction
+ {
+ public:
+ Transaction(QPcscCard *card);
+ ~Transaction();
+
+ private:
+ QPcscCard *m_card;
+ bool m_initiated = false;
+ };
+
+public Q_SLOTS:
+ void onDisconnectRequest();
+ void onTargetDestroyed();
+ void onSendCommandRequest(const QNearFieldTarget::RequestId &request,
+ const QByteArray &command);
+ void onReadNdefMessagesRequest(const QNearFieldTarget::RequestId &request);
+ void onWriteNdefMessagesRequest(const QNearFieldTarget::RequestId &request,
+ const QList<QNdefMessage> &messages);
+
+private Q_SLOTS:
+ void onKeepAliveTimeout();
+
+Q_SIGNALS:
+ void disconnected();
+ void invalidated();
+
+ void requestCompleted(const QNearFieldTarget::RequestId &request,
+ QNearFieldTarget::Error reason, const QVariant &result);
+ void ndefMessageRead(const QNdefMessage &message);
+};
+
+QT_END_NAMESPACE
+
+#endif // QPCSCCARD_P_H
diff --git a/src/nfc/pcsc/qpcscmanager.cpp b/src/nfc/pcsc/qpcscmanager.cpp
new file mode 100644
index 00000000..f5b358a5
--- /dev/null
+++ b/src/nfc/pcsc/qpcscmanager.cpp
@@ -0,0 +1,357 @@
+// 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 "qpcscmanager_p.h"
+#include "qpcscslot_p.h"
+#include "qpcsccard_p.h"
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QThread>
+#include <QtCore/QTimer>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_NFC_PCSC)
+
+static constexpr auto PollIntervalEnvVar = "QT_NFC_POLL_INTERVAL_MS";
+static constexpr int DefaultPollIntervalMs = 100;
+
+QPcscManager::QPcscManager(QObject *parent) : QObject(parent)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ int pollInterval = DefaultPollIntervalMs;
+ QByteArray intervalEnv = qgetenv(PollIntervalEnvVar);
+ if (!intervalEnv.isEmpty()) {
+ if (int intervalFromEnv = intervalEnv.toInt(); intervalFromEnv > 0)
+ pollInterval = intervalFromEnv;
+ else
+ qCWarning(QT_NFC_PCSC) << PollIntervalEnvVar << "set to an invalid value";
+ }
+
+ m_stateUpdateTimer = new QTimer(this);
+ m_stateUpdateTimer->setInterval(pollInterval);
+ connect(m_stateUpdateTimer, &QTimer::timeout, this, &QPcscManager::onStateUpdate);
+}
+
+QPcscManager::~QPcscManager()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+ if (m_hasContext) {
+ // Destroy all card handles before destroying the PCSC context.
+ for (auto slot : std::as_const(m_slots))
+ slot->invalidateInsertedCard();
+ SCardReleaseContext(m_context);
+ }
+
+ // Stop the worker thread.
+ thread()->quit();
+}
+
+void QPcscManager::processSlotUpdates()
+{
+ for (auto &state : m_slotStates) {
+ auto slot = static_cast<QPcscSlot *>(state.pvUserData);
+ Q_ASSERT(slot != nullptr);
+
+ if ((state.dwEventState & SCARD_STATE_UNKNOWN) != 0)
+ continue;
+
+ if (state.dwEventState == state.dwCurrentState)
+ continue;
+
+ qCDebug(QT_NFC_PCSC) << Qt::hex << state.dwCurrentState << "=>" << state.dwEventState << ":"
+ << slot->name();
+
+ state.dwCurrentState = state.dwEventState;
+ slot->processStateChange(state.dwEventState, m_targetDetectionRunning);
+ }
+}
+
+/*
+ Remove slots that no longer need to be tracked.
+*/
+void QPcscManager::removeSlots()
+{
+ for (auto &state : m_slotStates) {
+ auto slot = static_cast<QPcscSlot *>(state.pvUserData);
+ Q_ASSERT(slot != nullptr);
+
+ // Remove slots that no longer exist, or all slots without cards if
+ // target detection is stopped.
+ if ((state.dwEventState & SCARD_STATE_UNKNOWN) != 0
+ || !(m_targetDetectionRunning || slot->hasCard())) {
+ qCDebug(QT_NFC_PCSC) << "Removing slot:" << slot;
+ state.dwEventState = SCARD_STATE_UNKNOWN;
+ slot->invalidateInsertedCard();
+ m_slots.remove(slot->name());
+ slot->deleteLater();
+ state.pvUserData = nullptr;
+ }
+ }
+
+ // Remove state tracking entries for slots that no longer exist.
+ m_slotStates.removeIf(
+ [](const auto &state) { return (state.dwEventState & SCARD_STATE_UNKNOWN) != 0; });
+}
+
+/*
+ Reads the system slot lists and marks slots that no longer exists, also
+ creates new slot entries if target detection is currently running.
+*/
+void QPcscManager::updateSlotList()
+{
+ Q_ASSERT(m_hasContext);
+
+#ifndef SCARD_AUTOALLOCATE
+ // macOS does not support automatic allocation. Try using a fixed-size
+ // buffer first, extending it if it is not sufficient.
+#define LIST_READER_BUFFER_EXTRA 1024
+ QPcscSlotName buf(nullptr);
+ DWORD listSize = LIST_READER_BUFFER_EXTRA;
+ buf.resize(listSize);
+ QPcscSlotName::Ptr list = buf.ptr();
+
+ auto ret = SCardListReaders(m_context, nullptr, list, &listSize);
+#else
+ QPcscSlotName::Ptr list;
+ DWORD listSize = SCARD_AUTOALLOCATE;
+ auto ret = SCardListReaders(m_context, nullptr, reinterpret_cast<QPcscSlotName::Ptr>(&list),
+ &listSize);
+#endif
+
+ if (ret == LONG(SCARD_E_NO_READERS_AVAILABLE)) {
+ list = nullptr;
+ ret = SCARD_S_SUCCESS;
+ }
+#ifndef SCARD_AUTOALLOCATE
+ else if (ret == LONG(SCARD_E_INSUFFICIENT_BUFFER)) {
+ // SCardListReaders() has set listSize to the required size. We add
+ // extra space to reduce possibility of failure if the reader list has
+ // changed since the last call.
+ listSize += LIST_READER_BUFFER_EXTRA;
+ buf.resize(listSize);
+ list = buf.ptr();
+
+ ret = SCardListReaders(m_context, nullptr, list, &listSize);
+ if (ret == LONG(SCARD_E_NO_READERS_AVAILABLE)) {
+ list = nullptr;
+ ret = SCARD_S_SUCCESS;
+ }
+ }
+#undef LIST_READER_BUFFER_EXTRA
+#endif
+
+ if (ret != SCARD_S_SUCCESS) {
+ qCDebug(QT_NFC_PCSC) << "Failed to list readers:" << QPcsc::errorMessage(ret);
+ return;
+ }
+
+#ifdef SCARD_AUTOALLOCATE
+ auto freeList = qScopeGuard([this, list] {
+ if (list) {
+ Q_ASSERT(m_hasContext);
+ SCardFreeMemory(m_context, list);
+ }
+ });
+#endif
+
+ QSet<QPcscSlotName> presentSlots;
+
+ if (list != nullptr) {
+ for (const auto *p = list; *p; p += QPcscSlotName::nameSize(p) + 1)
+ presentSlots.insert(QPcscSlotName(p));
+ }
+
+ // Check current state list and mark slots that are not present anymore to
+ // be removed later.
+ for (auto &state : m_slotStates) {
+ auto slot = static_cast<QPcscSlot *>(state.pvUserData);
+ Q_ASSERT(slot != nullptr);
+
+ if (presentSlots.contains(slot->name()))
+ presentSlots.remove(slot->name());
+ else
+ state.dwEventState = SCARD_STATE_UNKNOWN;
+ }
+
+ if (!m_targetDetectionRunning)
+ return;
+
+ // Add new slots
+ for (auto &&slotName : std::as_const(presentSlots)) {
+ QPcscSlot *slot = new QPcscSlot(slotName, this);
+ qCDebug(QT_NFC_PCSC) << "New slot:" << slot;
+
+ m_slots[slotName] = slot;
+
+ SCARD_READERSTATE state {};
+ state.pvUserData = slot;
+ state.szReader = slot->name().ptr();
+ state.dwCurrentState = SCARD_STATE_UNAWARE;
+
+ m_slotStates.append(state);
+ }
+}
+
+bool QPcscManager::establishContext()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ Q_ASSERT(!m_hasContext);
+
+ LONG ret = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &m_context);
+ if (ret != SCARD_S_SUCCESS) {
+ qCWarning(QT_NFC_PCSC) << "Failed to establish context:" << QPcsc::errorMessage(ret);
+ return false;
+ }
+ m_hasContext = true;
+
+ return true;
+}
+
+void QPcscManager::onStateUpdate()
+{
+ if (!m_hasContext) {
+ if (!m_targetDetectionRunning) {
+ m_stateUpdateTimer->stop();
+ return;
+ }
+
+ if (!establishContext())
+ return;
+ }
+
+ updateSlotList();
+ removeSlots();
+
+ if (m_slotStates.isEmpty()) {
+ if (!m_targetDetectionRunning) {
+ // Free the context if it is no longer needed to card tracking.
+ SCardReleaseContext(m_context);
+ m_hasContext = false;
+
+ m_stateUpdateTimer->stop();
+ }
+ return;
+ }
+
+ // Both Windows and PCSCLite support interruptable continuos state detection
+ // where SCardCancel() can be used to abort it from another thread.
+ // But that introduces a problem of reliable cancelling of the status change
+ // call and no other. Reliable use of SCardCancel() would probably require
+ // some form of synchronization and polling, and would make the code much
+ // more complicated.
+ // Alternatively, the state detection code could run in a yet another thread
+ // that will not need to be cancelled too often.
+ // For simplicity, the current code just checks for status changes every
+ // second.
+ LONG ret = SCardGetStatusChange(m_context, 0, m_slotStates.data(), m_slotStates.size());
+
+ if (ret == SCARD_S_SUCCESS || ret == LONG(SCARD_E_UNKNOWN_READER)) {
+ processSlotUpdates();
+ removeSlots();
+ } else if (ret == LONG(SCARD_E_CANCELLED) || ret == LONG(SCARD_E_UNKNOWN_READER)
+ || ret == LONG(SCARD_E_TIMEOUT)) {
+ /* ignore */
+ } else {
+ qCWarning(QT_NFC_PCSC) << "SCardGetStatusChange failed:" << QPcsc::errorMessage(ret);
+
+ // Unknown failure. It is likely that the current context will not
+ // recover from it, so destroy it and try to create a new context at the
+ // next iteration.
+ Q_ASSERT(m_hasContext);
+ m_hasContext = false;
+ for (auto slot : std::as_const(m_slots)) {
+ slot->invalidateInsertedCard();
+ slot->deleteLater();
+ }
+ SCardReleaseContext(m_context);
+ m_slots.clear();
+ m_slotStates.clear();
+ }
+}
+
+void QPcscManager::onStartTargetDetectionRequest(QNearFieldTarget::AccessMethod accessMethod)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ m_requestedMethod = accessMethod;
+
+ if (m_targetDetectionRunning)
+ return;
+
+ m_targetDetectionRunning = true;
+ m_stateUpdateTimer->start();
+}
+
+void QPcscManager::onStopTargetDetectionRequest()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+ m_targetDetectionRunning = false;
+}
+
+QPcscCard *QPcscManager::connectToCard(QPcscSlot *slot)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+ Q_ASSERT(slot != nullptr);
+ Q_ASSERT(m_hasContext);
+
+ SCARDHANDLE cardHandle;
+ DWORD activeProtocol;
+
+ LONG ret = SCardConnect(m_context, slot->name().ptr(), SCARD_SHARE_SHARED,
+ SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &cardHandle, &activeProtocol);
+ if (ret != SCARD_S_SUCCESS) {
+ qCDebug(QT_NFC_PCSC) << "Failed to connect to card:" << QPcsc::errorMessage(ret);
+ retryCardDetection(slot);
+ return nullptr;
+ }
+
+ auto card = new QPcscCard(cardHandle, activeProtocol, this);
+ auto uid = card->readUid();
+ auto maxInputLength = card->readMaxInputLength();
+
+ QNearFieldTarget::AccessMethods accessMethods = QNearFieldTarget::TagTypeSpecificAccess;
+ if (card->supportsNdef())
+ accessMethods |= QNearFieldTarget::NdefAccess;
+
+ if (m_requestedMethod != QNearFieldTarget::UnknownAccess
+ && (accessMethods & m_requestedMethod) == 0) {
+ qCDebug(QT_NFC_PCSC) << "Dropping card without required access support";
+ card->deleteLater();
+ return nullptr;
+ }
+
+ if (!card->isValid()) {
+ qCDebug(QT_NFC_PCSC) << "Card became invalid";
+ card->deleteLater();
+
+ retryCardDetection(slot);
+
+ return nullptr;
+ }
+
+ Q_EMIT cardInserted(card, uid, accessMethods, maxInputLength);
+
+ return card;
+}
+
+/*
+ Setup states list so that the card detection for the given slot will
+ be retried on the next iteration.
+
+ This is useful to try to get cards working after reset.
+*/
+void QPcscManager::retryCardDetection(const QPcscSlot *slot)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ for (auto &state : m_slotStates) {
+ if (state.pvUserData == slot) {
+ state.dwCurrentState = SCARD_STATE_UNAWARE;
+ break;
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/pcsc/qpcscmanager_p.h b/src/nfc/pcsc/qpcscmanager_p.h
new file mode 100644
index 00000000..d35edf57
--- /dev/null
+++ b/src/nfc/pcsc/qpcscmanager_p.h
@@ -0,0 +1,65 @@
+// 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 QPCSCMANAGER_P_H
+#define QPCSCMANAGER_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 "qpcsc_p.h"
+#include "qnearfieldtarget.h"
+
+QT_BEGIN_NAMESPACE
+
+class QPcscSlot;
+class QPcscCard;
+class QTimer;
+
+class QPcscManager : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QPcscManager(QObject *parent = nullptr);
+ ~QPcscManager() override;
+
+ QPcscCard *connectToCard(QPcscSlot *slot);
+
+private:
+ QTimer *m_stateUpdateTimer;
+ bool m_targetDetectionRunning = false;
+ bool m_hasContext = false;
+ SCARDCONTEXT m_context;
+ QMap<QPcscSlotName, QPcscSlot *> m_slots;
+ QList<SCARD_READERSTATE> m_slotStates;
+ QNearFieldTarget::AccessMethod m_requestedMethod;
+
+ [[nodiscard]] bool establishContext();
+ void processSlotUpdates();
+ void updateSlotList();
+ void removeSlots();
+ void retryCardDetection(const QPcscSlot *slot);
+
+public Q_SLOTS:
+ void onStartTargetDetectionRequest(QNearFieldTarget::AccessMethod accessMethod);
+ void onStopTargetDetectionRequest();
+
+private Q_SLOTS:
+ void onStateUpdate();
+
+Q_SIGNALS:
+ void cardInserted(QPcscCard *card, const QByteArray &uid,
+ QNearFieldTarget::AccessMethods accessMethods, int maxInputLength);
+};
+
+QT_END_NAMESPACE
+
+#endif // QPCSCMANAGER_P_H
diff --git a/src/nfc/pcsc/qpcscslot.cpp b/src/nfc/pcsc/qpcscslot.cpp
new file mode 100644
index 00000000..cf55cf7b
--- /dev/null
+++ b/src/nfc/pcsc/qpcscslot.cpp
@@ -0,0 +1,57 @@
+// 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 "qpcscslot_p.h"
+#include "qpcscmanager_p.h"
+#include "qpcsccard_p.h"
+#include <QtCore/QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_NFC_PCSC)
+
+QPcscSlot::QPcscSlot(const QPcscSlotName &name, QPcscManager *manager)
+ : QObject(manager), m_name(name)
+{
+}
+
+QPcscSlot::~QPcscSlot()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO << this;
+ if (m_insertedCard)
+ m_insertedCard->invalidate();
+}
+
+void QPcscSlot::processStateChange(DWORD eventId, bool createCards)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ // Check if the currently inserted card is still valid
+ if (!m_insertedCard.isNull()) {
+ if (m_insertedCard->checkCardPresent())
+ return;
+ qCDebug(QT_NFC_PCSC) << "Removing card from slot" << m_name;
+ m_insertedCard->invalidate();
+ m_insertedCard.clear();
+ }
+
+ auto manager = qobject_cast<QPcscManager *>(parent());
+
+ if (manager != nullptr && createCards
+ && (eventId
+ & (SCARD_STATE_PRESENT | SCARD_STATE_MUTE | SCARD_STATE_UNPOWERED
+ | SCARD_STATE_EXCLUSIVE))
+ == SCARD_STATE_PRESENT) {
+ qCDebug(QT_NFC_PCSC) << "New card in slot" << m_name;
+
+ m_insertedCard = manager->connectToCard(this);
+ }
+}
+
+void QPcscSlot::invalidateInsertedCard()
+{
+ if (m_insertedCard)
+ m_insertedCard->invalidate();
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/pcsc/qpcscslot_p.h b/src/nfc/pcsc/qpcscslot_p.h
new file mode 100644
index 00000000..c335b47a
--- /dev/null
+++ b/src/nfc/pcsc/qpcscslot_p.h
@@ -0,0 +1,46 @@
+// 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 QPCSCSLOT_P_H
+#define QPCSCSLOT_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 "qpcsc_p.h"
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QPcscManager;
+class QPcscCard;
+
+class QPcscSlot : public QObject
+{
+ Q_OBJECT
+public:
+ QPcscSlot(const QPcscSlotName &name, QPcscManager *manager);
+ ~QPcscSlot() override;
+
+ const QPcscSlotName &name() const { return m_name; }
+ void processStateChange(DWORD eventId, bool createCards);
+ bool hasCard() const { return !m_insertedCard.isNull(); }
+ void invalidateInsertedCard();
+
+private:
+ const QPcscSlotName m_name;
+ QPointer<QPcscCard> m_insertedCard;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPCSCSLOT_P_H
diff --git a/src/nfc/qapduutils.cpp b/src/nfc/qapduutils.cpp
new file mode 100644
index 00000000..057e4346
--- /dev/null
+++ b/src/nfc/qapduutils.cpp
@@ -0,0 +1,81 @@
+// 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 "qapduutils_p.h"
+#include <QtCore/QtEndian>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Utilities for handling smart card application protocol data units (APDU).
+
+ The structure of APDUs is defined by ISO/IEC 7816-4 Organization, security
+ and commands for interchange. The summary can be found on Wikipedia:
+
+ https://en.wikipedia.org/wiki/Smart_card_application_protocol_data_unit
+*/
+
+/*
+ Parses a response APDU from the raw data.
+
+ If the data is too short to contain SW bytes, the returned responses SW
+ is set to QResponseApdu::Empty.
+*/
+QResponseApdu::QResponseApdu(const QByteArray &response)
+{
+ if (response.size() < 2) {
+ m_status = Empty;
+ m_data = response;
+ } else {
+ const auto dataSize = response.size() - 2;
+ m_status = qFromBigEndian(qFromUnaligned<uint16_t>(response.constData() + dataSize));
+ m_data = response.left(dataSize);
+ }
+}
+
+/*
+ Builds a command APDU from components according to ISO/IEC 7816.
+*/
+QByteArray QCommandApdu::build(uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2,
+ QByteArrayView data, uint16_t ne)
+{
+ Q_ASSERT(data.size() <= 0xFFFF);
+
+ QByteArray apdu;
+ apdu.append(static_cast<char>(cla));
+ apdu.append(static_cast<char>(ins));
+ apdu.append(static_cast<char>(p1));
+ apdu.append(static_cast<char>(p2));
+
+ bool extendedLc = false;
+ uint16_t nc = data.size();
+
+ if (nc > 0) {
+ if (nc < 256) {
+ apdu.append(static_cast<char>(nc));
+ } else {
+ extendedLc = true;
+ apdu.append('\0');
+ apdu.append(static_cast<char>(nc >> 8));
+ apdu.append(static_cast<char>(nc & 0xFF));
+ }
+ apdu.append(data);
+ }
+
+ if (ne) {
+ if (ne < 256) {
+ apdu.append(static_cast<char>(ne));
+ } else if (ne == 256) {
+ apdu.append(static_cast<char>('\0'));
+ } else {
+ if (!extendedLc)
+ apdu.append('\0');
+ apdu.append(static_cast<char>(ne >> 8));
+ apdu.append(static_cast<char>(ne & 0xFF));
+ }
+ }
+
+ return apdu;
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qapduutils_p.h b/src/nfc/qapduutils_p.h
new file mode 100644
index 00000000..dd777b03
--- /dev/null
+++ b/src/nfc/qapduutils_p.h
@@ -0,0 +1,53 @@
+// 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 QAPDUUTILS_P_H
+#define QAPDUUTILS_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/QByteArray>
+
+QT_BEGIN_NAMESPACE
+
+class QResponseApdu
+{
+public:
+ static constexpr uint16_t Empty = 0x0000;
+ static constexpr uint16_t Success = 0x9000;
+
+ explicit QResponseApdu(const QByteArray &response = {});
+
+ const QByteArray &data() const { return m_data; }
+ uint16_t status() const { return m_status; }
+ bool isOk() const { return m_status == Success; }
+
+private:
+ QByteArray m_data;
+ uint16_t m_status;
+};
+
+namespace QCommandApdu {
+
+// INS byte values for command APDUs
+constexpr uint8_t Select = 0xA4;
+constexpr uint8_t ReadBinary = 0xB0;
+constexpr uint8_t GetData = 0xCA;
+constexpr uint8_t UpdateBinary = 0xD6;
+
+QByteArray build(uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2, QByteArrayView data,
+ uint16_t ne = 0);
+};
+
+QT_END_NAMESPACE
+
+#endif // QAPDUUTILS_P_H
diff --git a/src/nfc/qllcpserver.cpp b/src/nfc/qllcpserver.cpp
deleted file mode 100644
index 66831b9f..00000000
--- a/src/nfc/qllcpserver.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qllcpserver_p.h"
-
-#if defined(QT_SIMULATOR)
-#include "qllcpserver_simulator_p.h"
-#elif defined(QT_ANDROID_NFC)
-#include "qllcpserver_android_p.h"
-#else
-#include "qllcpserver_p_p.h"
-#endif
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QLlcpServer
- \brief The QLlcpServer class provides an NFC LLCP socket based server.
- \internal
-
- \ingroup connectivity-nfc
- \inmodule QtNfc
-
- This class makes it possible to accept incoming LLCP socket connections.
-
- Call listen() to have the server start listening for incoming connections on a specified port.
- The newConnection() signal is then emitted each time a client connects to the server.
-
- Call nextPendingConnection() to accept the pending connection as a connected QLlcpSocket. The
- function returns a pointer to a QLlcpSocket that can be used for communicating with the client.
-
- If an error occurs, serverError() returns the type of error, and errorString() can be called to
- get a human readable description of what happened.
-
- When listening for connections, the port which the server is listening on is available through
- serverPort().
-
- Calling close() makes QLlcpServer stop listening for incoming connections.
-*/
-
-/*!
- \fn QLlcpServer::newConnection()
-
- This signal is emitted every time a new connection is available.
-
- \sa hasPendingConnections(), nextPendingConnection()
-*/
-
-/*!
- Constructs a new NFC LLCP server with \a parent.
-*/
-QLlcpServer::QLlcpServer(QObject *parent)
-: QObject(parent), d_ptr(new QLlcpServerPrivate(this))
-{
-}
-
-/*!
- Destroys the NFC LLCP server.
-*/
-QLlcpServer::~QLlcpServer()
-{
- delete d_ptr;
-}
-
-/*!
- Tells the server to listen for incoming connections on \a serviceUri. If the server is
- currently listening then it will return false. Returns true on success; otherwise returns
- false.
-
- serviceUri() will return the \a serviceUri that is passed into listen.
-
- serverPort() will return the port that is assigned to the server.
-
- \sa serverPort(), isListening(), close()
-*/
-bool QLlcpServer::listen(const QString &serviceUri)
-{
- Q_D(QLlcpServer);
-
- return d->listen(serviceUri);
-}
-
-/*!
- Returns true if the server is listening for incoming connections; otherwise returns false.
-*/
-bool QLlcpServer::isListening() const
-{
- Q_D(const QLlcpServer);
-
- return d->isListening();
-}
-
-/*!
- Stops listening for incoming connections.
-*/
-void QLlcpServer::close()
-{
- Q_D(QLlcpServer);
-
- d->close();
-}
-
-/*!
- Returns the LLCP service URI that the server is listening on.
-*/
-QString QLlcpServer::serviceUri() const
-{
- Q_D(const QLlcpServer);
-
- return d->serviceUri();
-}
-
-/*!
- Returns the LLCP port associated with the service URI that the server is listening on.
- This call is not supported on all platforms and will return 0 on these platforms.
-*/
-quint8 QLlcpServer::serverPort() const
-{
- Q_D(const QLlcpServer);
-
- return d->serverPort();
-}
-
-/*!
- Returns true if the server has a pending connection; otherwise returns false.
-
- \sa nextPendingConnection()
-*/
-bool QLlcpServer::hasPendingConnections() const
-{
- Q_D(const QLlcpServer);
-
- return d->hasPendingConnections();
-}
-
-/*!
- Returns the next pending connection as a connected QLlcpSocket object.
-
- The socket is created as a child of the server, which means that it is automatically deleted
- when the QLlcpServer object is destroyed. It is still a good idea to delete the object
- explicitly when you are done with it, to avoid wasting memory.
-
- 0 is returned if this function is called when there are no pending connections.
-
- \sa hasPendingConnections(), newConnection()
-*/
-QLlcpSocket *QLlcpServer::nextPendingConnection()
-{
- Q_D(QLlcpServer);
-
- return d->nextPendingConnection();
-}
-
-/*!
- Returns the last error that occurred.
-*/
-QLlcpSocket::SocketError QLlcpServer::serverError() const
-{
- Q_D(const QLlcpServer);
-
- return d->serverError();
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qllcpserver_android_p.cpp b/src/nfc/qllcpserver_android_p.cpp
deleted file mode 100644
index eb0306a0..00000000
--- a/src/nfc/qllcpserver_android_p.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Centria research and development
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qllcpserver_android_p.h"
-//#include "qnx/qnxnfcmanager_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QLlcpServerPrivate::QLlcpServerPrivate(QLlcpServer *q)
- : q_ptr(q), m_llcpSocket(0), m_connected(false)
-{
-}
-
-QLlcpServerPrivate::~QLlcpServerPrivate()
-{
-}
-
-bool QLlcpServerPrivate::listen(const QString &/*serviceUri*/)
-{
- /*//The server is already listening
- if (isListening())
- return false;
-
- nfc_result_t result = nfc_llcp_register_connection_listener(NFC_LLCP_SERVER, 0, serviceUri.toStdString().c_str(), &m_conListener);
- m_connected = true;
- if (result == NFC_RESULT_SUCCESS) {
- m_serviceUri = serviceUri;
- qQNXNFCDebug() << "LLCP server registered" << serviceUri;
- } else {
- qWarning() << Q_FUNC_INFO << "Could not register for llcp connection listener";
- return false;
- }
- QNXNFCManager::instance()->registerLLCPConnection(m_conListener, this);*/
- return true;
-}
-
-bool QLlcpServerPrivate::isListening() const
-{
- return m_connected;
-}
-
-void QLlcpServerPrivate::close()
-{
- /*nfc_llcp_unregister_connection_listener(m_conListener);
- QNXNFCManager::instance()->unregisterLLCPConnection(m_conListener);
- m_serviceUri = QString();
- m_connected = false;*/
-}
-
-QString QLlcpServerPrivate::serviceUri() const
-{
- return m_serviceUri;
-}
-
-quint8 QLlcpServerPrivate::serverPort() const
-{
- /*unsigned int sap;
- if (nfc_llcp_get_local_sap(m_target, &sap) == NFC_RESULT_SUCCESS) {
- return sap;
- }*/
- return -1;
-}
-
-bool QLlcpServerPrivate::hasPendingConnections() const
-{
- return m_llcpSocket != 0;
-}
-
-QLlcpSocket *QLlcpServerPrivate::nextPendingConnection()
-{
- /*QLlcpSocket *socket = m_llcpSocket;
- m_llcpSocket = 0;
- return socket;*/
- return 0;
-}
-
-QLlcpSocket::SocketError QLlcpServerPrivate::serverError() const
-{
- return QLlcpSocket::UnknownSocketError;
-}
-
-/*void QLlcpServerPrivate::connected(nfc_target_t *target)
-{
- m_target = target;
- if (m_llcpSocket != 0) {
- qWarning() << Q_FUNC_INFO << "LLCP socket not cloesed properly";
- return;
- }
- m_llcpSocket = new QLlcpSocket();
- m_llcpSocket->bind(serverPort());
-}*/
-
-QT_END_NAMESPACE
-
-
diff --git a/src/nfc/qllcpserver_android_p.h b/src/nfc/qllcpserver_android_p.h
deleted file mode 100644
index 5d5e2aea..00000000
--- a/src/nfc/qllcpserver_android_p.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Centria research and development
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QLLCPSERVER_ANDROID_P_H
-#define QLLCPSERVER_ANDROID_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 "qllcpserver_p.h"
-//#include "nfc/nfc.h"
-
-QT_BEGIN_NAMESPACE
-
-class QLlcpServerPrivate : public QObject
-{
- Q_OBJECT
-public:
- QLlcpServerPrivate(QLlcpServer *q);
- ~QLlcpServerPrivate();
-
- bool listen(const QString &serviceUri);
- bool isListening() const;
-
- void close();
-
- QString serviceUri() const;
- quint8 serverPort() const;
-
- bool hasPendingConnections() const;
- QLlcpSocket *nextPendingConnection();
-
- QLlcpSocket::SocketError serverError() const;
-
- //Q_INVOKABLE void connected(nfc_target_t *);
-
-private:
- QLlcpServer *q_ptr;
- QLlcpSocket *m_llcpSocket;
- //We can not use m_conListener for the connection state
- bool m_connected;
- //nfc_llcp_connection_listener_t m_conListener;
- QString m_serviceUri;
- //nfc_target_t *m_target;
-};
-
-QT_END_NAMESPACE
-
-#endif // QLLCPSERVER_ANDROID_P_H
diff --git a/src/nfc/qllcpserver_p.cpp b/src/nfc/qllcpserver_p.cpp
deleted file mode 100644
index a3cf95bd..00000000
--- a/src/nfc/qllcpserver_p.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qllcpserver_p_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QLlcpServerPrivate::QLlcpServerPrivate(QLlcpServer *q)
-: q_ptr(q)
-{
-}
-
-QLlcpServerPrivate::~QLlcpServerPrivate()
-{
-}
-
-bool QLlcpServerPrivate::listen(const QString &serviceUri)
-{
- Q_UNUSED(serviceUri);
-
- return false;
-}
-
-bool QLlcpServerPrivate::isListening() const
-{
- return false;
-}
-
-void QLlcpServerPrivate::close()
-{
-}
-
-QString QLlcpServerPrivate::serviceUri() const
-{
- return QString();
-}
-
-quint8 QLlcpServerPrivate::serverPort() const
-{
- return 0;
-}
-
-bool QLlcpServerPrivate::hasPendingConnections() const
-{
- return false;
-}
-
-QLlcpSocket *QLlcpServerPrivate::nextPendingConnection()
-{
- return 0;
-}
-
-QLlcpSocket::SocketError QLlcpServerPrivate::serverError() const
-{
- return QLlcpSocket::UnknownSocketError;
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qllcpserver_p.h b/src/nfc/qllcpserver_p.h
deleted file mode 100644
index 33ab6f1b..00000000
--- a/src/nfc/qllcpserver_p.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QLLCPSERVER_H
-#define QLLCPSERVER_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 <QtNfc/qtnfcglobal.h>
-#include "qllcpsocket_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QLlcpServerPrivate;
-
-class Q_NFC_EXPORT QLlcpServer : public QObject
-{
- Q_OBJECT
-
- Q_DECLARE_PRIVATE(QLlcpServer)
-
-public:
- explicit QLlcpServer(QObject *parent = 0);
- virtual ~QLlcpServer();
-
- bool listen(const QString &serviceUri);
- bool isListening() const;
-
- void close();
-
- QString serviceUri() const;
- quint8 serverPort() const;
-
- virtual bool hasPendingConnections() const;
- virtual QLlcpSocket *nextPendingConnection();
-
- QLlcpSocket::SocketError serverError() const;
-
-signals:
- void newConnection();
-
-private:
- QLlcpServerPrivate *d_ptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QLLCPSERVER_H
diff --git a/src/nfc/qllcpserver_p_p.h b/src/nfc/qllcpserver_p_p.h
deleted file mode 100644
index 62cfa953..00000000
--- a/src/nfc/qllcpserver_p_p.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QLLCPSERVER_P_H
-#define QLLCPSERVER_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 "qtnfcglobal.h"
-
-#include "qllcpserver_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QLlcpServerPrivate
-{
- Q_DECLARE_PUBLIC(QLlcpServer)
-
-public:
- QLlcpServerPrivate(QLlcpServer *q);
- ~QLlcpServerPrivate();
-
- bool listen(const QString &serviceUri);
- bool isListening() const;
-
- void close();
-
- QString serviceUri() const;
- quint8 serverPort() const;
-
- bool hasPendingConnections() const;
- QLlcpSocket *nextPendingConnection();
-
- QLlcpSocket::SocketError serverError() const;
-
-private:
- QLlcpServer *q_ptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QLLCPSERVER_P_H
diff --git a/src/nfc/qllcpsocket.cpp b/src/nfc/qllcpsocket.cpp
deleted file mode 100644
index a3785a60..00000000
--- a/src/nfc/qllcpsocket.cpp
+++ /dev/null
@@ -1,400 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qllcpsocket_p.h"
-
-#if defined(QT_SIMULATOR)
-#include "qllcpsocket_simulator_p.h"
-#else
-#include "qllcpsocket_p_p.h"
-#endif
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QLlcpSocket
- \brief The QLlcpSocket class provides an NFC LLCP socket.
- \internal
-
- \ingroup connectivity-nfc
- \inmodule QtNfc
-
- NFC LLCP protocol is a peer-to-peer communication protocol between two NFC compliant devices.
-*/
-
-/*!
- \enum QLlcpSocket::SocketError
-
- This enum describes the errors that can occur. The most recent error can be retrieved through a
- call to error().
-
- \value UnknownSocketError An unidentified error has occurred.
- \value RemoteHostClosedError The remote host closed the connection.
- \value SocketAccessError The socket operation failed because the application lacked the
- required privileges.
- \value SocketResourceError The local system ran out of resources (e.g., too many sockets).
-*/
-
-/*!
- \enum QLlcpSocket::SocketState
-
- This enum describes the different state in which a socket can be.
-
- \value UnconnectedState The socket is not connected.
- \value ConnectingState The socket has started establishing a connection.
- \value ConnectedState A connection is established.
- \value ClosingState The socket is about to close.
- \value BoundState The socket is bound to a local port (for servers).
- \value ListeningState The socket is listening for incoming connections (for internal use).
-*/
-
-/*!
- \fn QLlcpSocket::connected()
-
- This signal is emitted after connectToService() has been called and a connection has been
- successfully established.
-
- \sa connectToService(), disconnected()
-*/
-
-/*!
- \fn QLlcpSocket::disconnected()
-
- This signal is emitted when the socket has been disconnected.
-
- \sa disconnectFromService(),
-*/
-
-/*!
- \fn QLlcpSocket::error(QLlcpSocket::SocketError socketError)
-
- This signal is emitted when an error occurs. The \a socketError parameter describes the error.
-*/
-
-/*!
- \fn QLlcpSocket::stateChanged(QLlcpSocket::SocketState socketState)
-
- This signal is emitted when the state of the socket changes. The \a socketState parameter
- describes the new state.
-*/
-
-/*!
- Construct a new unconnected LLCP socket with \a parent.
-*/
-QLlcpSocket::QLlcpSocket(QObject *parent)
-: QIODevice(parent), d_ptr(new QLlcpSocketPrivate(this))
-{
- setOpenMode(QIODevice::NotOpen);
-}
-
-/*!
- \internal
-*/
-QLlcpSocket::QLlcpSocket(QLlcpSocketPrivate *d, QObject *parent)
-: QIODevice(parent), d_ptr(d)
-{
- setOpenMode(QIODevice::ReadWrite);
- d_ptr->q_ptr = this;
-}
-
-/*!
- Destroys the LLCP socket.
-*/
-QLlcpSocket::~QLlcpSocket()
-{
- delete d_ptr;
-}
-
-/*!
- Connects to the service identified by the URI \a serviceUri on \a target.
-*/
-void QLlcpSocket::connectToService(QNearFieldTarget *target, const QString &serviceUri)
-{
- Q_D(QLlcpSocket);
-
- d->connectToService(target, serviceUri);
-}
-
-/*!
- Disconnects the socket.
-*/
-void QLlcpSocket::disconnectFromService()
-{
- Q_D(QLlcpSocket);
-
- d->disconnectFromService();
-}
-
-/*!
- Disconnects the socket.
-*/
-void QLlcpSocket::close()
-{
- Q_D(QLlcpSocket);
-
- QIODevice::close();
-
- d->disconnectFromService();
-}
-
-/*!
- Binds the LLCP socket to local \a port. Returns true on success; otherwise returns false.
-*/
-bool QLlcpSocket::bind(quint8 port)
-{
- Q_D(QLlcpSocket);
-
- return d->bind(port);
-}
-
-/*!
- Returns true if at least one datagram (service data units) is waiting to be read; otherwise
- returns false.
-
- \sa pendingDatagramSize(), readDatagram()
-*/
-bool QLlcpSocket::hasPendingDatagrams() const
-{
- Q_D(const QLlcpSocket);
-
- return d->hasPendingDatagrams();
-}
-
-/*!
- Returns the size of the first pending datagram (service data unit). If there is no datagram
- available, this function returns -1.
-
- \sa hasPendingDatagrams(), readDatagram()
-*/
-qint64 QLlcpSocket::pendingDatagramSize() const
-{
- Q_D(const QLlcpSocket);
-
- return d->pendingDatagramSize();
-}
-
-/*!
- Sends the datagram at \a data of size \a size to the service that this socket is connected to.
- Returns the number of bytes sent on success; otherwise return -1;
-*/
-qint64 QLlcpSocket::writeDatagram(const char *data, qint64 size)
-{
- Q_D(QLlcpSocket);
-
- return d->writeDatagram(data, size);
-}
-
-/*!
- \reimp
-
- Always returns true.
-*/
-bool QLlcpSocket::isSequential() const
-{
- return true;
-}
-
-/*!
- \overload
-
- Sends the datagram \a datagram to the service that this socket is connected to.
-*/
-qint64 QLlcpSocket::writeDatagram(const QByteArray &datagram)
-{
- Q_D(QLlcpSocket);
-
- return d->writeDatagram(datagram);
-}
-
-/*!
- Receives a datagram no larger than \a maxSize bytes and stores it in \a data. The sender's
- details are stored in \a target and \a port (unless the pointers are 0).
-
- Returns the size of the datagram on success; otherwise returns -1.
-
- If maxSize is too small, the rest of the datagram will be lost. To avoid loss of data, call
- pendingDatagramSize() to determine the size of the pending datagram before attempting to read
- it. If maxSize is 0, the datagram will be discarded.
-
- \sa writeDatagram(), hasPendingDatagrams(), pendingDatagramSize()
-*/
-qint64 QLlcpSocket::readDatagram(char *data, qint64 maxSize, QNearFieldTarget **target,
- quint8 *port)
-{
- Q_D(QLlcpSocket);
-
- return d->readDatagram(data, maxSize, target, port);
-}
-
-/*!
- Sends the datagram at \a data of size \a size to the service identified by the URI
- \a port on \a target. Returns the number of bytes sent on success; otherwise returns -1.
-
- \sa readDatagram()
-*/
-qint64 QLlcpSocket::writeDatagram(const char *data, qint64 size, QNearFieldTarget *target,
- quint8 port)
-{
- Q_D(QLlcpSocket);
-
- return d->writeDatagram(data, size, target, port);
-}
-
-/*!
- \overload
-
- Sends the datagram \a datagram to the service identified by the URI \a port on \a target.
-*/
-qint64 QLlcpSocket::writeDatagram(const QByteArray &datagram, QNearFieldTarget *target,
- quint8 port)
-{
- Q_D(QLlcpSocket);
-
- return d->writeDatagram(datagram, target, port);
-}
-
-/*!
- Returns the type of error that last occurred.
-*/
-QLlcpSocket::SocketError QLlcpSocket::error() const
-{
- Q_D(const QLlcpSocket);
-
- return d->error();
-}
-
-/*!
- Returns the state of the socket.
-*/
-QLlcpSocket::SocketState QLlcpSocket::state() const
-{
- Q_D(const QLlcpSocket);
-
- return d->state();
-}
-
-/*!
- \reimp
-*/
-qint64 QLlcpSocket::bytesAvailable() const
-{
- Q_D(const QLlcpSocket);
-
- return d->bytesAvailable() + QIODevice::bytesAvailable();
-}
-
-/*!
- \reimp
-*/
-bool QLlcpSocket::canReadLine() const
-{
- Q_D(const QLlcpSocket);
-
- return d->canReadLine() || QIODevice::canReadLine();
-}
-
-/*!
- \reimp
-*/
-bool QLlcpSocket::waitForReadyRead(int msecs)
-{
- Q_D(QLlcpSocket);
-
- return d->waitForReadyRead(msecs);
-}
-
-/*!
- \reimp
-*/
-bool QLlcpSocket::waitForBytesWritten(int msecs)
-{
- Q_D(QLlcpSocket);
-
- return d->waitForBytesWritten(msecs);
-}
-
-/*!
- Waits until the socket is connected, up to \a msecs milliseconds. If the connection has been
- established, this function returns true; otherwise it returns false. In the case where it
- returns false, you can call error() to determine the cause of the error.
-
- If msecs is -1, this function will not time out.
-*/
-bool QLlcpSocket::waitForConnected(int msecs)
-{
- Q_D(QLlcpSocket);
-
- return d->waitForConnected(msecs);
-}
-
-/*!
- Waits until the socket is disconnected, up to \a msecs milliseconds. If the connection has been
- disconnected, this function returns true; otherwise it returns false. In the case where it
- returns false, you can call error() to determine the cause of the error.
-
- If msecs is -1, this function will not time out.
-*/
-bool QLlcpSocket::waitForDisconnected(int msecs)
-{
- Q_D(QLlcpSocket);
-
- return d->waitForDisconnected(msecs);
-}
-
-/*!
- \internal
-*/
-qint64 QLlcpSocket::readData(char *data, qint64 maxlen)
-{
- Q_D(QLlcpSocket);
-
- return d->readData(data, maxlen);
-}
-
-/*!
- \internal
-*/
-qint64 QLlcpSocket::writeData(const char *data, qint64 len)
-{
- Q_D(QLlcpSocket);
-
- return d->writeData(data, len);
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qllcpsocket_android_p.cpp b/src/nfc/qllcpsocket_android_p.cpp
deleted file mode 100644
index 97b8db16..00000000
--- a/src/nfc/qllcpsocket_android_p.cpp
+++ /dev/null
@@ -1,324 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Centria research and development
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qllcpsocket_android_p.h"
-#include <unistd.h>
-
-QT_BEGIN_NAMESPACE
-
-QLlcpSocketPrivate::QLlcpSocketPrivate(QLlcpSocket *q)
- : q_ptr(q), m_state(QLlcpSocket::UnconnectedState), m_server(false)
-{
-}
-
-QLlcpSocketPrivate::~QLlcpSocketPrivate()
-{
- disconnectFromService();
-}
-
-void QLlcpSocketPrivate::connectToService(QNearFieldTarget *target, const QString &serviceUri)
-{
- Q_UNUSED(target)
- Q_UNUSED(serviceUri)
- /*if (m_state != QLlcpSocket::UnconnectedState) {
- qWarning() << Q_FUNC_INFO << "socket is already connected";
- return;
- }
-
- m_state = QLlcpSocket::ConnectingState;
- if (nfc_llcp_register_connection_listener(NFC_LLCP_CLIENT, 0, serviceUri.toLocal8Bit().constData(),
- &m_conListener) != NFC_RESULT_SUCCESS) {
- qWarning() << Q_FUNC_INFO << "could not register for connection listener";
- return;
- }
-
- QNXNFCManager::instance()->registerLLCPConnection(m_conListener, this);
-
- qQNXNFCDebug() << "Connecting client socket" << serviceUri << m_conListener;
- connect(QNXNFCManager::instance(), &QNXNFCManager::llcpDisconnected, this, &QLlcpSocketPrivate::disconnectFromService);*/
-}
-
-void QLlcpSocketPrivate::disconnectFromService()
-{
- /*Q_Q(QLlcpSocket);
- QNXNFCManager::instance()->unregisterTargetLost(this);
- qQNXNFCDebug() << "Shutting down LLCP socket";
- if (!m_server && nfc_llcp_unregister_connection_listener(m_conListener) != NFC_RESULT_SUCCESS) {
- qWarning() << Q_FUNC_INFO << "Error when trying to close LLCP socket";
- }
- QNXNFCManager::instance()->unregisterLLCPConnection(m_conListener);
- disconnect(QNXNFCManager::instance(), &QNXNFCManager::llcpDisconnected, this, &QLlcpSocketPrivate::disconnectFromService);
-
- q->disconnected();
- m_conListener = 0;
- m_state = QLlcpSocket::UnconnectedState;*/
-}
-
-bool QLlcpSocketPrivate::bind(quint8 port)
-{
- Q_UNUSED(port);
-
- /*m_state = QLlcpSocket::ConnectedState;
- m_server = true;
- connect(QNXNFCManager::instance(), &QNXNFCManager::llcpDisconnected, this, &QLlcpSocketPrivate::disconnectFromService);
- connected(QNXNFCManager::instance()->getLastTarget());*/
-
- return true;
-}
-
-bool QLlcpSocketPrivate::hasPendingDatagrams() const
-{
- return !m_receivedDatagrams.isEmpty();
-}
-
-qint64 QLlcpSocketPrivate::pendingDatagramSize() const
-{
- if (m_receivedDatagrams.isEmpty())
- return -1;
-
- return m_receivedDatagrams.first().length();
-}
-
-qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size)
-{
- if (m_state == QLlcpSocket::ConnectedState)
- return writeData(data, size);
-
- return -1;
-}
-
-qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram)
-{
- return writeDatagram(datagram.constData(), datagram.size());
-}
-
-qint64 QLlcpSocketPrivate::readDatagram(char *data, qint64 maxSize,
- QNearFieldTarget **target, quint8 *port)
-{
- Q_UNUSED(target);
- Q_UNUSED(port);
-
- if (m_state == QLlcpSocket::ConnectedState)
- return readData(data, maxSize);
-
- return -1;
-}
-
-qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size,
- QNearFieldTarget *target, quint8 port)
-{
- Q_UNUSED(target);
- Q_UNUSED(port);
-
- return writeDatagram(data, size);
-}
-
-qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram,
- QNearFieldTarget *target, quint8 port)
-{
- Q_UNUSED(datagram);
- Q_UNUSED(target);
- Q_UNUSED(port);
-
- return writeDatagram(datagram.constData(), datagram.size()-1);
-}
-
-QLlcpSocket::SocketError QLlcpSocketPrivate::error() const
-{
- return QLlcpSocket::UnknownSocketError;
-}
-
-QLlcpSocket::SocketState QLlcpSocketPrivate::state() const
-{
- return m_state;
-}
-
-qint64 QLlcpSocketPrivate::readData(char *data, qint64 maxlen)
-{
- Q_UNUSED(data);
- Q_UNUSED(maxlen);
- if (m_receivedDatagrams.isEmpty())
- return 0;
-
- /*const QByteArray datagram = m_receivedDatagrams.takeFirst();
- qint64 size = qMin(maxlen, qint64(datagram.length()));
- memcpy(data, datagram.constData(), size);
- return size;*/
- return 0;
-}
-
-qint64 QLlcpSocketPrivate::writeData(const char *data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
- /*if (socketState != Idle) {
- m_writeQueue.append(QByteArray(data, len));
- return len;
- } else {
- socketState = Writing;
- qQNXNFCDebug() << "LLCP write";
- nfc_result_t res = nfc_llcp_write(m_target, (uchar_t*)data, (size_t)len);
- if (res == NFC_RESULT_SUCCESS) {
- return len;
- } else {
- qWarning() << Q_FUNC_INFO << "Error writing to LLCP socket. Error" << res;
- enteringIdle();
- return -1;
- }
- }*/
- return -1;
-}
-
-qint64 QLlcpSocketPrivate::bytesAvailable() const
-{
- /*qint64 available = 0;
- for (const QByteArray &datagram : qAsConst(m_receivedDatagrams))
- available += datagram.length();
-
- return available;*/
- return 0;
-}
-
-bool QLlcpSocketPrivate::canReadLine() const
-{
- /*for (const QByteArray &datagram : qAsConst(m_receivedDatagrams)) {
- if (datagram.contains('\n'))
- return true;
- }*/
-
- return false;
-}
-
-bool QLlcpSocketPrivate::waitForReadyRead(int msecs)
-{
- Q_UNUSED(msecs);
-
- return false;
-}
-
-bool QLlcpSocketPrivate::waitForBytesWritten(int msecs)
-{
- Q_UNUSED(msecs);
-
- return false;
-}
-
-bool QLlcpSocketPrivate::waitForConnected(int msecs)
-{
- Q_UNUSED(msecs);
-
- return false;
-}
-
-bool QLlcpSocketPrivate::waitForDisconnected(int msecs)
-{
- Q_UNUSED(msecs);
-
- return false;
-}
-
-/*void QLlcpSocketPrivate::connected(nfc_target_t *target)
-{
- Q_Q(QLlcpSocket);
- m_target = target;
-
- m_state = QLlcpSocket::ConnectedState;
- emit q->connected();
- qQNXNFCDebug() << "Socket connected";
-
- unsigned int targetId;
- nfc_get_target_connection_id(target, &targetId);
- QNXNFCManager::instance()->requestTargetLost(this, targetId);
- enteringIdle();
-}*/
-
-void QLlcpSocketPrivate::targetLost()
-{
- disconnectFromService();
- //qQNXNFCDebug() << "LLCP target lost...socket disconnected";
-}
-
-void QLlcpSocketPrivate::dataRead(QByteArray& data)
-{
- Q_UNUSED(data);
- /*Q_Q(QLlcpSocket);
- if (!data.isEmpty()) {
- m_receivedDatagrams.append(data);
- emit q->readyRead();
- }
- socketState = Idle;
- enteringIdle();*/
-}
-
-void QLlcpSocketPrivate::dataWritten()
-{
- //enteringIdle();
-}
-
-void QLlcpSocketPrivate::read()
-{
- /*if (socketState != Idle) {
- qQNXNFCDebug() << "Trying to read but socket state not in idle..abort";
- return;
- }
- socketState = Reading;
- qQNXNFCDebug() << "LLCP read";
- if (nfc_llcp_read(m_target, 128) != NFC_RESULT_SUCCESS) {
- qWarning() << Q_FUNC_INFO << "Could not register for reading";
- socketState = Idle;
- }*/
-}
-
-void QLlcpSocketPrivate::enteringIdle()
-{
- /*qQNXNFCDebug() << "entering idle; Socket state:" << socketState;
- socketState = Idle;
- if (m_state == QLlcpSocket::ConnectedState) {
- if (m_writeQueue.isEmpty()) {
- qQNXNFCDebug() << "Write queue empty, reading in 50ms";
- QTimer::singleShot(50, this, SLOT(read()));
- } else {
- qQNXNFCDebug() << "Write first package in queue";
- writeDatagram(m_writeQueue.takeFirst());
- }
- }*/
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/nfc/qllcpsocket_android_p.h b/src/nfc/qllcpsocket_android_p.h
deleted file mode 100644
index 6109d7dd..00000000
--- a/src/nfc/qllcpsocket_android_p.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Centria research and development
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QLLCPSOCKET_ANDROID_P_H
-#define QLLCPSOCKET_ANDROID_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 "qllcpsocket_p.h"
-
-//#include "qnearfieldtarget_ANDROID_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QLlcpSocketPrivate : public QObject
-{
- Q_OBJECT
- Q_DECLARE_PUBLIC(QLlcpSocket)
-
-public:
- QLlcpSocketPrivate(QLlcpSocket *q);
-
- ~QLlcpSocketPrivate();
-
- void connectToService(QNearFieldTarget *target, const QString &serviceUri);
-
- bool bind(quint8 port);
-
- bool hasPendingDatagrams() const;
- qint64 pendingDatagramSize() const;
-
- qint64 writeDatagram(const char *data, qint64 size);
- qint64 writeDatagram(const QByteArray &datagram);
-
- qint64 readDatagram(char *data, qint64 maxSize,
- QNearFieldTarget **target = 0, quint8 *port = 0);
- qint64 writeDatagram(const char *data, qint64 size,
- QNearFieldTarget *target, quint8 port);
- qint64 writeDatagram(const QByteArray &datagram, QNearFieldTarget *target, quint8 port);
-
- QLlcpSocket::SocketError error() const;
- QLlcpSocket::SocketState state() const;
-
- qint64 readData(char *data, qint64 maxlen);
- qint64 writeData(const char *data, qint64 len);
-
- qint64 bytesAvailable() const;
- bool canReadLine() const;
-
- bool waitForReadyRead(int msecs);
- bool waitForBytesWritten(int msecs);
- bool waitForConnected(int msecs);
- bool waitForDisconnected(int msecs);
-
- //Q_INVOKABLE void connected(nfc_target_t *);
- Q_INVOKABLE void targetLost();
-
- void dataRead(QByteArray&);
- void dataWritten();
-
-public Q_SLOTS:
- void disconnectFromService();
-
-private:
- QLlcpSocket *q_ptr;
- unsigned int m_sap;
- //nfc_llcp_connection_listener_t m_conListener;
- //NearFieldTarget *m_target;
- //nfc_target_t *m_target;
-
- QLlcpSocket::SocketState m_state;
-
- QList<QByteArray> m_receivedDatagrams;
- QList<QByteArray> m_writeQueue;
-
- bool m_server;
-
- enum llcpState {
- Idle, Reading, Writing
- } socketState;
-
-private Q_SLOTS:
- void read();
- void enteringIdle();
-};
-
-QT_END_NAMESPACE
-
-#endif // QLLCPSOCKET_ANDROID_P_H
diff --git a/src/nfc/qllcpsocket_p.cpp b/src/nfc/qllcpsocket_p.cpp
deleted file mode 100644
index f604d551..00000000
--- a/src/nfc/qllcpsocket_p.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qllcpsocket_p_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QLlcpSocketPrivate::QLlcpSocketPrivate(QLlcpSocket *q)
-: q_ptr(q)
-{
-}
-
-QLlcpSocketPrivate::~QLlcpSocketPrivate()
-{
-
-}
-
-void QLlcpSocketPrivate::connectToService(QNearFieldTarget *target, const QString &serviceUri)
-{
- Q_UNUSED(target);
- Q_UNUSED(serviceUri);
-}
-
-void QLlcpSocketPrivate::disconnectFromService()
-{
-}
-
-bool QLlcpSocketPrivate::bind(quint8 port)
-{
- Q_UNUSED(port);
-
- return false;
-}
-
-bool QLlcpSocketPrivate::hasPendingDatagrams() const
-{
- return false;
-}
-
-qint64 QLlcpSocketPrivate::pendingDatagramSize() const
-{
- return -1;
-}
-
-qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size)
-{
- Q_UNUSED(data);
- Q_UNUSED(size);
-
- return -1;
-}
-
-qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram)
-{
- Q_UNUSED(datagram);
-
- return -1;
-}
-
-qint64 QLlcpSocketPrivate::readDatagram(char *data, qint64 maxSize,
- QNearFieldTarget **target, quint8 *port)
-{
- Q_UNUSED(data);
- Q_UNUSED(maxSize);
- Q_UNUSED(target);
- Q_UNUSED(port);
-
- return -1;
-}
-
-qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size,
- QNearFieldTarget *target, quint8 port)
-{
- Q_UNUSED(data);
- Q_UNUSED(size);
- Q_UNUSED(target);
- Q_UNUSED(port);
-
- return -1;
-}
-
-qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram,
- QNearFieldTarget *target, quint8 port)
-{
- Q_UNUSED(datagram);
- Q_UNUSED(target);
- Q_UNUSED(port);
-
- return -1;
-}
-
-QLlcpSocket::SocketError QLlcpSocketPrivate::error() const
-{
- return QLlcpSocket::UnknownSocketError;
-}
-
-QLlcpSocket::SocketState QLlcpSocketPrivate::state() const
-{
- return QLlcpSocket::UnconnectedState;
-}
-
-qint64 QLlcpSocketPrivate::readData(char *data, qint64 maxlen)
-{
- Q_UNUSED(data);
- Q_UNUSED(maxlen);
-
- return -1;
-}
-
-qint64 QLlcpSocketPrivate::writeData(const char *data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
-
- return -1;
-}
-
-qint64 QLlcpSocketPrivate::bytesAvailable() const
-{
- return 0;
-}
-
-bool QLlcpSocketPrivate::canReadLine() const
-{
- return false;
-}
-
-bool QLlcpSocketPrivate::waitForReadyRead(int msecs)
-{
- Q_UNUSED(msecs);
-
- return false;
-}
-
-bool QLlcpSocketPrivate::waitForBytesWritten(int msecs)
-{
- Q_UNUSED(msecs);
-
- return false;
-}
-
-bool QLlcpSocketPrivate::waitForConnected(int msecs)
-{
- Q_UNUSED(msecs);
-
- return false;
-}
-
-bool QLlcpSocketPrivate::waitForDisconnected(int msecs)
-{
- Q_UNUSED(msecs);
-
- return false;
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qllcpsocket_p.h b/src/nfc/qllcpsocket_p.h
deleted file mode 100644
index 442367c6..00000000
--- a/src/nfc/qllcpsocket_p.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QLLCPSOCKET_H
-#define QLLCPSOCKET_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 <QtNetwork/QAbstractSocket>
-#include <QtNfc/qtnfcglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-class QNearFieldTarget;
-class QLlcpSocketPrivate;
-
-class Q_NFC_EXPORT QLlcpSocket : public QIODevice
-{
- Q_OBJECT
-
- Q_DECLARE_PRIVATE(QLlcpSocket)
-
- friend class QLlcpServerPrivate;
-
-public:
- enum SocketState {
- UnconnectedState = QAbstractSocket::UnconnectedState,
- ConnectingState = QAbstractSocket::ConnectingState,
- ConnectedState = QAbstractSocket::ConnectedState,
- ClosingState = QAbstractSocket::ClosingState,
- BoundState = QAbstractSocket::BoundState,
- ListeningState = QAbstractSocket::ListeningState
- };
- Q_ENUM(SocketState)
-
- enum SocketError {
- UnknownSocketError = QAbstractSocket::UnknownSocketError,
- RemoteHostClosedError = QAbstractSocket::RemoteHostClosedError,
- SocketAccessError = QAbstractSocket::SocketAccessError,
- SocketResourceError = QAbstractSocket::SocketResourceError
- };
- Q_ENUM(SocketError)
-
- explicit QLlcpSocket(QObject *parent = 0);
- ~QLlcpSocket();
-
- void connectToService(QNearFieldTarget *target, const QString &serviceUri);
- void disconnectFromService();
-
- void close();
-
- bool bind(quint8 port);
-
- bool hasPendingDatagrams() const;
- qint64 pendingDatagramSize() const;
-
- qint64 writeDatagram(const char *data, qint64 size);
- qint64 writeDatagram(const QByteArray &datagram);
-
- qint64 readDatagram(char *data, qint64 maxSize,
- QNearFieldTarget **target = 0, quint8 *port = 0);
- qint64 writeDatagram(const char *data, qint64 size,
- QNearFieldTarget *target, quint8 port);
- qint64 writeDatagram(const QByteArray &datagram, QNearFieldTarget *target, quint8 port);
-
- SocketError error() const;
- SocketState state() const;
-
- qint64 bytesAvailable() const;
- bool canReadLine() const;
-
- bool waitForReadyRead(int msecs = 30000);
- bool waitForBytesWritten(int msecs = 30000);
- virtual bool waitForConnected(int msecs = 30000);
- virtual bool waitForDisconnected(int msecs = 30000);
- bool isSequential() const;
-
-signals:
- void connected();
- void disconnected();
- void error(QLlcpSocket::SocketError socketError);
- void stateChanged(QLlcpSocket::SocketState socketState);
-
-protected:
- qint64 readData(char *data, qint64 maxlen);
- qint64 writeData(const char *data, qint64 len);
-
-private:
- QLlcpSocket(QLlcpSocketPrivate *d, QObject *parent);
-
- QLlcpSocketPrivate *d_ptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QLLCPSOCKET_H
diff --git a/src/nfc/qllcpsocket_p_p.h b/src/nfc/qllcpsocket_p_p.h
deleted file mode 100644
index 9a747502..00000000
--- a/src/nfc/qllcpsocket_p_p.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QLLCPSOCKET_P_H
-#define QLLCPSOCKET_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 "qtnfcglobal.h"
-
-#include "qllcpsocket_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QLlcpSocketPrivate
-{
- Q_DECLARE_PUBLIC(QLlcpSocket)
-
-public:
- QLlcpSocketPrivate(QLlcpSocket *q);
-
- ~QLlcpSocketPrivate();
-
- void connectToService(QNearFieldTarget *target, const QString &serviceUri);
- void disconnectFromService();
-
- bool bind(quint8 port);
-
- bool hasPendingDatagrams() const;
- qint64 pendingDatagramSize() const;
-
- qint64 writeDatagram(const char *data, qint64 size);
- qint64 writeDatagram(const QByteArray &datagram);
-
- qint64 readDatagram(char *data, qint64 maxSize,
- QNearFieldTarget **target = 0, quint8 *port = 0);
- qint64 writeDatagram(const char *data, qint64 size,
- QNearFieldTarget *target, quint8 port);
- qint64 writeDatagram(const QByteArray &datagram, QNearFieldTarget *target, quint8 port);
-
- QLlcpSocket::SocketError error() const;
- QLlcpSocket::SocketState state() const;
-
- qint64 readData(char *data, qint64 maxlen);
- qint64 writeData(const char *data, qint64 len);
-
- qint64 bytesAvailable() const;
- bool canReadLine() const;
-
- bool waitForReadyRead(int msecs);
- bool waitForBytesWritten(int msecs);
- bool waitForConnected(int msecs);
- bool waitForDisconnected(int msecs);
-
-private:
- QLlcpSocket *q_ptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QLLCPSOCKET_P_H
diff --git a/src/nfc/qndeffilter.cpp b/src/nfc/qndeffilter.cpp
index 486ac633..4bbd0ef7 100644
--- a/src/nfc/qndeffilter.cpp
+++ b/src/nfc/qndeffilter.cpp
@@ -1,45 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qndeffilter.h"
+#include "qndefmessage.h"
#include <QtCore/QList>
+#include <QtCore/QMap>
QT_BEGIN_NAMESPACE
@@ -51,9 +17,8 @@ QT_BEGIN_NAMESPACE
\inmodule QtNfc
\since 5.2
- The QNdefFilter encapsulates the structure of an NDEF message and is used by
- QNearFieldManager::registerNdefMessageHandler() to match NDEF message that have a particular
- structure.
+ The QNdefFilter encapsulates the structure of an NDEF message and is used for
+ matching messages that have a particular structure.
The following filter matches NDEF messages that contain a single smart poster record:
@@ -72,13 +37,185 @@ QT_BEGIN_NAMESPACE
filter.appendRecord<QNdefNfcTextRecord>();
filter.appendRecord(QNdefRecord::Mime, "image/jpeg", 0, 1);
\endcode
+
+ The \l match() method can be used to check if a message matches the filter.
+
+ \section1 Matching Algorithms
+
+ The filter behavior depends on the value of \l orderMatch() parameter.
+
+ \note In the discussion below we will consider the filter records to be
+ equal if their \c typeNameFormat and \c type parameters match. Joining
+ two records means adding their \c minimum and \c maximum values,
+ respectively.
+
+ \section2 Unordered Matching
+
+ If the record order is not taken into account, all the equal records in the
+ filter can be joined. The resulting filter will contain only unique records,
+ each with the updated \c minimum and \c maximum value.
+
+ Consider the following example:
+
+ \code
+ QNdefFilter filter;
+ filter.appendRecord<QNdefNfcTextRecord>(0, 1);
+ filter.appendRecord<QNdefNfcTextRecord>(0, 1);
+ filter.appendRecord(QNdefRecord::Mime, "", 1, 1);
+ filter.appendRecord<QNdefNfcTextRecord>(1, 1);
+ filter.setOrderMatch(false);
+ \endcode
+
+ With the unordered matching, the filter will be simplified to the following:
+
+ \code
+ QNdefFilter filter;
+ filter.appendRecord<QNdefNfcTextRecord>(1, 3);
+ filter.appendRecord(QNdefRecord::Mime, "", 1, 1);
+ filter.setOrderMatch(false);
+ \endcode
+
+ Once the filter contains only the unique records, the matching algorithm
+ iterates through the message and calculates the actual amount of records of
+ each type. If all the actual amounts fit in the corresponding
+ [minimum, maximum] ranges, the matching algorithm returns \c true.
+
+ \section2 Ordered Matching
+
+ If the record order is important, a different approach is applied. In this
+ case the equal records can't be simply joined together. However, the
+ consecutive equal records can still be joined. Then, the matching
+ algorithm iterates through the message, this time also taking the positions
+ of the records into account.
+
+ \section2 Handling Empty Type in Filter Record
+
+ It's possible to add a filter record with an empty \c type. In this case
+ the empty type will act as a wildcard for any type.
+
+ For example, the filter can be defined as follows:
+
+ \code
+ QNdefFilter filter;
+ filter.addRecord(QNdefRecord::Mime, "", 1, 1);
+ \endcode
+
+ This filter specifies that the message must contain exactly one NDEF record
+ with \l {QNdefRecord::}{Mime} \l {QNdefRecord::}{typeNameFormat}(), and any
+ \l {QNdefRecord::}{type}().
+
+ \section2 Handling Extra Records in the Message
+
+ If the message contains some records that do not match \e any record in the
+ filter, the matching algorithm will return \c false.
+
+ \section2 Filter Examples
+
+ In the table below, each filter record is specified by the following
+ parameters (in the given order):
+
+ \list
+ \li \c typeNameFormat - contains the \l {QNdefRecord::}{typeNameFormat}() of
+ the record.
+ \li \c type - contains the \l {QNdefRecord::}{type}() of the record.
+ \li \c minimum - contains the minimum amount of occurrences of the record
+ in the message.
+ \li \c maximum - contains the maximum amount of occurrences of the record
+ in the message.
+ \endlist
+
+ The filter contains multiple records.
+
+ The message consists of multiple \l {QNdefRecord}s. In the table below, only
+ the \l {QNdefRecord::}{typeNameFormat}() and \l {QNdefRecord::}{type}() of
+ each record will be shown, because the other parameters do not matter for
+ filtering.
+
+ \table
+ \header
+ \li Filter
+ \li Message
+ \li Match Result
+ \li Comment
+ \row
+ \li Empty filter
+ \li Empty message
+ \li Match
+ \li
+ \row
+ \li Empty filter
+ \li Non-empty message
+ \li No match
+ \li
+ \row
+ \li Non-empty filter
+ \li Empty message
+ \li No match
+ \li
+ \row
+ \li {1, 2}[(QNdefRecord::NfcRtd, "T", 1, 2),
+ (QNdefRecord::Mime, "", 1, 1), (QNdefRecord::Empty, "", 0, 100)]
+ \li {1, 2}[(QNdefRecord::Mime, "image/jpeg"), (QNdefRecord::Empty, ""),
+ (QNdefRecord::NfcRtd, "T"), (QNdefRecord::Empty, ""),
+ (QNdefRecord::NfcRtd, "T")]
+ \li Unordered: match
+ \li {1, 2} Ordered filter does not match because the message must start
+ with a QNdefRecord::NfcRtd record, but it starts with
+ QNdefRecord::Mime.
+ \row
+ \li Ordered: no match
+ \row
+ \li {1, 2}[(QNdefRecord::NfcRtd, "T", 0, 2),
+ (QNdefRecord::Mime, "", 1, 1), (QNdefRecord::NfcRtd, "T", 1, 1)]
+ \li {1, 2}[(QNdefRecord::NfcRtd, "T"), (QNdefRecord::NfcRtd, "T"),
+ (QNdefRecord::Mime, "image/jpeg")]
+ \li Unordered: match
+ \li {1, 2} Ordered filter does not match because an QNdefRecord::NfcRtd
+ record is expected after QNdefRecord::Mime, but the message does not
+ have it.
+ \row
+ \li Ordered: no match
+ \row
+ \li {1, 2}[(QNdefRecord::NfcRtd, "T", 0, 2),
+ (QNdefRecord::NfcRtd, "T", 1, 1), (QNdefRecord::Mime, "", 1, 1)]
+ \li {1, 2}[(QNdefRecord::NfcRtd, "T"),
+ (QNdefRecord::Mime, "image/jpeg")]
+ \li Unordered: match
+ \li {1, 2} Both cases match because the message contains the required
+ minimum of records in the correct order.
+ \row
+ \li Ordered: match
+ \endtable
+
*/
/*!
- \fn void QNdefFilter::appendRecord(unsigned int min, unsigned int max)
+ \class QNdefFilter::Record
+ \brief The QNdefFilter::Record struct contains the information about a
+ filter record.
- Appends a record matching the template parameter to the NDEF filter. The record must occur
- between \a min and \a max times in the NDEF message.
+ \ingroup connectivity-nfc
+ \inmodule QtNfc
+ \since 5.2
+
+ The QNdefFilter::Record struct is used to populate the QNdefFilter object.
+ Each record contains the following information:
+ \list
+ \li \l {QNdefRecord::TypeNameFormat} of the corresponding \l QNdefRecord.
+ \li Type of the \l QNdefRecord.
+ \li Minimum and maximum amount of the records with such parameters in the
+ filter.
+ \endlist
+*/
+
+/*!
+ \fn template<typename T> bool QNdefFilter::appendRecord(unsigned int min, unsigned int max)
+
+ Appends a record matching the template parameter to the NDEF filter.
+ The record must occur between \a min and \a max times in the NDEF message.
+
+ Returns \c true if the record was appended successfully. Otherwise returns
+ \c false.
*/
class QNdefFilterPrivate : public QSharedData
@@ -104,7 +241,7 @@ QNdefFilter::QNdefFilter()
}
/*!
- constructs a new NDEF filter that is a copy of \a other.
+ Constructs a new NDEF filter that is a copy of \a other.
*/
QNdefFilter::QNdefFilter(const QNdefFilter &other)
: d(other.d)
@@ -130,6 +267,132 @@ QNdefFilter &QNdefFilter::operator=(const QNdefFilter &other)
}
/*!
+ \since 6.2
+
+ Returns \c true if the \a message matches the given filter.
+ Otherwise returns \c false.
+
+ See \l {Matching Algorithms} for more detailed explanation of matching.
+*/
+bool QNdefFilter::match(const QNdefMessage &message) const
+{
+ // empty filter matches only empty message
+ if (d->filterRecords.isEmpty())
+ return message.isEmpty();
+
+ bool matched = true;
+ int totalCount = 0;
+
+ if (!d->orderMatching) {
+ // Order is not important. The most reliable way is to merge all the
+ // similar records, and then simply check the amount of occurrences.
+ using MapKey = QPair<QNdefRecord::TypeNameFormat, QByteArray>;
+
+ // Creating a map from the list of filter records.
+ QMap<MapKey, Record> joinedFilterRecords;
+ for (const auto &rec : d->filterRecords) {
+ const auto key = qMakePair(rec.typeNameFormat, rec.type);
+ if (joinedFilterRecords.contains(key)) {
+ joinedFilterRecords[key].minimum += rec.minimum;
+ joinedFilterRecords[key].maximum += rec.maximum;
+ } else {
+ joinedFilterRecords.insert(key, rec);
+ }
+ }
+ // Checking the message, calculate occurrences.
+ QMap<MapKey, unsigned int> counts; // current number of occurrences
+ for (const auto &record : message) {
+ const auto key = qMakePair(record.typeNameFormat(), record.type());
+ // Do not forget that we handle an empty type as "any type".
+ const auto emptyTypeKey = qMakePair(record.typeNameFormat(), QByteArray());
+
+ if (joinedFilterRecords.contains(key))
+ counts[key] += 1;
+ else if (joinedFilterRecords.contains(emptyTypeKey))
+ counts[emptyTypeKey] += 1;
+ }
+ // Check that the occurrences match [min; max] range.
+ for (auto it = joinedFilterRecords.cbegin(); it != joinedFilterRecords.cend(); ++it) {
+ const auto count = counts.value(it.key(), 0);
+ totalCount += count;
+ if (count < it.value().minimum || count > it.value().maximum) {
+ matched = false;
+ break;
+ }
+ }
+ } else {
+ // Order *is* important. Need to iterate the list.
+
+ // Here we need to merge consecutive records with the same parameters.
+ QList<Record> mergedRecords;
+ // we know that filer is not empty here
+ Record currentRecord = d->filterRecords.first();
+ for (qsizetype i = 1; i < d->filterRecords.size(); ++i) {
+ const auto &rec = d->filterRecords.at(i);
+ if (rec.typeNameFormat == currentRecord.typeNameFormat
+ && rec.type == currentRecord.type) {
+ currentRecord.minimum += rec.minimum;
+ currentRecord.maximum += rec.maximum;
+ } else {
+ mergedRecords.push_back(currentRecord);
+ currentRecord = rec;
+ }
+ }
+ mergedRecords.push_back(currentRecord);
+
+ // The list contains the current number of occurrences of each record.
+ QList<unsigned int> counts(mergedRecords.size(), 0);
+
+ // Iterate through the messages and calculate the number of occurrences.
+ qsizetype filterIndex = 0;
+ for (qsizetype messageIndex = 0; matched && messageIndex < message.size(); ++messageIndex) {
+ const auto &messageRec = message.at(messageIndex);
+ // Try to find a filter record that matches the message record.
+ // We start from the last processed filter record, not from the very
+ // beginning (because the order matters).
+ qsizetype idx = filterIndex;
+ for (; idx < mergedRecords.size(); ++idx) {
+ const auto &filterRec = mergedRecords.at(idx);
+ if (filterRec.typeNameFormat == messageRec.typeNameFormat()
+ && (filterRec.type == messageRec.type() || filterRec.type.isEmpty())) {
+ counts[idx] += 1;
+ break;
+ } else if (counts[idx] < filterRec.minimum || counts[idx] > filterRec.maximum) {
+ // The current message record does not match the current
+ // filter record, but we didn't get enough records to
+ // fulfill the filter => that's an error.
+ matched = false;
+ break;
+ }
+ }
+ filterIndex = idx;
+ }
+
+ if (matched) {
+ // Check that the occurrences match [min; max] range.
+ for (qsizetype i = 0; i < mergedRecords.size(); ++i) {
+ const auto &rec = mergedRecords.at(i);
+ totalCount += counts[i];
+ if (counts[i] < rec.minimum || counts[i] > rec.maximum) {
+ matched = false;
+ break;
+ }
+ }
+ }
+ }
+
+ // Check if the message has records that do not match any record from the
+ // filter. To do it we just need to compare the total count of records,
+ // detected by filter, with the full message size. If they do not match,
+ // we have some records, that are not covered by the filter.
+ if (matched && (totalCount != message.size())) {
+ matched = false;
+ }
+
+ return matched;
+}
+
+/*!
Clears the filter.
*/
void QNdefFilter::clear()
@@ -139,9 +402,10 @@ void QNdefFilter::clear()
}
/*!
- Sets the ording requirements of the filter. If \a on is true the filter will only match if the
- order of records in the filter matches the order of the records in the NDEF message. If \a on
- is false the order of the records is not taken into account when matching.
+ Sets the ordering requirements of the filter. If \a on is \c {true}, the
+ filter will only match if the order of records in the filter matches the
+ order of the records in the NDEF message. If \a on is \c {false}, the order
+ of the records is not taken into account when matching.
By default record order is not taken into account.
*/
@@ -151,8 +415,8 @@ void QNdefFilter::setOrderMatch(bool on)
}
/*!
- Returns true if the filter takes NDEF record order into account when matching; otherwise
- returns false.
+ Returns \c true if the filter takes NDEF record order into account when
+ matching. Otherwise returns \c false.
*/
bool QNdefFilter::orderMatch() const
{
@@ -160,10 +424,14 @@ bool QNdefFilter::orderMatch() const
}
/*!
- Appends a record with type name format \a typeNameFormat and type \a type to the NDEF filter.
- The record must occur between \a min and \a max times in the NDEF message.
+ Appends a record with type name format \a typeNameFormat and type \a type
+ to the NDEF filter. The record must occur between \a min and \a max times
+ in the NDEF message.
+
+ Returns \c true if the record was appended successfully. Otherwise returns
+ \c false.
*/
-void QNdefFilter::appendRecord(QNdefRecord::TypeNameFormat typeNameFormat, const QByteArray &type,
+bool QNdefFilter::appendRecord(QNdefRecord::TypeNameFormat typeNameFormat, const QByteArray &type,
unsigned int min, unsigned int max)
{
QNdefFilter::Record record;
@@ -173,21 +441,37 @@ void QNdefFilter::appendRecord(QNdefRecord::TypeNameFormat typeNameFormat, const
record.minimum = min;
record.maximum = max;
- d->filterRecords.append(record);
+ return appendRecord(record);
+}
+
+static bool verifyRecord(const QNdefFilter::Record &record)
+{
+ return record.minimum <= record.maximum;
}
/*!
- Appends \a record to the NDEF filter.
+ Verifies the \a record and appends it to the NDEF filter.
+
+ Returns \c true if the record was appended successfully. Otherwise returns
+ \c false.
*/
-void QNdefFilter::appendRecord(const Record &record)
+bool QNdefFilter::appendRecord(const Record &record)
{
- d->filterRecords.append(record);
+ if (verifyRecord(record)) {
+ d->filterRecords.append(record);
+ return true;
+ }
+ return false;
}
/*!
Returns the NDEF record at index \a i.
+
+ \a i must be a valid index (i.e. 0 <= i < \l recordCount()).
+
+ \sa recordCount()
*/
-QNdefFilter::Record QNdefFilter::recordAt(int i) const
+QNdefFilter::Record QNdefFilter::recordAt(qsizetype i) const
{
return d->filterRecords.at(i);
}
@@ -195,9 +479,9 @@ QNdefFilter::Record QNdefFilter::recordAt(int i) const
/*!
Returns the number of NDEF records in the filter.
*/
-int QNdefFilter::recordCount() const
+qsizetype QNdefFilter::recordCount() const
{
- return d->filterRecords.count();
+ return d->filterRecords.size();
}
QT_END_NAMESPACE
diff --git a/src/nfc/qndeffilter.h b/src/nfc/qndeffilter.h
index 26327067..693342e6 100644
--- a/src/nfc/qndeffilter.h
+++ b/src/nfc/qndeffilter.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNDEFFILTER_H
#define QNDEFFILTER_H
@@ -46,6 +10,8 @@
QT_BEGIN_NAMESPACE
+class QNdefMessage;
+
class QNdefFilterPrivate;
class Q_NFC_EXPORT QNdefFilter
{
@@ -67,26 +33,28 @@ public:
};
template<typename T>
- void appendRecord(unsigned int min = 1, unsigned int max = 1);
- void appendRecord(QNdefRecord::TypeNameFormat typeNameFormat, const QByteArray &type,
+ bool appendRecord(unsigned int min = 1, unsigned int max = 1);
+ bool appendRecord(QNdefRecord::TypeNameFormat typeNameFormat, const QByteArray &type,
unsigned int min = 1, unsigned int max = 1);
- void appendRecord(const Record &record);
+ bool appendRecord(const Record &record);
- int recordCount() const;
- Record recordAt(int i) const;
+ qsizetype recordCount() const;
+ Record recordAt(qsizetype i) const;
QNdefFilter &operator=(const QNdefFilter &other);
+ bool match(const QNdefMessage &message) const;
+
private:
QSharedDataPointer<QNdefFilterPrivate> d;
};
template <typename T>
-void QNdefFilter::appendRecord(unsigned int min, unsigned int max)
+bool QNdefFilter::appendRecord(unsigned int min, unsigned int max)
{
T record;
- appendRecord(record.typeNameFormat(), record.type(), min, max);
+ return appendRecord(record.typeNameFormat(), record.type(), min, max);
}
QT_END_NAMESPACE
diff --git a/src/nfc/qndefmessage.cpp b/src/nfc/qndefmessage.cpp
index 58a572c8..443d43e6 100644
--- a/src/nfc/qndefmessage.cpp
+++ b/src/nfc/qndefmessage.cpp
@@ -1,47 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qndefmessage.h"
#include "qndefrecord_p.h"
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QNdefMessage)
+
/*!
\class QNdefMessage
\brief The QNdefMessage class provides an NFC NDEF message.
@@ -101,17 +67,17 @@ QNdefMessage QNdefMessage::fromByteArray(const QByteArray &message)
QByteArray partialChunk;
QNdefRecord record;
- QByteArray::const_iterator i = message.begin();
- while (i < message.constEnd()) {
- quint8 flags = *i;
+ qsizetype idx = 0;
+ while (idx < message.size()) {
+ quint8 flags = message.at(idx);
- bool messageBegin = flags & 0x80;
- bool messageEnd = flags & 0x40;
+ const bool messageBegin = flags & 0x80;
+ const bool messageEnd = flags & 0x40;
- bool cf = flags & 0x20;
- bool sr = flags & 0x10;
- bool il = flags & 0x08;
- quint8 typeNameFormat = flags & 0x07;
+ const bool cf = flags & 0x20;
+ const bool sr = flags & 0x10;
+ const bool il = flags & 0x08;
+ const quint8 typeNameFormat = flags & 0x07;
if (messageBegin && seenMessageBegin) {
qWarning("Got message begin but already parsed some records");
@@ -128,8 +94,9 @@ QNdefMessage QNdefMessage::fromByteArray(const QByteArray &message)
} else if (messageEnd && !seenMessageEnd) {
seenMessageEnd = true;
}
- if (cf && (typeNameFormat != 0x06) && !partialChunk.isEmpty()) {
- qWarning("partial chunk not empty or typeNameFormat not 0x06 as expected");
+ // TNF must be 0x06 even for the last chunk, when cf == 0.
+ if ((typeNameFormat != 0x06) && !partialChunk.isEmpty()) {
+ qWarning("Partial chunk not empty, but TNF not 0x06 as expected");
return QNdefMessage();
}
@@ -137,12 +104,12 @@ QNdefMessage QNdefMessage::fromByteArray(const QByteArray &message)
headerLength += (sr) ? 1 : 4;
headerLength += (il) ? 1 : 0;
- if (i + headerLength >= message.constEnd()) {
+ if (idx + headerLength >= message.size()) {
qWarning("Unexpected end of message");
return QNdefMessage();
}
- quint8 typeLength = *(++i);
+ const quint8 typeLength = message.at(++idx);
if ((typeNameFormat == 0x06) && (typeLength != 0)) {
qWarning("Invalid chunked data, TYPE_LENGTH != 0");
@@ -151,27 +118,40 @@ QNdefMessage QNdefMessage::fromByteArray(const QByteArray &message)
quint32 payloadLength;
if (sr)
- payloadLength = quint8(*(++i));
+ payloadLength = quint8(message.at(++idx));
else {
- payloadLength = quint8(*(++i)) << 24;
- payloadLength |= quint8(*(++i)) << 16;
- payloadLength |= quint8(*(++i)) << 8;
- payloadLength |= quint8(*(++i)) << 0;
+ payloadLength = quint8(message.at(++idx)) << 24;
+ payloadLength |= quint8(message.at(++idx)) << 16;
+ payloadLength |= quint8(message.at(++idx)) << 8;
+ payloadLength |= quint8(message.at(++idx)) << 0;
}
quint8 idLength;
if (il)
- idLength = *(++i);
+ idLength = message.at(++idx);
else
idLength = 0;
- int contentLength = typeLength + payloadLength + idLength;
- if (i + contentLength >= message.constEnd()) {
+ // On 32-bit systems this can overflow
+ const qsizetype convertedPayloadLength = static_cast<qsizetype>(payloadLength);
+ const qsizetype contentLength = convertedPayloadLength + typeLength + idLength;
+
+ // On a 32 bit platform the payload can theoretically exceed the max.
+ // size of a QByteArray. This will never happen in practice with correct
+ // data because there are no NFC tags that can store such data sizes,
+ // but still can be possible if the data is corrupted.
+ if ((contentLength < 0) || (convertedPayloadLength < 0)
+ || ((std::numeric_limits<qsizetype>::max() - idx) < contentLength)) {
+ qWarning("Payload can't fit into QByteArray");
+ return QNdefMessage();
+ }
+
+ if (idx + contentLength >= message.size()) {
qWarning("Unexpected end of message");
return QNdefMessage();
}
- if ((typeNameFormat == 0x06) && (idLength != 0)) {
+ if ((typeNameFormat == 0x06) && il) {
qWarning("Invalid chunked data, IL != 0");
return QNdefMessage();
}
@@ -180,20 +160,19 @@ QNdefMessage QNdefMessage::fromByteArray(const QByteArray &message)
record.setTypeNameFormat(QNdefRecord::TypeNameFormat(typeNameFormat));
if (typeLength > 0) {
- QByteArray type(++i, typeLength);
+ QByteArray type(&message.constData()[++idx], typeLength);
record.setType(type);
- i += typeLength - 1;
+ idx += typeLength - 1;
}
if (idLength > 0) {
- QByteArray id(++i, idLength);
+ QByteArray id(&message.constData()[++idx], idLength);
record.setId(id);
- i += idLength - 1;
+ idx += idLength - 1;
}
if (payloadLength > 0) {
- QByteArray payload(++i, payloadLength);
-
+ QByteArray payload(&message.constData()[++idx], payloadLength);
if (cf) {
// chunked payload, except last
@@ -207,7 +186,7 @@ QNdefMessage QNdefMessage::fromByteArray(const QByteArray &message)
record.setPayload(payload);
}
- i += payloadLength - 1;
+ idx += payloadLength - 1;
}
if (!cf) {
@@ -219,11 +198,11 @@ QNdefMessage QNdefMessage::fromByteArray(const QByteArray &message)
break;
// move to start of next record
- ++i;
+ ++idx;
}
- if (!seenMessageBegin && !seenMessageEnd) {
- qWarning("Malformed NDEF Message, missing begin or end.");
+ if (!seenMessageBegin || !seenMessageEnd) {
+ qWarning("Malformed NDEF Message, missing begin or end");
return QNdefMessage();
}
@@ -231,10 +210,33 @@ QNdefMessage QNdefMessage::fromByteArray(const QByteArray &message)
}
/*!
- Returns true if this NDEF message is equivalent to \a other; otherwise returns false.
+ \fn QNdefMessage &QNdefMessage::operator=(const QNdefMessage &other)
+ \overload
+ \since 6.2
+
+ Copy assignment operator from QList<QNdefRecord>. Assigns the
+ \a other list of NDEF records to this NDEF record list.
+
+ After the operation, \a other and \c *this will be equal.
+*/
+
+/*!
+ \fn QNdefMessage &QNdefMessage::operator=(QNdefMessage &&other)
+ \overload
+ \since 6.2
+
+ Move assignment operator from QList<QNdefRecord>. Moves the
+ \a other list of NDEF records to this NDEF record list.
+
+ After the operation, \a other will be empty.
+*/
+
+/*!
+ Returns \c true if this NDEF message is equivalent to \a other; otherwise
+ returns \c false.
- An empty message (i.e. isEmpty() returns true) is equivalent to a NDEF message containing a
- single record of type QNdefRecord::Empty.
+ An empty message (i.e. isEmpty() returns \c true) is equivalent to a NDEF
+ message containing a single record of type \l QNdefRecord::Empty.
*/
bool QNdefMessage::operator==(const QNdefMessage &other) const
{
@@ -243,15 +245,15 @@ bool QNdefMessage::operator==(const QNdefMessage &other) const
return true;
// compare empty to really empty
- if (isEmpty() && other.count() == 1 && other.first().typeNameFormat() == QNdefRecord::Empty)
+ if (isEmpty() && other.size() == 1 && other.first().typeNameFormat() == QNdefRecord::Empty)
return true;
- if (other.isEmpty() && count() == 1 && first().typeNameFormat() == QNdefRecord::Empty)
+ if (other.isEmpty() && size() == 1 && first().typeNameFormat() == QNdefRecord::Empty)
return true;
- if (count() != other.count())
+ if (size() != other.size())
return false;
- for (int i = 0; i < count(); ++i) {
+ for (qsizetype i = 0; i < size(); ++i) {
if (at(i) != other.at(i))
return false;
}
@@ -273,31 +275,31 @@ QByteArray QNdefMessage::toByteArray() const
QByteArray m;
- for (int i = 0; i < count(); ++i) {
+ for (qsizetype i = 0; i < size(); ++i) {
const QNdefRecord &record = at(i);
quint8 flags = record.typeNameFormat();
if (i == 0)
flags |= 0x80;
- if (i == count() - 1)
+ if (i == size() - 1)
flags |= 0x40;
// cf (chunked records) not supported yet
- if (record.payload().length() < 255)
+ if (record.payload().size() < 255)
flags |= 0x10;
if (!record.id().isEmpty())
flags |= 0x08;
m.append(flags);
- m.append(record.type().length());
+ m.append(record.type().size());
if (flags & 0x10) {
- m.append(quint8(record.payload().length()));
+ m.append(quint8(record.payload().size()));
} else {
- quint32 length = record.payload().length();
+ quint32 length = record.payload().size();
m.append(length >> 24);
m.append(length >> 16);
m.append(length >> 8);
@@ -305,7 +307,7 @@ QByteArray QNdefMessage::toByteArray() const
}
if (flags & 0x08)
- m.append(record.id().length());
+ m.append(record.id().size());
if (!record.type().isEmpty())
m.append(record.type());
diff --git a/src/nfc/qndefmessage.h b/src/nfc/qndefmessage.h
index 59dedaa8..ba840d10 100644
--- a/src/nfc/qndefmessage.h
+++ b/src/nfc/qndefmessage.h
@@ -1,46 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNDEFMESSAGE_H
#define QNDEFMESSAGE_H
-#include <QtCore/QVector>
#include <QtCore/QSet>
#include <QtCore/QList>
#include <QtCore/QMetaType>
@@ -49,23 +12,39 @@
QT_BEGIN_NAMESPACE
-class Q_NFC_EXPORT QNdefMessage : public QList<QNdefRecord>
+// This class used to be exported exposing QList methods, see QTBUG-102367.
+#if defined(QT_BUILD_NFC_LIB)
+# define Q_NFC_EXPORT_COMPAT QT6_ONLY(Q_NFC_EXPORT)
+#else
+# define Q_NFC_EXPORT_COMPAT
+#endif
+
+class QNdefMessage : public QList<QNdefRecord>
{
public:
- inline QNdefMessage() { }
- inline explicit QNdefMessage(const QNdefRecord &record) { append(record); }
- inline QNdefMessage(const QNdefMessage &message) : QList<QNdefRecord>(message) { }
- inline QNdefMessage(const QList<QNdefRecord> &records) : QList<QNdefRecord>(records) { }
+ Q_NFC_EXPORT_COMPAT
+ QNdefMessage() = default;
+ Q_NFC_EXPORT_COMPAT
+ explicit QNdefMessage(const QNdefRecord &record) { append(record); }
+ Q_NFC_EXPORT_COMPAT
+ QNdefMessage(const QNdefMessage &message) = default;
+ Q_NFC_EXPORT_COMPAT
+ QNdefMessage(const QList<QNdefRecord> &records) : QList<QNdefRecord>(records) { }
+
+ Q_NFC_EXPORT_COMPAT
+ QNdefMessage &operator=(const QNdefMessage &other) = default;
+ Q_NFC_EXPORT_COMPAT
+ QNdefMessage &operator=(QNdefMessage &&other) noexcept = default;
- bool operator==(const QNdefMessage &other) const;
+ Q_NFC_EXPORT bool operator==(const QNdefMessage &other) const;
- QByteArray toByteArray() const;
+ Q_NFC_EXPORT QByteArray toByteArray() const;
- static QNdefMessage fromByteArray(const QByteArray &message);
+ Q_NFC_EXPORT static QNdefMessage fromByteArray(const QByteArray &message);
};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QNdefMessage)
+QT_DECL_METATYPE_EXTERN(QNdefMessage, Q_NFC_EXPORT)
#endif // QNDEFMESSAGE_H
diff --git a/src/nfc/qndefnfcsmartposterrecord.cpp b/src/nfc/qndefnfcsmartposterrecord.cpp
index bc7acfab..866abeed 100644
--- a/src/nfc/qndefnfcsmartposterrecord.cpp
+++ b/src/nfc/qndefnfcsmartposterrecord.cpp
@@ -1,41 +1,5 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 - 2012 Research In Motion
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qndefnfcsmartposterrecord.h>
#include "qndefnfcsmartposterrecord_p.h"
@@ -48,6 +12,32 @@
QT_BEGIN_NAMESPACE
/*!
+ \class QNdefNfcIconRecord
+ \brief The QNdefNfcIconRecord class provides an NFC MIME record to hold an
+ icon.
+
+ \ingroup connectivity-nfc
+ \inmodule QtNfc
+ \since Qt 5.2
+
+ This class wraps the image data into an NDEF message.
+ It provides an NDEF record of type \l QNdefRecord::Mime.
+ The \l {QNdefRecord::}{payload}() contains the raw image data.
+*/
+
+/*!
+ \fn QNdefNfcIconRecord::QNdefNfcIconRecord()
+
+ Constructs an empty NDEF record of type \l QNdefRecord::Mime.
+*/
+
+/*!
+ \fn QNdefNfcIconRecord::QNdefNfcIconRecord(const QNdefRecord &other)
+
+ Constructs an NDEF icon record that is a copy of \a other.
+*/
+
+/*!
\class QNdefNfcSmartPosterRecord
\brief The QNdefNfcSmartPosterRecord class provides an NFC RTD-SmartPoster.
@@ -183,7 +173,7 @@ void QNdefNfcSmartPosterRecord::convertToPayload()
QNdefMessage message;
// Title
- for (int t=0; t<titleCount(); t++)
+ for (qsizetype t = 0; t < titleCount(); t++)
message.append(titleRecord(t));
// URI
@@ -195,7 +185,7 @@ void QNdefNfcSmartPosterRecord::convertToPayload()
message.append(*(d->m_action));
// Icon
- for (int i=0; i<iconCount(); i++)
+ for (qsizetype i = 0; i < iconCount(); i++)
message.append(iconRecord(i));
// Size
@@ -210,13 +200,14 @@ void QNdefNfcSmartPosterRecord::convertToPayload()
}
/*!
- Returns true if the smart poster contains a title record using locale \a locale. If \a locale
- is empty then true is returned if the smart poster contains at least one title record. In all
- cases false is returned.
+ Returns \c true if the smart poster contains a title record using the locale
+ \a locale. If \a locale is empty, then \c true is returned if the smart
+ poster contains at least one title record. In all other cases, \c false is
+ returned.
*/
bool QNdefNfcSmartPosterRecord::hasTitle(const QString &locale) const
{
- for (int i = 0; i < d->m_titleList.length(); ++i) {
+ for (qsizetype i = 0; i < d->m_titleList.size(); ++i) {
const QNdefNfcTextRecord &text = d->m_titleList[i];
if (locale.isEmpty() || text.locale() == locale)
@@ -227,21 +218,23 @@ bool QNdefNfcSmartPosterRecord::hasTitle(const QString &locale) const
}
/*!
- Returns true if the smart poster contains an action record, otherwise false.
+ Returns \c true if the smart poster contains an action record, otherwise
+ returns \c false.
*/
bool QNdefNfcSmartPosterRecord::hasAction() const
{
- return d->m_action != 0;
+ return d->m_action != nullptr;
}
/*!
- Returns true if the smart poster contains an icon record using type \a mimetype.
- If \a mimetype is empty then true is returned if the smart poster contains at least one icon record.
- In all other cases false is returned.
+ Returns \c true if the smart poster contains an icon record using the type
+ \a mimetype. If \a mimetype is empty, then \c true is returned if the smart
+ poster contains at least one icon record.
+ In all other cases, \c false is returned.
*/
bool QNdefNfcSmartPosterRecord::hasIcon(const QByteArray &mimetype) const
{
- for (int i = 0; i < d->m_iconList.length(); ++i) {
+ for (qsizetype i = 0; i < d->m_iconList.size(); ++i) {
const QNdefNfcIconRecord &icon = d->m_iconList[i];
if (mimetype.isEmpty() || icon.type() == mimetype)
@@ -252,35 +245,39 @@ bool QNdefNfcSmartPosterRecord::hasIcon(const QByteArray &mimetype) const
}
/*!
- Returns true if the smart poster contains a size record, otherwise false.
+ Returns \c true if the smart poster contains a size record, otherwise
+ returns \c false.
*/
bool QNdefNfcSmartPosterRecord::hasSize() const
{
- return d->m_size != 0;
+ return d->m_size != nullptr;
}
/*!
- Returns true if the smart poster contains a type record, otherwise false.
+ Returns \c true if the smart poster contains a type record, otherwise
+ returns \c false.
*/
bool QNdefNfcSmartPosterRecord::hasTypeInfo() const
{
- return d->m_type != 0;
+ return d->m_type != nullptr;
}
/*!
Returns the number of title records contained inside the smart poster.
*/
-int QNdefNfcSmartPosterRecord::titleCount() const
+qsizetype QNdefNfcSmartPosterRecord::titleCount() const
{
- return d->m_titleList.length();
+ return d->m_titleList.size();
}
/*!
- Returns the title record corresponding to the index \a index inside the smart poster, where \a index is a value between 0 and titleCount() - 1. Values outside of this range return an empty record.
+ Returns the title record corresponding to the index \a index inside the
+ smart poster, where \a index is a value between 0 and titleCount() - 1.
+ Values outside of this range return an empty record.
*/
-QNdefNfcTextRecord QNdefNfcSmartPosterRecord::titleRecord(const int index) const
+QNdefNfcTextRecord QNdefNfcSmartPosterRecord::titleRecord(qsizetype index) const
{
- if (index >= 0 && index < d->m_titleList.length())
+ if (index >= 0 && index < d->m_titleList.size())
return d->m_titleList[index];
return QNdefNfcTextRecord();
@@ -293,7 +290,7 @@ QNdefNfcTextRecord QNdefNfcSmartPosterRecord::titleRecord(const int index) const
*/
QString QNdefNfcSmartPosterRecord::title(const QString &locale) const
{
- for (int i = 0; i < d->m_titleList.length(); ++i) {
+ for (qsizetype i = 0; i < d->m_titleList.size(); ++i) {
const QNdefNfcTextRecord &text = d->m_titleList[i];
if (locale.isEmpty() || text.locale() == locale)
@@ -314,21 +311,22 @@ QList<QNdefNfcTextRecord> QNdefNfcSmartPosterRecord::titleRecords() const
/*!
Attempts to add a title record \a text to the smart poster. If the smart poster does not already
contain a title record with the same locale as title record \a text, then the title record is added
- and the function returns true. Otherwise false is returned.
+ and the function returns \c true. Otherwise \c false is returned.
*/
bool QNdefNfcSmartPosterRecord::addTitle(const QNdefNfcTextRecord &text)
{
- bool status = addTitleInternal(text);
+ const bool status = addTitleInternal(text);
- // Convert to payload
- convertToPayload();
+ // Convert to payload if the title is added
+ if (status)
+ convertToPayload();
return status;
}
bool QNdefNfcSmartPosterRecord::addTitleInternal(const QNdefNfcTextRecord &text)
{
- for (int i = 0; i < d->m_titleList.length(); ++i) {
+ for (qsizetype i = 0; i < d->m_titleList.size(); ++i) {
const QNdefNfcTextRecord &rec = d->m_titleList[i];
if (rec.locale() == text.locale())
@@ -342,7 +340,7 @@ bool QNdefNfcSmartPosterRecord::addTitleInternal(const QNdefNfcTextRecord &text)
/*!
Attempts to add a new title record with title \a text, locale \a locale and encoding \a encoding.
If the smart poster does not already contain a title record with locale \a locale, then the title record
- is added and the function returns true. Otherwise false is returned.
+ is added and the function returns \c true. Otherwise \c false is returned.
*/
bool QNdefNfcSmartPosterRecord::addTitle(const QString &text, const QString &locale, QNdefNfcTextRecord::Encoding encoding)
{
@@ -355,14 +353,15 @@ bool QNdefNfcSmartPosterRecord::addTitle(const QString &text, const QString &loc
}
/*!
- Attempts to remove the title record \a text from the smart poster. Removes the record and returns true
- if the smart poster contains a matching record, otherwise false.
+ Attempts to remove the title record \a text from the smart poster. Removes
+ the record and returns \c true if the smart poster contains a matching
+ record, otherwise \c false is returned.
*/
bool QNdefNfcSmartPosterRecord::removeTitle(const QNdefNfcTextRecord &text)
{
bool status = false;
- for (int i = 0; i < d->m_titleList.length(); ++i) {
+ for (qsizetype i = 0; i < d->m_titleList.size(); ++i) {
const QNdefNfcTextRecord &rec = d->m_titleList[i];
if (rec.text() == text.text() && rec.locale() == text.locale() && rec.encoding() == text.encoding()) {
@@ -372,21 +371,23 @@ bool QNdefNfcSmartPosterRecord::removeTitle(const QNdefNfcTextRecord &text)
}
}
- // Convert to payload
- convertToPayload();
+ // Convert to payload if the title list has changed
+ if (status)
+ convertToPayload();
return status;
}
/*!
- Attempts to remove a title record with locale \a locale from the smart poster. Removes the record and returns true
- if the smart poster contains a matching record, otherwise false.
+ Attempts to remove a title record with the locale \a locale from the smart
+ poster. Removes the record and returns \c true if the smart poster contains
+ a matching record, otherwise \c false is returned.
*/
bool QNdefNfcSmartPosterRecord::removeTitle(const QString &locale)
{
bool status = false;
- for (int i = 0; i < d->m_titleList.length(); ++i) {
+ for (qsizetype i = 0; i < d->m_titleList.size(); ++i) {
const QNdefNfcTextRecord &rec = d->m_titleList[i];
if (rec.locale() == locale) {
@@ -396,8 +397,9 @@ bool QNdefNfcSmartPosterRecord::removeTitle(const QString &locale)
}
}
- // Convert to payload
- convertToPayload();
+ // Convert to payload if the title list has changed
+ if (status)
+ convertToPayload();
return status;
}
@@ -409,7 +411,7 @@ void QNdefNfcSmartPosterRecord::setTitles(const QList<QNdefNfcTextRecord> &title
{
d->m_titleList.clear();
- for (int i = 0; i < titles.length(); ++i) {
+ for (qsizetype i = 0; i < titles.size(); ++i) {
d->m_titleList.append(titles[i]);
}
@@ -492,17 +494,19 @@ void QNdefNfcSmartPosterRecord::setAction(Action act)
/*!
Returns the number of icon records contained inside the smart poster.
*/
-int QNdefNfcSmartPosterRecord::iconCount() const
+qsizetype QNdefNfcSmartPosterRecord::iconCount() const
{
- return d->m_iconList.length();
+ return d->m_iconList.size();
}
/*!
- Returns the icon record corresponding to the index \a index inside the smart poster, where \a index is a value between 0 and \l iconCount() - 1. Values outside of this range return an empty record.
+ Returns the icon record corresponding to the index \a index inside the smart
+ poster, where \a index is a value between 0 and \l iconCount() - 1.
+ Values outside of this range return an empty record.
*/
-QNdefNfcIconRecord QNdefNfcSmartPosterRecord::iconRecord(const int index) const
+QNdefNfcIconRecord QNdefNfcSmartPosterRecord::iconRecord(qsizetype index) const
{
- if (index >= 0 && index < d->m_iconList.length())
+ if (index >= 0 && index < d->m_iconList.size())
return d->m_iconList[index];
return QNdefNfcIconRecord();
@@ -514,7 +518,7 @@ QNdefNfcIconRecord QNdefNfcSmartPosterRecord::iconRecord(const int index) const
*/
QByteArray QNdefNfcSmartPosterRecord::icon(const QByteArray& mimetype) const
{
- for (int i = 0; i < d->m_iconList.length(); ++i) {
+ for (qsizetype i = 0; i < d->m_iconList.size(); ++i) {
const QNdefNfcIconRecord &icon = d->m_iconList[i];
if (mimetype.isEmpty() || icon.type() == mimetype)
@@ -546,7 +550,7 @@ void QNdefNfcSmartPosterRecord::addIcon(const QNdefNfcIconRecord &icon)
void QNdefNfcSmartPosterRecord::addIconInternal(const QNdefNfcIconRecord &icon)
{
- for (int i = 0; i < d->m_iconList.length(); ++i) {
+ for (qsizetype i = 0; i < d->m_iconList.size(); ++i) {
const QNdefNfcIconRecord &rec = d->m_iconList[i];
if (rec.type() == icon.type())
@@ -570,14 +574,15 @@ void QNdefNfcSmartPosterRecord::addIcon(const QByteArray &type, const QByteArray
}
/*!
- Attempts to remove the icon record \a icon from the smart poster. Removes the record and returns true
- if the smart poster contains a matching record, otherwise false.
+ Attempts to remove the icon record \a icon from the smart poster.
+ Removes the record and returns \c true if the smart poster contains
+ a matching record, otherwise \c false is returned.
*/
bool QNdefNfcSmartPosterRecord::removeIcon(const QNdefNfcIconRecord &icon)
{
bool status = false;
- for (int i = 0; i < d->m_iconList.length(); ++i) {
+ for (qsizetype i = 0; i < d->m_iconList.size(); ++i) {
const QNdefNfcIconRecord &rec = d->m_iconList[i];
if (rec.type() == icon.type() && rec.data() == icon.data()) {
@@ -587,21 +592,23 @@ bool QNdefNfcSmartPosterRecord::removeIcon(const QNdefNfcIconRecord &icon)
}
}
- // Convert to payload
- convertToPayload();
+ // Convert to payload if the icon list has changed
+ if (status)
+ convertToPayload();
return status;
}
/*!
- Attempts to remove the icon record with type \a type from the smart poster. Removes the record
- and returns true if the smart poster contains a matching record, otherwise false.
+ Attempts to remove the icon record with the type \a type from the smart
+ poster. Removes the record and returns \c true if the smart poster contains
+ a matching record, otherwise \c false is returned.
*/
bool QNdefNfcSmartPosterRecord::removeIcon(const QByteArray &type)
{
bool status = false;
- for (int i = 0; i < d->m_iconList.length(); ++i) {
+ for (qsizetype i = 0; i < d->m_iconList.size(); ++i) {
const QNdefNfcIconRecord &rec = d->m_iconList[i];
if (rec.type() == type) {
@@ -611,8 +618,9 @@ bool QNdefNfcSmartPosterRecord::removeIcon(const QByteArray &type)
}
}
- // Convert to payload
- convertToPayload();
+ // Convert to payload if the icon list has changed
+ if (status)
+ convertToPayload();
return status;
}
@@ -627,7 +635,7 @@ void QNdefNfcSmartPosterRecord::setIcons(const QList<QNdefNfcIconRecord> &icons)
{
d->m_iconList.clear();
- for (int i = 0; i < icons.length(); ++i) {
+ for (qsizetype i = 0; i < icons.size(); ++i) {
d->m_iconList.append(icons[i]);
}
@@ -670,28 +678,28 @@ void QNdefNfcSmartPosterRecord::setSize(quint32 size)
}
/*!
- Returns the UTF-8 encoded MIME type that describes the type of the objects
- that can be reached via uri().
+ Returns the MIME type that describes the type of the objects that can be
+ reached via uri().
- If the type is not known the return QByteArray is empty.
+ If the type is not known, the returned QString is empty.
\sa setTypeInfo(), hasTypeInfo()
*/
-QByteArray QNdefNfcSmartPosterRecord::typeInfo() const
+QString QNdefNfcSmartPosterRecord::typeInfo() const
{
if (d->m_type)
return d->m_type->typeInfo();
- return QByteArray();
+ return QString();
}
/*!
- Sets the type record to \a type. \a type must be UTF-8 encoded
- and describes the type of the object referenced by uri()
+ Sets the type record to \a type. \a type describes the type of the object
+ referenced by uri().
\sa typeInfo()
*/
-void QNdefNfcSmartPosterRecord::setTypeInfo(const QByteArray &type)
+void QNdefNfcSmartPosterRecord::setTypeInfo(const QString &type)
{
if (d->m_type)
delete d->m_type;
@@ -705,8 +713,7 @@ void QNdefNfcSmartPosterRecord::setTypeInfo(const QByteArray &type)
void QNdefNfcActRecord::setAction(QNdefNfcSmartPosterRecord::Action action)
{
- QByteArray data;
- data[0] = action;
+ QByteArray data(1, action);
setPayload(data);
}
@@ -723,11 +730,17 @@ QNdefNfcSmartPosterRecord::Action QNdefNfcActRecord::action() const
return value;
}
+/*!
+ Sets the contents of the icon record to \a data.
+*/
void QNdefNfcIconRecord::setData(const QByteArray &data)
{
setPayload(data);
}
+/*!
+ Returns the icon data as \l QByteArray.
+*/
QByteArray QNdefNfcIconRecord::data() const
{
return payload();
@@ -735,7 +748,7 @@ QByteArray QNdefNfcIconRecord::data() const
void QNdefNfcSizeRecord::setSize(quint32 size)
{
- QByteArray data;
+ QByteArray data(4, 0);
data[0] = (int) ((size & 0xFF000000) >> 24);
data[1] = (int) ((size & 0x00FF0000) >> 16);
@@ -756,14 +769,14 @@ quint32 QNdefNfcSizeRecord::size() const
+ ((p[2] << 8) & 0x0000FF00) + (p[3] & 0x000000FF);
}
-void QNdefNfcTypeRecord::setTypeInfo(const QByteArray &type)
+void QNdefNfcTypeRecord::setTypeInfo(const QString &type)
{
- setPayload(type);
+ setPayload(type.toUtf8());
}
-QByteArray QNdefNfcTypeRecord::typeInfo() const
+QString QNdefNfcTypeRecord::typeInfo() const
{
- return payload();
+ return QString::fromUtf8(payload());
}
QT_END_NAMESPACE
diff --git a/src/nfc/qndefnfcsmartposterrecord.h b/src/nfc/qndefnfcsmartposterrecord.h
index 9b714d5d..0424e05c 100644
--- a/src/nfc/qndefnfcsmartposterrecord.h
+++ b/src/nfc/qndefnfcsmartposterrecord.h
@@ -1,46 +1,11 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 - 2012 Research In Motion
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNDEFNFCSMARTPOSTERRECORD_H
#define QNDEFNFCSMARTPOSTERRECORD_H
#include <QtCore/QList>
+#include <QtCore/QString>
#include <QtNfc/qtnfcglobal.h>
#include <QtNfc/QNdefRecord>
#include <QtNfc/qndefnfctextrecord.h>
@@ -97,8 +62,8 @@ public:
bool hasSize() const;
bool hasTypeInfo() const;
- int titleCount() const;
- QNdefNfcTextRecord titleRecord(const int index) const;
+ qsizetype titleCount() const;
+ QNdefNfcTextRecord titleRecord(qsizetype index) const;
QString title(const QString &locale = QString()) const;
QList<QNdefNfcTextRecord> titleRecords() const;
@@ -116,8 +81,8 @@ public:
Action action() const;
void setAction(Action act);
- int iconCount() const;
- QNdefNfcIconRecord iconRecord(const int index) const;
+ qsizetype iconCount() const;
+ QNdefNfcIconRecord iconRecord(qsizetype index) const;
QByteArray icon(const QByteArray& mimetype = QByteArray()) const;
QList<QNdefNfcIconRecord> iconRecords() const;
@@ -131,9 +96,8 @@ public:
quint32 size() const;
void setSize(quint32 size);
- //TODO Qt 6 the mimetype should be QString as it is UTF-8
- QByteArray typeInfo() const;
- void setTypeInfo(const QByteArray &type);
+ QString typeInfo() const;
+ void setTypeInfo(const QString &type);
private:
QSharedDataPointer<QNdefNfcSmartPosterRecordPrivate> d;
diff --git a/src/nfc/qndefnfcsmartposterrecord_p.h b/src/nfc/qndefnfcsmartposterrecord_p.h
index f2042be8..cab85756 100644
--- a/src/nfc/qndefnfcsmartposterrecord_p.h
+++ b/src/nfc/qndefnfcsmartposterrecord_p.h
@@ -1,41 +1,5 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 - 2012 Research In Motion
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 - 2012 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNDEFNFCSMARTPOSTERRECORD_P_H
#define QNDEFNFCSMARTPOSTERRECORD_P_H
@@ -76,22 +40,22 @@ class QNdefNfcTypeRecord : public QNdefRecord
public:
Q_DECLARE_NDEF_RECORD(QNdefNfcTypeRecord, QNdefRecord::NfcRtd, "t", QByteArray(0, char(0)))
- void setTypeInfo(const QByteArray &type);
- QByteArray typeInfo() const;
+ void setTypeInfo(const QString &type);
+ QString typeInfo() const;
};
class QNdefNfcSmartPosterRecordPrivate : public QSharedData
{
public:
- QNdefNfcSmartPosterRecordPrivate() : m_uri(0), m_action(0), m_size(0), m_type(0) {}
+ QNdefNfcSmartPosterRecordPrivate() {}
public:
QList<QNdefNfcTextRecord> m_titleList;
- QNdefNfcUriRecord *m_uri;
- QNdefNfcActRecord *m_action;
+ QNdefNfcUriRecord *m_uri = nullptr;
+ QNdefNfcActRecord *m_action = nullptr;
QList<QNdefNfcIconRecord> m_iconList;
- QNdefNfcSizeRecord *m_size;
- QNdefNfcTypeRecord *m_type;
+ QNdefNfcSizeRecord *m_size = nullptr;
+ QNdefNfcTypeRecord *m_type = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/nfc/qndefnfctextrecord.cpp b/src/nfc/qndefnfctextrecord.cpp
index 95fb4c66..a8d9b091 100644
--- a/src/nfc/qndefnfctextrecord.cpp
+++ b/src/nfc/qndefnfctextrecord.cpp
@@ -1,45 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 <qndefnfctextrecord.h>
-#include <QtCore/QTextCodec>
+#include <QtCore/QStringConverter>
#include <QtCore/QLocale>
QT_BEGIN_NAMESPACE
@@ -104,7 +68,7 @@ void QNdefNfcTextRecord::setLocale(const QString &locale)
quint8 codeLength = status & 0x3f;
- quint8 newStatus = (status & 0xd0) | locale.length();
+ quint8 newStatus = (status & 0xd0) | locale.size();
p[0] = newStatus;
p.replace(1, codeLength, locale.toLatin1());
@@ -122,19 +86,15 @@ QString QNdefNfcTextRecord::text() const
if (p.isEmpty())
return QString();
-#if QT_CONFIG(textcodec)
quint8 status = p.at(0);
-
bool utf16 = status & 0x80;
quint8 codeLength = status & 0x3f;
- QTextCodec *codec = QTextCodec::codecForName(utf16 ? "UTF-16BE" : "UTF-8");
+ auto toUnicode = QStringDecoder(
+ utf16 ? QStringDecoder::Encoding::Utf16BE : QStringDecoder::Encoding::Utf8,
+ QStringDecoder::Flag::Stateless);
- return codec ? codec->toUnicode(p.constData() + 1 + codeLength, p.length() - 1 - codeLength) : QString();
-#else
- qWarning("Cannot decode payload, Qt was built with -no-feature-textcodec!");
- return QString();
-#endif
+ return toUnicode(QByteArrayView(p.constData() + 1 + codeLength, p.size() - 1 - codeLength));
}
/*!
@@ -142,7 +102,6 @@ QString QNdefNfcTextRecord::text() const
*/
void QNdefNfcTextRecord::setText(const QString text)
{
-#if QT_CONFIG(textcodec)
if (payload().isEmpty())
setLocale(QLocale().name());
@@ -155,15 +114,13 @@ void QNdefNfcTextRecord::setText(const QString text)
p.truncate(1 + codeLength);
- QTextCodec *codec = QTextCodec::codecForName(utf16 ? "UTF-16BE" : "UTF-8");
+ auto fromUnicode = QStringEncoder(
+ utf16? QStringEncoder::Encoding::Utf16BE : QStringEncoder::Encoding::Utf8,
+ QStringEncoder::Flag::Stateless|QStringEncoder::Flag::WriteBom);
- p += codec->fromUnicode(text);
+ p += fromUnicode(text);
setPayload(p);
-#else
- qWarning("Cannot encode payload, Qt was built with -no-feature-textcodec!");
- Q_UNUSED(text);
-#endif
}
/*!
diff --git a/src/nfc/qndefnfctextrecord.h b/src/nfc/qndefnfctextrecord.h
index 72fc4878..103669b3 100644
--- a/src/nfc/qndefnfctextrecord.h
+++ b/src/nfc/qndefnfctextrecord.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNDEFNFCTEXTRECORD_H
#define QNDEFNFCTEXTRECORD_H
diff --git a/src/nfc/qndefnfcurirecord.cpp b/src/nfc/qndefnfcurirecord.cpp
index 3438d9f2..690e1848 100644
--- a/src/nfc/qndefnfcurirecord.cpp
+++ b/src/nfc/qndefnfcurirecord.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qndefnfcurirecord.h"
@@ -135,9 +99,8 @@ void QNdefNfcUriRecord::setUri(const QUrl &uri)
for (int i = 1; i < abbrevs; ++i) {
if (uri.toString().startsWith(QLatin1String(abbreviations[i]))) {
- QByteArray p;
+ QByteArray p(1, i);
- p[0] = i;
p += uri.toString().mid(qstrlen(abbreviations[i])).toUtf8();
setPayload(p);
@@ -146,8 +109,7 @@ void QNdefNfcUriRecord::setUri(const QUrl &uri)
}
}
- QByteArray p;
- p[0] = 0;
+ QByteArray p(1, 0);
p += uri.toString().toUtf8();
setPayload(p);
diff --git a/src/nfc/qndefnfcurirecord.h b/src/nfc/qndefnfcurirecord.h
index 90a199a3..9a59d8ee 100644
--- a/src/nfc/qndefnfcurirecord.h
+++ b/src/nfc/qndefnfcurirecord.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNDEFNFCURIRECORD_H
#define QNDEFNFCURIRECORD_H
diff --git a/src/nfc/qndefrecord.cpp b/src/nfc/qndefrecord.cpp
index a8436bdb..51df2ab6 100644
--- a/src/nfc/qndefrecord.cpp
+++ b/src/nfc/qndefrecord.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qndefrecord.h"
@@ -102,15 +66,17 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn bool QNdefRecord::isRecordType() const
+ \fn template <typename T> bool QNdefRecord::isRecordType() const
- Returns true if the NDEF record is of the specified record type; otherwise returns false.
+ Returns \c true if the NDEF record is of the specified record type;
+ otherwise returns \c false.
*/
/*!
\fn bool QNdefRecord::operator!=(const QNdefRecord &other) const
- Returns true if this NDEF record does not equal \a other; otherwise return false.
+ Returns \c true if this NDEF record does not equal \a other;
+ otherwise return \c false.
*/
/*!
@@ -148,7 +114,7 @@ QT_BEGIN_NAMESPACE
\sa Q_DECLARE_NDEF_RECORD()
*/
-uint qHash(const QNdefRecord &key)
+size_t qHash(const QNdefRecord &key)
{
return qHash(key.type() + key.id() + key.payload());
}
@@ -327,7 +293,8 @@ QByteArray QNdefRecord::payload() const
}
/*!
- Returns true if the NDEF record contains an empty payload; otherwise return false.
+ Returns \c true if the NDEF record contains an empty payload;
+ otherwise returns \c false.
This is equivalent to calling \c {payload().isEmpty()}.
*/
@@ -340,7 +307,8 @@ bool QNdefRecord::isEmpty() const
}
/*!
- Returns true if \a other and this NDEF record are the same.
+ Returns \c true if \a other and this NDEF record are the same.
+ Otherwise returns \c false.
*/
bool QNdefRecord::operator==(const QNdefRecord &other) const
{
@@ -365,4 +333,22 @@ bool QNdefRecord::operator==(const QNdefRecord &other) const
return true;
}
+/*!
+ \since 6.2
+
+ Clear the NDEF record.
+
+ An \l isEmpty() call returns \c true for a cleared record. The record
+ \l type() is set to \l {QNdefRecord::}{Empty}.
+*/
+void QNdefRecord::clear()
+{
+ if (d) {
+ d->typeNameFormat = 0;
+ d->type.clear();
+ d->id.clear();
+ d->payload.clear();
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/nfc/qndefrecord.h b/src/nfc/qndefrecord.h
index 6cb6ac8c..1d9c65ee 100644
--- a/src/nfc/qndefrecord.h
+++ b/src/nfc/qndefrecord.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNDEFRECORD_H
#define QNDEFRECORD_H
@@ -90,6 +54,8 @@ public:
bool operator==(const QNdefRecord &other) const;
inline bool operator!=(const QNdefRecord &other) const { return !operator==(other); }
+ void clear();
+
protected:
QNdefRecord(const QNdefRecord &other, TypeNameFormat typeNameFormat, const QByteArray &type);
QNdefRecord(const QNdefRecord &other, TypeNameFormat typeNameFormat);
@@ -111,7 +77,7 @@ private:
} \
QT_END_NAMESPACE
-Q_NFC_EXPORT uint qHash(const QNdefRecord &key);
+Q_NFC_EXPORT size_t qHash(const QNdefRecord &key);
QT_END_NAMESPACE
diff --git a/src/nfc/qndefrecord_p.h b/src/nfc/qndefrecord_p.h
index 89ce5d99..f9f64d9a 100644
--- a/src/nfc/qndefrecord_p.h
+++ b/src/nfc/qndefrecord_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 QtNfc 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 QNDEFRECORD_P_H
#define QNDEFRECORD_P_H
diff --git a/src/nfc/qnearfieldmanager.cpp b/src/nfc/qnearfieldmanager.cpp
index 02e4d918..ee1013f2 100644
--- a/src/nfc/qnearfieldmanager.cpp
+++ b/src/nfc/qnearfieldmanager.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qnearfieldmanager.h"
#include "qnearfieldmanager_p.h"
@@ -46,8 +10,12 @@
#include "qnearfieldmanager_neard_p.h"
#elif defined(ANDROID_NFC)
#include "qnearfieldmanager_android_p.h"
+#elif defined(IOS_NFC)
+#include "qnearfieldmanager_ios_p.h"
+#elif defined(PCSC_NFC)
+#include "qnearfieldmanager_pcsc_p.h"
#else
-#include "qnearfieldmanagerimpl_p.h"
+#include "qnearfieldmanager_generic_p.h"
#endif
#include <QtCore/QMetaType>
@@ -66,56 +34,27 @@ QT_BEGIN_NAMESPACE
NFC Forum devices support two modes of communications. The first mode, peer-to-peer
communications, is used to communicate between two NFC Forum devices. The second mode,
master/slave communications, is used to communicate between an NFC Forum device and an NFC
- Forum Tag or Contactless Card. The targetDetected() signal is emitted when a target device
- enters communications range. Communications can be initiated from the slot connected to this
+ Forum Tag or Contactless Card. The targetDetected() signal is emitted when a target device
+ enters communications range. Communications can be initiated from the slot connected to this
signal.
NFC Forum devices generally operate as the master in master/slave communications. Some devices
are also capable of operating as the slave, so called Card Emulation mode. In this mode the
local NFC device emulates a NFC Forum Tag or Contactless Card.
- NFC Forum Tags can contain one or more messages in a standardized format. These messages are
- encapsulated by the QNdefMessage class. Use the registerNdefMessageHandler() functions to
- register message handlers with particular criteria. Handlers can be unregistered with the
- unregisterNdefMessageHandler() function.
-
Applications can connect to the targetDetected() and targetLost() signals to get notified when
- an NFC Forum Tag enters or leaves proximity. Before these signals are
- emitted target detection must be started with the startTargetDetection() function.
- Target detection can be stopped with
- the stopTargetDetection() function. Before a detected target can be accessed it is necessary to
- request access rights. This must be done before the target device is touched. The
- setTargetAccessModes() function is used to set the types of access the application wants to
- perform on the detected target. When access is no longer required the target access modes
- should be set to NoTargetAccess as other applications may be blocked from accessing targets.
- The current target access modes can be retried with the targetAccessModes() function.
-
-
- \section2 Automatically launching NDEF message handlers
-
- On some platforms it is possible to pre-register an application to receive NDEF messages
- matching a given criteria. This is useful to get the system to automatically launch your
- application when a matching NDEF message is received. This removes the need to have the user
- manually launch NDEF handling applications, prior to touching a tag, or to have those
- applications always running and using system resources.
-
- The process of registering the handler is different for each platform. Please refer to the
- platform documentation on how such a registration may be done.
- If the application has been registered as an NDEF message handler, the application only needs
- to call the registerNdefMessageHandler() function:
-
- \snippet doc_src_qtnfc.cpp handleNdefMessage
-
- Automatically launching NDEF message handlers is supported on
- \l{nfc-android.html}{Android}.
+ an NFC Forum Tag enters or leaves proximity. Before these signals are emitted target detection
+ must be started with the startTargetDetection() function. Target detection can be stopped with
+ the stopTargetDetection() function. When the target is no longer required the target should be
+ deleted as other applications may be blocked from accessing the target.
\section3 NFC on Linux
- The \l{https://01.org/linux-nfc}{Linux NFC project} provides software to support NFC on Linux platforms.
- The neard daemon will allow access to the supported hardware via DBus interfaces. QtNfc requires neard
- version 0.14 which can be built from source or installed via the appropriate Linux package manager. Not
- all API features are currently supported.
- To allow QtNfc to access the DBus interfaces the neard daemon has to be running. In case of problems
- debug output can be enabled by enabling categorized logging for 'qt.nfc.neard'.
+ The \l{https://github.com/linux-nfc/neard}{Linux NFC project} provides software to support NFC
+ on Linux platforms. The neard daemon will allow access to the supported hardware via DBus
+ interfaces. QtNfc requires neard version 0.14 which can be built from source or installed via
+ the appropriate Linux package manager. Not all API features are currently supported.
+ To allow QtNfc to access the DBus interfaces the neard daemon has to be running. In case of
+ problems debug output can be enabled by enabling categorized logging for 'qt.nfc.neard'.
*/
/*!
@@ -132,27 +71,25 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \enum QNearFieldManager::TargetAccessMode
+ \fn void QNearFieldManager::adapterStateChanged(AdapterState state)
- This enum describes the different access modes an application can have.
+ \since 5.12
+
+ This signal is emitted whenever the \a state of the NFC adapter changed.
- \value NoTargetAccess The application cannot access NFC capabilities.
- \value NdefReadTargetAccess The application can read NDEF messages from targets by calling
- QNearFieldTarget::readNdefMessages().
- \value NdefWriteTargetAccess The application can write NDEF messages to targets by calling
- QNearFieldTarget::writeNdefMessages().
- \value TagTypeSpecificTargetAccess The application can access targets using raw commands by
- calling QNearFieldTarget::sendCommand().
+ \note Currently, this signal is only emitted on Android.
*/
/*!
- \fn void QNearFieldManager::adapterStateChanged(AdapterState state)
+ \fn void QNearFieldManager::targetDetectionStopped()
- \since 5.12
+ \since 6.2
- This signal is emitted whenever the state of the NFC adapter changed.
+ This signal is emitted whenever the target detection is stopped.
- \note Currently, this signal is only emitted on Android.
+ \note Mostly this signal is emitted when \l stopTargetDetection() has been called.
+ Additionally the user is able to stop the detection on iOS within a popup shown
+ by the system during the scan, which also leads to emitting this signal.
*/
/*!
@@ -196,6 +133,8 @@ QNearFieldManager::QNearFieldManager(QObject *parent)
connect(d_ptr, &QNearFieldManagerPrivate::adapterStateChanged,
this, &QNearFieldManager::adapterStateChanged);
+ connect(d_ptr, &QNearFieldManagerPrivate::targetDetectionStopped,
+ this, &QNearFieldManager::targetDetectionStopped);
connect(d_ptr, &QNearFieldManagerPrivate::targetDetected,
this, &QNearFieldManager::targetDetected);
connect(d_ptr, &QNearFieldManagerPrivate::targetLost,
@@ -217,6 +156,8 @@ QNearFieldManager::QNearFieldManager(QNearFieldManagerPrivate *backend, QObject
connect(d_ptr, &QNearFieldManagerPrivate::adapterStateChanged,
this, &QNearFieldManager::adapterStateChanged);
+ connect(d_ptr, &QNearFieldManagerPrivate::targetDetectionStopped,
+ this, &QNearFieldManager::targetDetectionStopped);
connect(d_ptr, &QNearFieldManagerPrivate::targetDetected,
this, &QNearFieldManager::targetDetected);
connect(d_ptr, &QNearFieldManagerPrivate::targetLost,
@@ -232,211 +173,109 @@ QNearFieldManager::~QNearFieldManager()
}
/*!
+ \since 6.2
+
Returns \c true if the device has a NFC adapter and
it is turned on; otherwise returns \c false.
\sa isSupported()
*/
-bool QNearFieldManager::isAvailable() const
+bool QNearFieldManager::isEnabled() const
{
Q_D(const QNearFieldManager);
- return d->isAvailable();
+ return d->isEnabled();
}
/*!
\since 5.12
- Returns \c true if the underlying device has a NFC adapter; otherwise returns \c false.
+ Returns \c true if the underlying device has a NFC adapter; otherwise
+ returns \c false. If an \a accessMethod is given, the function returns
+ \c true only if the NFC adapter supports the given \a accessMethod.
- \sa isAvailable()
+ \sa isEnabled()
*/
-bool QNearFieldManager::isSupported() const
+bool QNearFieldManager::isSupported(QNearFieldTarget::AccessMethod accessMethod) const
{
Q_D(const QNearFieldManager);
- return d->isSupported();
-}
-/*!
- \fn bool QNearFieldManager::startTargetDetection()
-
- Starts detecting targets and returns true if target detection is
- successfully started; otherwise returns false. Causes the targetDetected() signal to be emitted
- when a target is within proximity.
- \sa stopTargetDetection()
-
- \note For platforms using neard: target detection will stop as soon as a tag has been detected.
-*/
-bool QNearFieldManager::startTargetDetection()
-{
- Q_D(QNearFieldManager);
- return d->startTargetDetection();
+ return d->isSupported(accessMethod);
}
/*!
- Stops detecting targets. The targetDetected() signal will no longer be emitted until another
- call to startTargetDetection() is made.
-*/
-void QNearFieldManager::stopTargetDetection()
-{
- Q_D(QNearFieldManager);
+ \fn bool QNearFieldManager::startTargetDetection(QNearFieldTarget::AccessMethod accessMethod)
- d->stopTargetDetection();
-}
+ Starts detecting targets and returns \c true if target detection started successfully;
+ otherwise returns \c false. Causes the targetDetected() signal to be emitted
+ when a target is within proximity. Only tags with the given \a accessMethod will be reported.
+ Target detection continues until \l stopTargetDetection() is called.
-static QMetaMethod methodForSignature(QObject *object, const char *method)
-{
- QByteArray normalizedMethod = QMetaObject::normalizedSignature(method);
-
- if (!QMetaObject::checkConnectArgs(SIGNAL(targetDetected(QNdefMessage,QNearFieldTarget*)),
- normalizedMethod)) {
- qWarning("Signatures do not match: %s:%d\n", __FILE__, __LINE__);
- return QMetaMethod();
- }
-
- quint8 memcode = (normalizedMethod.at(0) - '0') & 0x03;
- normalizedMethod = normalizedMethod.mid(1);
-
- int index;
- switch (memcode) {
- case QSLOT_CODE:
- index = object->metaObject()->indexOfSlot(normalizedMethod.constData());
- break;
- case QSIGNAL_CODE:
- index = object->metaObject()->indexOfSignal(normalizedMethod.constData());
- break;
- case QMETHOD_CODE:
- index = object->metaObject()->indexOfMethod(normalizedMethod.constData());
- break;
- default:
- index = -1;
- }
-
- if (index == -1)
- return QMetaMethod();
-
- return object->metaObject()->method(index);
-}
+ To detect targets with a different \a accessMethod, stopTargetDetection() must be called first.
-/*!
- Registers \a object to receive notifications on \a method when a tag has been detected and has
- an NDEF record that matches \a typeNameFormat and \a type. The \a method on \a object should
- have the prototype
- 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'.
+ \note On iOS, it is impossible to start target detection for both NdefAccess and TagTypeSpecificAccess
+ at the same time. So if AnyAccess is selected, NdefAccess will be used instead.
- Returns an identifier, which can be used to unregister the handler, on success; otherwise
- returns -1.
+ \note On platforms using neard, target detection will stop as soon as a tag has been detected.
- \note The \e target parameter of \a method may not be available on all platforms, in which case
- \e target will be 0.
-
- \note On platforms using neard registering message handlers is not supported.
+ \sa stopTargetDetection()
*/
-
-int QNearFieldManager::registerNdefMessageHandler(QNdefRecord::TypeNameFormat typeNameFormat,
- const QByteArray &type,
- QObject *object, const char *method)
+bool QNearFieldManager::startTargetDetection(QNearFieldTarget::AccessMethod accessMethod)
{
- QMetaMethod metaMethod = methodForSignature(object, method);
- if (!metaMethod.enclosingMetaObject())
- return -1;
-
- QNdefFilter filter;
- filter.appendRecord(typeNameFormat, type);
-
Q_D(QNearFieldManager);
- return d->registerNdefMessageHandler(filter, object, metaMethod);
+ return d->startTargetDetection(accessMethod);
}
/*!
- \fn int QNearFieldManager::registerNdefMessageHandler(QObject *object, const char *method)
+ Stops detecting targets. The \l targetDetected() signal will no longer be emitted until another
+ call to \l startTargetDetection() is made. Targets detected before are still valid.
- Registers \a object to receive notifications on \a method when a tag has been detected and has
- an NDEF message that matches a pre-registered message format. The \a method on \a object should
- have the prototype
- 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'.
+ \note On iOS, detected targets become invalid after this call (e.g. an attempt to write or
+ read NDEF messages will result in an error).
- Returns an identifier, which can be used to unregister the handler, on success; otherwise
- returns -1.
+ If an \a errorMessage is provided, it is a hint to the system that the application's goal
+ was not achieved. The \a errorMessage and a matching error icon are shown to the user.
+ Calling this function with an empty \a errorMessage implies a successful end of operation;
+ otherwise, an \a errorMessage should be passed to this function.
- This function is used to register a QNearFieldManager instance to receive notifications when a
- NDEF message matching a pre-registered message format is received. See the section on
- \l {Automatically launching NDEF message handlers}.
+ \note Currently, \a errorMessage only has an effect on iOS because the system shows a popup
+ during the scan where the \a errorMessage is visible. Other platforms will ignore this
+ parameter.
- \note The \e target parameter of \a method may not be available on all platforms, in which case
- \e target will be 0.
+ \sa setUserInformation()
*/
-int QNearFieldManager::registerNdefMessageHandler(QObject *object, const char *method)
+void QNearFieldManager::stopTargetDetection(const QString &errorMessage)
{
- QMetaMethod metaMethod = methodForSignature(object, method);
- if (!metaMethod.enclosingMetaObject())
- return -1;
-
Q_D(QNearFieldManager);
- return d->registerNdefMessageHandler(object, metaMethod);
+ d->stopTargetDetection(errorMessage);
}
/*!
- Registers \a object to receive notifications on \a method when a tag has been detected and has
- an NDEF message that matches \a filter is detected. The \a method on \a object should have the
- prototype 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'.
+ \since 6.2
- Returns an identifier, which can be used to unregister the handler, on success; otherwise
- returns -1.
+ Sets the message that the system shows to the user. If target detection is running, the
+ \a message will be updated immediately and can be used as a progress message. The last message
+ set before a call to \l startTargetDetection() without an error message is used as a success
+ message. If target detection is not running, the \a message will be used as the initial
+ message when the next detection is started. By default, no message is shown to the user.
- \note The \e target parameter of \a method may not be available on all platforms, in which case
- \e target will be 0.
-*/
-int QNearFieldManager::registerNdefMessageHandler(const QNdefFilter &filter,
- QObject *object, const char *method)
-{
- QMetaMethod metaMethod = methodForSignature(object, method);
- if (!metaMethod.enclosingMetaObject())
- return -1;
+ \note Currently, this function only has an effect on iOS because the system shows a popup
+ during the scan. On iOS, this \a message is mapped to the alert message which is shown upon
+ successful completion of the scan. Other platforms will ignore \a message.
- Q_D(QNearFieldManager);
-
- return d->registerNdefMessageHandler(filter, object, metaMethod);
-}
-
-/*!
- Unregisters the target detect handler identified by \a handlerId.
-
- Returns true on success; otherwise returns false.
+ \sa startTargetDetection(), stopTargetDetection()
*/
-bool QNearFieldManager::unregisterNdefMessageHandler(int handlerId)
+void QNearFieldManager::setUserInformation(const QString &message)
{
Q_D(QNearFieldManager);
- return d->unregisterNdefMessageHandler(handlerId);
+ d->setUserInformation(message);
}
-/*!
- Sets the requested target access modes to \a accessModes.
-*/
-void QNearFieldManager::setTargetAccessModes(TargetAccessModes accessModes)
-{
- Q_D(QNearFieldManager);
-
- TargetAccessModes removedModes = ~accessModes & d->m_requestedModes;
- if (removedModes)
- d->releaseAccess(removedModes);
-
- TargetAccessModes newModes = accessModes & ~d->m_requestedModes;
- if (newModes)
- d->requestAccess(newModes);
-}
-
-/*!
- Returns current requested target access modes.
-*/
-QNearFieldManager::TargetAccessModes QNearFieldManager::targetAccessModes() const
-{
- Q_D(const QNearFieldManager);
+QT_END_NAMESPACE
- return d->m_requestedModes;
-}
+#include "moc_qnearfieldmanager_p.cpp"
-QT_END_NAMESPACE
+#include "moc_qnearfieldmanager.cpp"
diff --git a/src/nfc/qnearfieldmanager.h b/src/nfc/qnearfieldmanager.h
index 22506e7e..833245b0 100644
--- a/src/nfc/qnearfieldmanager.h
+++ b/src/nfc/qnearfieldmanager.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNEARFIELDMANAGER_H
#define QNEARFIELDMANAGER_H
@@ -63,43 +27,23 @@ public:
TurningOff = 4
};
Q_ENUM(AdapterState)
- enum TargetAccessMode {
- NoTargetAccess = 0x00,
- NdefReadTargetAccess = 0x01,
- NdefWriteTargetAccess = 0x02,
- TagTypeSpecificTargetAccess = 0x04
- };
- Q_ENUM(TargetAccessMode)
- Q_DECLARE_FLAGS(TargetAccessModes, TargetAccessMode)
explicit QNearFieldManager(QObject *parent = nullptr);
explicit QNearFieldManager(QNearFieldManagerPrivate *backend, QObject *parent = nullptr);
~QNearFieldManager();
- bool isAvailable() const;
- bool isSupported() const;
-
- void setTargetAccessModes(TargetAccessModes accessModes);
- TargetAccessModes targetAccessModes() const;
+ bool isEnabled() const;
+ bool isSupported(QNearFieldTarget::AccessMethod accessMethod
+ = QNearFieldTarget::AnyAccess) const;
- bool startTargetDetection();
- void stopTargetDetection();
+ bool startTargetDetection(QNearFieldTarget::AccessMethod accessMethod);
+ void stopTargetDetection(const QString &errorMessage = QString());
- //TODO Qt 6 Consider removal of this registration mechanism
- //None of the currently supported platforms supports the feature
- //or in fact the implementation (on Android) is not what the
- //function is supposed to do.
- int registerNdefMessageHandler(QObject *object, const char *method);
- int registerNdefMessageHandler(QNdefRecord::TypeNameFormat typeNameFormat,
- const QByteArray &type,
- QObject *object, const char *method);
- int registerNdefMessageHandler(const QNdefFilter &filter,
- QObject *object, const char *method);
-
- bool unregisterNdefMessageHandler(int handlerId);
+ void setUserInformation(const QString &message);
Q_SIGNALS:
void adapterStateChanged(QNearFieldManager::AdapterState state);
+ void targetDetectionStopped();
void targetDetected(QNearFieldTarget *target);
void targetLost(QNearFieldTarget *target);
@@ -107,8 +51,6 @@ private:
QNearFieldManagerPrivate *d_ptr;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QNearFieldManager::TargetAccessModes)
-
QT_END_NAMESPACE
#endif // QNEARFIELDMANAGER_H
diff --git a/src/nfc/qnearfieldmanager_android.cpp b/src/nfc/qnearfieldmanager_android.cpp
index 0b305501..63cc8472 100644
--- a/src/nfc/qnearfieldmanager_android.cpp
+++ b/src/nfc/qnearfieldmanager_android.cpp
@@ -1,340 +1,148 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Centria research and development
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 Centria research and development
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnearfieldmanager_android_p.h"
-#include "qnearfieldtarget_android_p.h"
-#include "qndeffilter.h"
#include "qndefmessage.h"
-#include "qndefrecord.h"
#include "qbytearray.h"
#include "qcoreapplication.h"
-#include "qdebug.h"
-#include "qlist.h"
-#include <QScopedPointer>
#include <QtCore/QMetaType>
-#include <QtCore/QMetaMethod>
-#include <QtCore/private/qjnihelpers_p.h>
QT_BEGIN_NAMESPACE
-Q_GLOBAL_STATIC(QAndroidJniObject, broadcastReceiver)
-Q_GLOBAL_STATIC(QList<QNearFieldManagerPrivateImpl *>, broadcastListener)
-
extern "C"
{
- JNIEXPORT void JNICALL Java_org_qtproject_qt5_android_nfc_QtNfcBroadcastReceiver_jniOnReceive(
- JNIEnv */*env*/, jobject /*javaObject*/, jint state)
+ JNIEXPORT void JNICALL Java_org_qtproject_qt_android_nfc_QtNfcBroadcastReceiver_jniOnReceive(
+ JNIEnv */*env*/, jobject /*javaObject*/, jlong qtObject, jint state)
{
- QNearFieldManager::AdapterState adapterState = static_cast<QNearFieldManager::AdapterState>((int) state);
-
- for (const auto listener : qAsConst(*broadcastListener)) {
- Q_EMIT listener->adapterStateChanged(adapterState);
- }
+ QNearFieldManager::AdapterState adapterState =
+ static_cast<QNearFieldManager::AdapterState>(state);
+ auto obj = reinterpret_cast<QNearFieldManagerPrivateImpl *>(qtObject);
+ Q_ASSERT(obj != nullptr);
+ obj->adapterStateChanged(adapterState);
}
}
+Q_GLOBAL_STATIC(QMainNfcNewIntentListener, newIntentListener)
+
QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() :
- m_detecting(false), m_handlerID(0)
+ detecting(false)
{
- qRegisterMetaType<QAndroidJniObject>("QAndroidJniObject");
+ qRegisterMetaType<QJniObject>("QJniObject");
qRegisterMetaType<QNdefMessage>("QNdefMessage");
- if (!broadcastReceiver->isValid()) {
- *broadcastReceiver = QAndroidJniObject("org/qtproject/qt5/android/nfc/QtNfcBroadcastReceiver",
- "(Landroid/content/Context;)V", QtAndroidPrivate::context());
- }
- broadcastListener->append(this);
-
- connect(this, &QNearFieldManagerPrivateImpl::targetDetected, this, &QNearFieldManagerPrivateImpl::handlerTargetDetected);
- connect(this, &QNearFieldManagerPrivateImpl::targetLost, this, &QNearFieldManagerPrivateImpl::handlerTargetLost);
+ broadcastReceiver = QJniObject::construct<QtJniTypes::QtNfcBroadcastReceiver>(
+ reinterpret_cast<jlong>(this), QNativeInterface::QAndroidApplication::context());
}
QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
{
- broadcastListener->removeOne(this);
- if (broadcastListener->isEmpty()) {
- broadcastReceiver->callMethod<void>("unregisterReceiver");
- *broadcastReceiver = QAndroidJniObject();
- }
+ broadcastReceiver.callMethod<void>("unregisterReceiver");
}
-void QNearFieldManagerPrivateImpl::handlerTargetDetected(QNearFieldTarget *target)
+void QNearFieldManagerPrivateImpl::onTargetDetected(QNearFieldTargetPrivateImpl *target)
{
- if (ndefMessageHandlers.count() == 0 && ndefFilterHandlers.count() == 0) // if no handler is registered
+ if (target->q_ptr) {
+ Q_EMIT targetDetected(target->q_ptr);
return;
- if (target->hasNdefMessage()) {
- connect(reinterpret_cast<NearFieldTarget *>(target), &NearFieldTarget::ndefMessageRead,
- this, &QNearFieldManagerPrivateImpl::handlerNdefMessageRead);
- connect(target, &QNearFieldTarget::requestCompleted,
- this, &QNearFieldManagerPrivateImpl::handlerRequestCompleted);
- connect(target, &QNearFieldTarget::error,
- this, &QNearFieldManagerPrivateImpl::handlerError);
-
- QNearFieldTarget::RequestId id = target->readNdefMessages();
- m_idToTarget.insert(id, target);
- }
-}
-
-void QNearFieldManagerPrivateImpl::handlerTargetLost(QNearFieldTarget *target)
-{
- disconnect(reinterpret_cast<NearFieldTarget *>(target), &NearFieldTarget::ndefMessageRead,
- this, &QNearFieldManagerPrivateImpl::handlerNdefMessageRead);
- disconnect(target, &QNearFieldTarget::requestCompleted,
- this, &QNearFieldManagerPrivateImpl::handlerRequestCompleted);
- disconnect(target, &QNearFieldTarget::error,
- this, &QNearFieldManagerPrivateImpl::handlerError);
- m_idToTarget.remove(m_idToTarget.key(target));
-}
-
-struct VerifyRecord
-{
- QNdefFilter::Record filterRecord;
- unsigned int count;
-};
-
-void QNearFieldManagerPrivateImpl::handlerNdefMessageRead(const QNdefMessage &message, const QNearFieldTarget::RequestId &id)
-{
- QNearFieldTarget *target = m_idToTarget.value(id);
- //For message handlers without filters
- for (int i = 0; i < ndefMessageHandlers.count(); i++) {
- ndefMessageHandlers.at(i).second.invoke(ndefMessageHandlers.at(i).first.second, Q_ARG(QNdefMessage, message), Q_ARG(QNearFieldTarget*, target));
}
- //For message handlers that specified a filter
- for (int i = 0; i < ndefFilterHandlers.count(); ++i) {
- bool matched = true;
-
- QNdefFilter filter = ndefFilterHandlers.at(i).second.first;
-
- QList<VerifyRecord> filterRecords;
- for (int j = 0; j < filter.recordCount(); ++j) {
- VerifyRecord vr;
- vr.count = 0;
- vr.filterRecord = filter.recordAt(j);
-
- filterRecords.append(vr);
- }
-
- for (const QNdefRecord &record : message) {
- for (int j = 0; matched && (j < filterRecords.count()); ++j) {
- VerifyRecord &vr = filterRecords[j];
-
- if (vr.filterRecord.typeNameFormat == record.typeNameFormat() &&
- ( vr.filterRecord.type == record.type() ||
- vr.filterRecord.type.isEmpty()) ) {
- ++vr.count;
- break;
- } else {
- if (filter.orderMatch()) {
- if (vr.filterRecord.minimum <= vr.count &&
- vr.count <= vr.filterRecord.maximum) {
- continue;
- } else {
- matched = false;
- }
- }
- }
- }
- }
-
- for (int j = 0; matched && (j < filterRecords.count()); ++j) {
- const VerifyRecord &vr = filterRecords.at(j);
-
- if (vr.filterRecord.minimum <= vr.count && vr.count <= vr.filterRecord.maximum)
- continue;
- else
- matched = false;
- }
-
- if (matched) {
- ndefFilterHandlers.at(i).second.second.invoke(ndefFilterHandlers.at(i).first.second, Q_ARG(QNdefMessage, message), Q_ARG(QNearFieldTarget*, target));
- }
- }
+ Q_EMIT targetDetected(new QNearFieldTarget(target, this));
}
-void QNearFieldManagerPrivateImpl::handlerRequestCompleted(const QNearFieldTarget::RequestId &id)
+void QNearFieldManagerPrivateImpl::onTargetLost(QNearFieldTargetPrivateImpl *target)
{
- m_idToTarget.remove(id);
+ Q_EMIT targetLost(target->q_ptr);
}
-void QNearFieldManagerPrivateImpl::handlerError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id)
+bool QNearFieldManagerPrivateImpl::isEnabled() const
{
- Q_UNUSED(error);
- m_idToTarget.remove(id);
+ return QtNfc::isEnabled();
}
-bool QNearFieldManagerPrivateImpl::isAvailable() const
+bool QNearFieldManagerPrivateImpl::isSupported(QNearFieldTarget::AccessMethod accessMethod) const
{
- return AndroidNfc::isAvailable();
-}
+ if (accessMethod == QNearFieldTarget::UnknownAccess)
+ return false;
-bool QNearFieldManagerPrivateImpl::isSupported() const
-{
- return AndroidNfc::isSupported();
+ return QtNfc::isSupported();
}
-bool QNearFieldManagerPrivateImpl::startTargetDetection()
+bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::AccessMethod accessMethod)
{
- if (m_detecting)
+ if (detecting)
return false; // Already detecting targets
- m_detecting = true;
- updateReceiveState();
- return true;
-}
+ if (newIntentListener.isDestroyed())
+ return false;
-void QNearFieldManagerPrivateImpl::stopTargetDetection()
-{
- m_detecting = false;
- updateReceiveState();
-}
-
-// FIXME This is supposed to be a platform registration. A message that
-// matches the given NDEF filter should restart the current application.
-// The implementation below only works as long as the current application
-// is running. It is not a platform wide registration on Android.
-int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(QObject *object, const QMetaMethod &method)
-{
- ndefMessageHandlers.append(QPair<QPair<int, QObject *>, QMetaMethod>(QPair<int, QObject *>(m_handlerID, object), method));
- updateReceiveState();
- //Returns the handler ID and increments it afterwards
- return m_handlerID++;
-}
-
-// FIXME see above
-int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(const QNdefFilter &filter,
- QObject *object, const QMetaMethod &method)
-{
- //If no record is set in the filter, we ignore the filter
- if (filter.recordCount()==0)
- return registerNdefMessageHandler(object, method);
-
- ndefFilterHandlers.append(QPair<QPair<int, QObject*>, QPair<QNdefFilter, QMetaMethod> >
- (QPair<int, QObject*>(m_handlerID, object), QPair<QNdefFilter, QMetaMethod>(filter, method)));
-
- updateReceiveState();
-
- return m_handlerID++;
-}
-
-bool QNearFieldManagerPrivateImpl::unregisterNdefMessageHandler(int handlerId)
-{
- for (int i=0; i<ndefMessageHandlers.count(); ++i) {
- if (ndefMessageHandlers.at(i).first.first == handlerId) {
- ndefMessageHandlers.removeAt(i);
- updateReceiveState();
- return true;
- }
- }
- for (int i=0; i<ndefFilterHandlers.count(); ++i) {
- if (ndefFilterHandlers.at(i).first.first == handlerId) {
- ndefFilterHandlers.removeAt(i);
- updateReceiveState();
- return true;
- }
- }
- return false;
-}
-
-void QNearFieldManagerPrivateImpl::requestAccess(QNearFieldManager::TargetAccessModes accessModes)
-{
- Q_UNUSED(accessModes);
- //Do nothing, because we dont have access modes for the target
+ detecting = true;
+ requestedMethod = accessMethod;
+ newIntentListener->registerListener(this);
+ return true;
}
-void QNearFieldManagerPrivateImpl::releaseAccess(QNearFieldManager::TargetAccessModes accessModes)
+void QNearFieldManagerPrivateImpl::stopTargetDetection(const QString &)
{
- Q_UNUSED(accessModes);
- //Do nothing, because we dont have access modes for the target
+ detecting = false;
+ if (newIntentListener.exists())
+ newIntentListener->unregisterListener(this);
+ Q_EMIT targetDetectionStopped();
}
-void QNearFieldManagerPrivateImpl::newIntent(QAndroidJniObject intent)
+void QNearFieldManagerPrivateImpl::newIntent(QJniObject intent)
{
// This function is called from different thread and is used to move intent to main thread.
- QMetaObject::invokeMethod(this, "onTargetDiscovered", Qt::QueuedConnection, Q_ARG(QAndroidJniObject, intent));
+ QMetaObject::invokeMethod(this, [this, intent] {
+ this->onTargetDiscovered(intent);
+ }, Qt::QueuedConnection);
}
-QByteArray QNearFieldManagerPrivateImpl::getUid(const QAndroidJniObject &intent)
+QByteArray QNearFieldManagerPrivateImpl::getUid(const QJniObject &intent)
{
if (!intent.isValid())
return QByteArray();
- QAndroidJniEnvironment env;
- QAndroidJniObject tag = AndroidNfc::getTag(intent);
+ QJniObject tag = QtNfc::getTag(intent);
return getUidforTag(tag);
}
-void QNearFieldManagerPrivateImpl::onTargetDiscovered(QAndroidJniObject intent)
+void QNearFieldManagerPrivateImpl::onTargetDiscovered(QJniObject intent)
{
- // Only intents with a tag are relevant
- if (!AndroidNfc::getTag(intent).isValid())
- return;
-
// Getting UID
QByteArray uid = getUid(intent);
// Accepting all targets but only sending signal of requested types.
- NearFieldTarget *&target = m_detectedTargets[uid];
+ QNearFieldTargetPrivateImpl *&target = detectedTargets[uid];
if (target) {
target->setIntent(intent); // Updating existing target
} else {
- target = new NearFieldTarget(intent, uid, this);
- connect(target, &NearFieldTarget::targetDestroyed, this, &QNearFieldManagerPrivateImpl::onTargetDestroyed);
- connect(target, &NearFieldTarget::targetLost, this, &QNearFieldManagerPrivateImpl::targetLost);
+ target = new QNearFieldTargetPrivateImpl(intent, uid);
+
+ if (target->accessMethods() & requestedMethod) {
+ connect(target, &QNearFieldTargetPrivateImpl::targetDestroyed, this, &QNearFieldManagerPrivateImpl::onTargetDestroyed);
+ connect(target, &QNearFieldTargetPrivateImpl::targetLost, this, &QNearFieldManagerPrivateImpl::onTargetLost);
+ onTargetDetected(target);
+ } else {
+ delete target;
+ detectedTargets.remove(uid);
+ }
}
- emit targetDetected(target);
}
void QNearFieldManagerPrivateImpl::onTargetDestroyed(const QByteArray &uid)
{
- m_detectedTargets.remove(uid);
+ detectedTargets.remove(uid);
}
-QByteArray QNearFieldManagerPrivateImpl::getUidforTag(const QAndroidJniObject &tag)
+QByteArray QNearFieldManagerPrivateImpl::getUidforTag(const QJniObject &tag)
{
if (!tag.isValid())
return QByteArray();
- QAndroidJniEnvironment env;
- QAndroidJniObject tagId = tag.callObjectMethod("getId", "()[B");
+ QJniEnvironment env;
+ QJniObject tagId = tag.callMethod<jbyteArray>("getId");
QByteArray uid;
jsize len = env->GetArrayLength(tagId.object<jbyteArray>());
uid.resize(len);
@@ -342,17 +150,4 @@ QByteArray QNearFieldManagerPrivateImpl::getUidforTag(const QAndroidJniObject &t
return uid;
}
-void QNearFieldManagerPrivateImpl::updateReceiveState()
-{
- if (m_detecting) {
- AndroidNfc::registerListener(this);
- } else {
- if (ndefMessageHandlers.count() || ndefFilterHandlers.count()) {
- AndroidNfc::registerListener(this);
- } else {
- AndroidNfc::unregisterListener(this);
- }
- }
-}
-
QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldmanager_android_p.h b/src/nfc/qnearfieldmanager_android_p.h
index 7bf444d9..76a5fd20 100644
--- a/src/nfc/qnearfieldmanager_android_p.h
+++ b/src/nfc/qnearfieldmanager_android_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Centria research and development
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 Centria research and development
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNEARFIELDMANAGER_ANDROID_P_H
#define QNEARFIELDMANAGER_ANDROID_P_H
@@ -52,22 +16,18 @@
//
#include "qnearfieldmanager_p.h"
-#include "qnearfieldmanager.h"
-#include "qnearfieldtarget.h"
+#include "qnearfieldtarget_android_p.h"
#include "android/androidjninfc_p.h"
+#include "android/androidmainnewintentlistener_p.h"
#include <QHash>
-#include <QMap>
-#include <QtAndroidExtras/QAndroidJniObject>
-#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
-typedef QList<QNdefMessage> QNdefMessageList;
-
-class NearFieldTarget;
class QByteArray;
-class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivate, public AndroidNfc::AndroidNfcListenerInterface
+class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivate,
+ public QAndroidNfcListenerInterface
{
Q_OBJECT
@@ -75,39 +35,28 @@ public:
QNearFieldManagerPrivateImpl();
~QNearFieldManagerPrivateImpl() override;
- bool isAvailable() const override;
- bool isSupported() const override;
- bool startTargetDetection() override;
- void stopTargetDetection() override;
- int registerNdefMessageHandler(QObject *object, const QMetaMethod &method) override;
- int registerNdefMessageHandler(const QNdefFilter &filter, QObject *object, const QMetaMethod &method) override;
- bool unregisterNdefMessageHandler(int handlerId) override;
- void requestAccess(QNearFieldManager::TargetAccessModes accessModes) override;
- void releaseAccess(QNearFieldManager::TargetAccessModes accessModes) override;
- void newIntent(QAndroidJniObject intent);
- QByteArray getUid(const QAndroidJniObject &intent);
-
-public slots:
- void onTargetDiscovered(QAndroidJniObject intent);
- void onTargetDestroyed(const QByteArray &uid);
- void handlerTargetDetected(QNearFieldTarget *target);
- void handlerTargetLost(QNearFieldTarget *target);
- void handlerNdefMessageRead(const QNdefMessage &message, const QNearFieldTarget::RequestId &id);
- void handlerRequestCompleted(const QNearFieldTarget::RequestId &id);
- void handlerError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id);
+ bool isEnabled() const override;
+ bool isSupported(QNearFieldTarget::AccessMethod accessMethod) const override;
+ bool startTargetDetection(QNearFieldTarget::AccessMethod accessMethod) override;
+ void stopTargetDetection(const QString &errorMessage) override;
+ void newIntent(QJniObject intent) override;
+ QByteArray getUid(const QJniObject &intent);
protected:
- static QByteArray getUidforTag(const QAndroidJniObject &tag);
- void updateReceiveState();
+ static QByteArray getUidforTag(const QJniObject &tag);
private:
- bool m_detecting;
- QHash<QByteArray, NearFieldTarget*> m_detectedTargets;
- QMap<QNearFieldTarget::RequestId, QNearFieldTarget*> m_idToTarget;
+ bool detecting;
+ QNearFieldTarget::AccessMethod requestedMethod;
+ QHash<QByteArray, QNearFieldTargetPrivateImpl*> detectedTargets;
- int m_handlerID;
- QList< QPair<QPair<int, QObject *>, QMetaMethod> > ndefMessageHandlers;
- QList< QPair<QPair<int, QObject *>, QPair<QNdefFilter, QMetaMethod> > > ndefFilterHandlers;
+ QJniObject broadcastReceiver;
+
+private slots:
+ void onTargetDiscovered(QJniObject intent);
+ void onTargetDestroyed(const QByteArray &uid);
+ void onTargetDetected(QNearFieldTargetPrivateImpl *target);
+ void onTargetLost(QNearFieldTargetPrivateImpl *target);
};
QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldmanager_emulator.cpp b/src/nfc/qnearfieldmanager_emulator.cpp
deleted file mode 100644
index 4b5e5e0c..00000000
--- a/src/nfc/qnearfieldmanager_emulator.cpp
+++ /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 QtNfc 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 "qnearfieldmanager_emulator_p.h"
-#include "qnearfieldtarget_emulator_p.h"
-
-#include "qndefmessage.h"
-#include "qtlv_p.h"
-
-#include <QtCore/QDebug>
-
-QT_BEGIN_NAMESPACE
-
-QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl()
-{
- TagActivator *activator = TagActivator::instance();
- activator->initialize();
-
- connect(activator, &TagActivator::tagActivated, this, &QNearFieldManagerPrivateImpl::tagActivated);
- connect(activator, &TagActivator::tagDeactivated, this, &QNearFieldManagerPrivateImpl::tagDeactivated);
-}
-
-QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
-{
-}
-
-bool QNearFieldManagerPrivateImpl::isAvailable() const
-{
- return true;
-}
-
-void QNearFieldManagerPrivateImpl::reset()
-{
- TagActivator::instance()->reset();
-}
-
-void QNearFieldManagerPrivateImpl::tagActivated(TagBase *tag)
-{
- QNearFieldTarget *target = m_targets.value(tag).data();
- if (!target) {
- if (dynamic_cast<NfcTagType1 *>(tag))
- target = new TagType1(tag, this);
- else if (dynamic_cast<NfcTagType2 *>(tag))
- target = new TagType2(tag, this);
- else
- qFatal("Unknown emulator tag type");
-
- m_targets.insert(tag, target);
- }
-
- targetActivated(target);
-}
-
-void QNearFieldManagerPrivateImpl::tagDeactivated(TagBase *tag)
-{
- QNearFieldTarget *target = m_targets.value(tag).data();
- if (!target) {
- m_targets.remove(tag);
- return;
- }
-
- targetDeactivated(target);
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldmanager_emulator_p.h b/src/nfc/qnearfieldmanager_emulator_p.h
deleted file mode 100644
index 0416388a..00000000
--- a/src/nfc/qnearfieldmanager_emulator_p.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNEARFIELDMANAGER_EMULATOR_H
-#define QNEARFIELDMANAGER_EMULATOR_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 "qnearfieldmanagervirtualbase_p.h"
-#include "qnearfieldtarget.h"
-#include "qndeffilter.h"
-
-#include <QtCore/QObject>
-#include <QtCore/QPointer>
-
-QT_BEGIN_NAMESPACE
-
-class TagBase;
-class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivateVirtualBase
-{
- Q_OBJECT
-
-public:
- QNearFieldManagerPrivateImpl();
- ~QNearFieldManagerPrivateImpl() override;
-
- bool isAvailable() const override;
-
- void reset();
-
-private slots:
- void tagActivated(TagBase *tag);
- void tagDeactivated(TagBase *tag);
-
-private:
- void ndefReceived(const QNdefMessage &message, QNearFieldTarget *target);
-
- QMap<TagBase *, QPointer<QNearFieldTarget> > m_targets;
-
-};
-
-QT_END_NAMESPACE
-
-#endif // QNEARFIELDMANAGER_EMULATOR_H
diff --git a/src/nfc/qnearfieldmanager_generic.cpp b/src/nfc/qnearfieldmanager_generic.cpp
new file mode 100644
index 00000000..1a8df2ce
--- /dev/null
+++ b/src/nfc/qnearfieldmanager_generic.cpp
@@ -0,0 +1,24 @@
+// 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 <QCoreApplication>
+
+#include "qnearfieldmanager_generic_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Constructs a new near field manager private implementation.
+*/
+QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl()
+{
+}
+
+/*
+ Destroys the near field manager private implementation.
+*/
+QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldmanager_generic_p.h b/src/nfc/qnearfieldmanager_generic_p.h
new file mode 100644
index 00000000..b01cd9ad
--- /dev/null
+++ b/src/nfc/qnearfieldmanager_generic_p.h
@@ -0,0 +1,31 @@
+// 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 QNEARFIELDMANAGERIMPL_P_H
+#define QNEARFIELDMANAGERIMPL_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 "qnearfieldmanager_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivate
+{
+public:
+ QNearFieldManagerPrivateImpl();
+ ~QNearFieldManagerPrivateImpl() override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNEARFIELDMANAGERIMPL_P_H
diff --git a/src/nfc/qnearfieldmanager_ios.mm b/src/nfc/qnearfieldmanager_ios.mm
new file mode 100644
index 00000000..4ab00a51
--- /dev/null
+++ b/src/nfc/qnearfieldmanager_ios.mm
@@ -0,0 +1,278 @@
+// Copyright (C) 2020 Governikus GmbH & Co. KG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qnearfieldmanager_ios_p.h"
+
+#include "ios/qiosnfcndefsessiondelegate_p.h"
+#include "ios/qiostagreaderdelegate_p.h"
+#include "ios/qiosndefnotifier_p.h"
+
+#include "qnearfieldtarget_ios_p.h"
+
+#include <QDateTime>
+
+#include <memory>
+
+#import <CoreNFC/NFCReaderSession.h>
+#import <CoreNFC/NFCNDEFReaderSession.h>
+#import <CoreNFC/NFCTagReaderSession.h>
+
+QT_BEGIN_NAMESPACE
+
+QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl()
+{
+ auto notifier = std::make_unique<QNfcNdefNotifier>();
+
+ if (@available(iOS 13, *))
+ delegate = [[QT_MANGLE_NAMESPACE(QIosTagReaderDelegate) alloc] initWithListener:this];
+
+ connect(this, &QNearFieldManagerPrivateImpl::tagDiscovered,
+ this, &QNearFieldManagerPrivateImpl::onTagDiscovered,
+ Qt::QueuedConnection);
+ connect(this, &QNearFieldManagerPrivateImpl::didInvalidateWithError,
+ this, &QNearFieldManagerPrivateImpl::onDidInvalidateWithError,
+ Qt::QueuedConnection);
+
+ ndefDelegate = [[QIosNfcNdefSessionDelegate alloc] initWithNotifier:notifier.get()];
+ if (ndefDelegate) {
+ auto watchDog = notifier.release(); // Delegate took the ownership.
+
+ connect(watchDog, &QNfcNdefNotifier::tagDetected,
+ this, &QNearFieldManagerPrivateImpl::onTagDiscovered,
+ Qt::QueuedConnection);
+ connect(watchDog, &QNfcNdefNotifier::invalidateWithError,
+ this, &QNearFieldManagerPrivateImpl::onDidInvalidateWithError,
+ Qt::QueuedConnection);
+ } else {
+ qCWarning(QT_IOS_NFC, "Failed to allocate NDEF reading session's delegate");
+ }
+
+ sessionTimer.setInterval(2000);
+ sessionTimer.setSingleShot(true);
+ connect(&sessionTimer, &QTimer::timeout, this, &QNearFieldManagerPrivateImpl::onSessionTimer);
+}
+
+QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
+{
+ if (@available(iOS 13, *))
+ [delegate release];
+
+ if (!ndefDelegate)
+ return;
+
+ if (auto queue = qt_Nfc_Queue()) {
+ dispatch_sync(queue, ^{
+ [ndefDelegate abort];
+ });
+ }
+
+ [ndefDelegate release];
+}
+
+bool QNearFieldManagerPrivateImpl::isSupported(QNearFieldTarget::AccessMethod accessMethod) const
+{
+ switch (accessMethod) {
+ case QNearFieldTarget::AnyAccess:
+ case QNearFieldTarget::NdefAccess:
+ return NFCNDEFReaderSession.readingAvailable;
+ case QNearFieldTarget::TagTypeSpecificAccess:
+ if (@available(iOS 13, *))
+ return NFCTagReaderSession.readingAvailable;
+ Q_FALLTHROUGH();
+ case QNearFieldTarget::UnknownAccess:
+ return false;
+ }
+}
+
+bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::AccessMethod accessMethod)
+{
+ if (detectionRunning)
+ return false;
+
+ activeAccessMethod = QNearFieldTarget::UnknownAccess;
+
+ switch (accessMethod) {
+ case QNearFieldTarget::UnknownAccess:
+ case QNearFieldTarget::AnyAccess:
+ return false;
+ case QNearFieldTarget::TagTypeSpecificAccess:
+ if (@available(iOS 13, *))
+ if (NFCTagReaderSession.readingAvailable) {
+ detectionRunning = scheduleSession(accessMethod);
+ if (detectionRunning)
+ activeAccessMethod = accessMethod;
+ return detectionRunning;
+ }
+ return false;
+ case QNearFieldTarget::NdefAccess:
+ if (NFCNDEFReaderSession.readingAvailable) {
+ detectionRunning = scheduleSession(accessMethod);
+ if (detectionRunning)
+ activeAccessMethod = accessMethod;
+ return detectionRunning;
+ }
+ return false;
+ }
+
+ return false;
+}
+
+void QNearFieldManagerPrivateImpl::stopTargetDetection(const QString &errorMessage)
+{
+ if (!detectionRunning)
+ return;
+
+ isSessionScheduled = false;
+
+ if (activeAccessMethod == QNearFieldTarget::TagTypeSpecificAccess) {
+ stopSession(errorMessage);
+ } else if (activeAccessMethod == QNearFieldTarget::NdefAccess) {
+ stopNdefSession(errorMessage);
+ } else {
+ qCWarning(QT_IOS_NFC, "Unknown access method, cannot stop target detection");
+ return;
+ }
+
+ detectionRunning = false;
+ Q_EMIT targetDetectionStopped();
+}
+
+bool QNearFieldManagerPrivateImpl::scheduleSession(QNearFieldTarget::AccessMethod accessMethod)
+{
+ if (sessionTimer.isActive()) {
+ isSessionScheduled = true;
+ return true;
+ }
+ isSessionScheduled = false;
+
+ if (accessMethod == QNearFieldTarget::TagTypeSpecificAccess) {
+ startSession();
+ return true;
+ } else if (accessMethod == QNearFieldTarget::NdefAccess) {
+ return startNdefSession();
+ }
+
+ return false;
+}
+
+void QNearFieldManagerPrivateImpl::startSession()
+{
+ if (@available(iOS 13, *)) {
+ [delegate startSession];
+ }
+}
+
+bool QNearFieldManagerPrivateImpl::startNdefSession()
+{
+ if (!ndefDelegate)
+ return false;
+
+ if (auto queue = qt_Nfc_Queue()) {
+ __block bool startSessionSucceded = false;
+ dispatch_sync(queue, ^{ startSessionSucceded = [ndefDelegate startSession]; });
+ return startSessionSucceded;
+ }
+
+ return false;
+}
+
+void QNearFieldManagerPrivateImpl::stopSession(const QString &error)
+{
+ Q_ASSERT(activeAccessMethod == QNearFieldTarget::TagTypeSpecificAccess);
+
+ clearTargets();
+
+ if (@available(iOS 13, *)) {
+ [delegate stopSession:error];
+ }
+}
+
+void QNearFieldManagerPrivateImpl::stopNdefSession(const QString &error)
+{
+ Q_ASSERT(activeAccessMethod == QNearFieldTarget::NdefAccess);
+
+ clearTargets();
+
+ if (auto queue = qt_Nfc_Queue()) {
+ dispatch_sync(queue, ^{
+ [ndefDelegate stopSession:error];
+ });
+ }
+}
+
+void QNearFieldManagerPrivateImpl::clearTargets()
+{
+ auto i = detectedTargets.begin();
+ while (i != detectedTargets.end()) {
+ (*i)->invalidate();
+ i = detectedTargets.erase(i);
+ }
+}
+
+
+void QNearFieldManagerPrivateImpl::setUserInformation(const QString &message)
+{
+ if (activeAccessMethod != QNearFieldTarget::NdefAccess)
+ [delegate alertMessage:message];
+
+ if (detectionRunning) {
+ // Too late!
+ qCWarning(QT_IOS_NFC,
+ "User information must be set prior before the target detection started");
+ return;
+ }
+
+ if (auto queue = qt_Nfc_Queue()) {
+ dispatch_sync(queue, ^{
+ [ndefDelegate setAlertMessage:message];
+ });
+ }
+}
+
+void QNearFieldManagerPrivateImpl::onTagDiscovered(void *tag)
+{
+ QNearFieldTargetPrivateImpl *target = nullptr;
+ if (activeAccessMethod == QNearFieldTarget::NdefAccess) {
+ [id(tag) retain];
+ target = new QNearFieldTargetPrivateImpl(ndefDelegate, tag);
+ } else {
+ target = new QNearFieldTargetPrivateImpl(tag);
+ }
+
+ detectedTargets += target;
+
+ connect(target, &QNearFieldTargetPrivateImpl::targetLost,
+ this, &QNearFieldManagerPrivateImpl::onTargetLost);
+ Q_EMIT targetDetected(new QNearFieldTarget(target, this));
+}
+
+void QNearFieldManagerPrivateImpl::onTargetLost(QNearFieldTargetPrivateImpl *target)
+{
+ detectedTargets.removeOne(target);
+ Q_EMIT targetLost(target->q_ptr);
+
+ if (detectionRunning && detectedTargets.isEmpty())
+ onDidInvalidateWithError(true);
+}
+
+void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart)
+{
+ clearTargets();
+ sessionTimer.start();
+
+ if (detectionRunning && doRestart && scheduleSession(activeAccessMethod))
+ return;
+
+ detectionRunning = false;
+ Q_EMIT targetDetectionStopped();
+}
+
+void QNearFieldManagerPrivateImpl::onSessionTimer()
+{
+ if (isSessionScheduled && !scheduleSession(activeAccessMethod)) {
+ detectionRunning = false;
+ Q_EMIT targetDetectionStopped();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldmanager_ios_p.h b/src/nfc/qnearfieldmanager_ios_p.h
new file mode 100644
index 00000000..ef638ecb
--- /dev/null
+++ b/src/nfc/qnearfieldmanager_ios_p.h
@@ -0,0 +1,84 @@
+// Copyright (C) 2020 Governikus GmbH & Co. KG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNEARFIELDMANAGER_IOS_P_H
+#define QNEARFIELDMANAGER_IOS_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/qcore_mac_p.h>
+
+#include "qnearfieldmanager_p.h"
+
+#include <QTimer>
+
+#import <os/availability.h>
+
+Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QIosTagReaderDelegate));
+
+Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QIosNfcNdefSessionDelegate));
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QIosNfcNdefSessionDelegate);
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldTargetPrivateImpl;
+
+class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivate
+{
+ Q_OBJECT
+
+public:
+ QNearFieldManagerPrivateImpl();
+ ~QNearFieldManagerPrivateImpl();
+
+ bool isEnabled() const override
+ {
+ return true;
+ }
+
+ bool isSupported(QNearFieldTarget::AccessMethod accessMethod) const override;
+
+ bool startTargetDetection(QNearFieldTarget::AccessMethod accessMethod) override;
+ void stopTargetDetection(const QString &errorMessage) override;
+
+ void setUserInformation(const QString &message) override;
+
+Q_SIGNALS:
+ void tagDiscovered(void *tag);
+ void didInvalidateWithError(bool doRestart);
+
+private:
+ QT_MANGLE_NAMESPACE(QIosTagReaderDelegate) *delegate API_AVAILABLE(ios(13.0)) = nullptr;
+ QIosNfcNdefSessionDelegate *ndefDelegate = nullptr;
+ bool detectionRunning = false;
+ bool isSessionScheduled = false;
+ QTimer sessionTimer;
+ QList<QNearFieldTargetPrivateImpl *> detectedTargets;
+ QNearFieldTarget::AccessMethod activeAccessMethod = QNearFieldTarget::UnknownAccess;
+
+ bool scheduleSession(QNearFieldTarget::AccessMethod accessMethod);
+ void startSession();
+ bool startNdefSession();
+ void stopSession(const QString &error);
+ void stopNdefSession(const QString &error);
+ void clearTargets();
+
+private Q_SLOTS:
+ void onTagDiscovered(void *target);
+ void onTargetLost(QNearFieldTargetPrivateImpl *target);
+ void onDidInvalidateWithError(bool doRestart);
+ void onSessionTimer();
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QNEARFIELDMANAGER_IOS_P_H
diff --git a/src/nfc/qnearfieldmanager_neard.cpp b/src/nfc/qnearfieldmanager_neard.cpp
index 4df1e0ef..4e942259 100644
--- a/src/nfc/qnearfieldmanager_neard.cpp
+++ b/src/nfc/qnearfieldmanager_neard.cpp
@@ -1,53 +1,17 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Copyright (C) 2016 BasysKom GmbH.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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, Copyright (C) 2016 BasysKom GmbH
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnearfieldmanager_neard_p.h"
#include "qnearfieldtarget_neard_p.h"
-#include "neard/adapter_p.h"
-#include "neard/dbusproperties_p.h"
-#include "neard/dbusobjectmanager_p.h"
+#include "adapter_interface.h"
+#include "properties_interface.h"
+#include "objectmanager_interface.h"
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_NFC_NEARD)
+Q_LOGGING_CATEGORY(QT_NFC_NEARD, "qt.nfc.neard")
// TODO We need a constructor that lets us select an adapter
QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl()
@@ -94,7 +58,7 @@ QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
stopTargetDetection();
}
-bool QNearFieldManagerPrivateImpl::isAvailable() const
+bool QNearFieldManagerPrivateImpl::isEnabled() const
{
if (!m_neardHelper->dbusObjectManager()->isValid() || m_adapterPath.isNull()) {
qCWarning(QT_NFC_NEARD) << "dbus object manager invalid or adapter path invalid";
@@ -117,25 +81,25 @@ bool QNearFieldManagerPrivateImpl::isAvailable() const
return false;
}
-bool QNearFieldManagerPrivateImpl::isSupported() const
+bool QNearFieldManagerPrivateImpl::isSupported(QNearFieldTarget::AccessMethod accessMethod) const
{
if (m_adapterPath.isEmpty()) {
qCWarning(QT_NFC_NEARD) << "no adapter found, neard daemon running?";
return false;
}
- if (!m_neardHelper->dbusObjectManager()->isValid() || m_adapterPath.isNull()) {
+ if (!m_neardHelper->dbusObjectManager()->isValid()) {
qCWarning(QT_NFC_NEARD) << "dbus object manager invalid or adapter path invalid";
return false;
}
- return true;
+ return accessMethod == QNearFieldTarget::NdefAccess;
}
-bool QNearFieldManagerPrivateImpl::startTargetDetection()
+bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::AccessMethod accessMethod)
{
qCDebug(QT_NFC_NEARD) << "starting target detection";
- if (!isAvailable())
+ if (!isEnabled() || accessMethod != QNearFieldTarget::NdefAccess)
return false;
OrgFreedesktopDBusPropertiesInterface dbusProperties(QStringLiteral("org.neard"),
@@ -188,7 +152,7 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection()
QDBusConnection::systemBus());
// possible modes: "Target", "Initiator", "Dual"
- QDBusPendingReply<> replyPollLoop = neardAdapter.StartPollLoop(QStringLiteral("Dual"));
+ QDBusPendingReply<> replyPollLoop = neardAdapter.StartPollLoop(QStringLiteral("Initiator"));
replyPollLoop.waitForFinished();
if (replyPollLoop.isError()) {
qCWarning(QT_NFC_NEARD) << "error when starting polling";
@@ -200,10 +164,10 @@ bool QNearFieldManagerPrivateImpl::startTargetDetection()
return true;
}
-void QNearFieldManagerPrivateImpl::stopTargetDetection()
+void QNearFieldManagerPrivateImpl::stopTargetDetection(const QString&)
{
qCDebug(QT_NFC_NEARD) << "stopping target detection";
- if (!isAvailable())
+ if (!isEnabled())
return;
OrgFreedesktopDBusPropertiesInterface dbusProperties(QStringLiteral("org.neard"),
@@ -240,40 +204,10 @@ void QNearFieldManagerPrivateImpl::stopTargetDetection()
}
}
-int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(QObject *object, const QMetaMethod &method)
-{
- Q_UNUSED(object);
- Q_UNUSED(method);
- return -1;
-}
-
-int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(const QNdefFilter &filter, QObject *object, const QMetaMethod &method)
-{
- Q_UNUSED(filter);
- Q_UNUSED(object);
- Q_UNUSED(method);
- return -1;
-}
-
-bool QNearFieldManagerPrivateImpl::unregisterNdefMessageHandler(int handlerId)
-{
- Q_UNUSED(handlerId);
- return false;
-}
-
-void QNearFieldManagerPrivateImpl::requestAccess(QNearFieldManager::TargetAccessModes accessModes)
-{
- Q_UNUSED(accessModes);
-}
-
-void QNearFieldManagerPrivateImpl::releaseAccess(QNearFieldManager::TargetAccessModes accessModes)
-{
- Q_UNUSED(accessModes);
-}
-
void QNearFieldManagerPrivateImpl::handleTagFound(const QDBusObjectPath &path)
{
- NearFieldTarget<QNearFieldTarget> *nfTag = new NearFieldTarget<QNearFieldTarget>(this, path);
+ auto priv = new QNearFieldTargetPrivateImpl(this, path);
+ auto nfTag = new QNearFieldTarget(priv, this);
m_activeTags.insert(path.path(), nfTag);
emit targetDetected(nfTag);
}
diff --git a/src/nfc/qnearfieldmanager_neard_p.h b/src/nfc/qnearfieldmanager_neard_p.h
index 88c45c1c..42cca80a 100644
--- a/src/nfc/qnearfieldmanager_neard_p.h
+++ b/src/nfc/qnearfieldmanager_neard_p.h
@@ -1,42 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Copyright (C) 2016 BasysKom GmbH.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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, Copyright (C) 2016 BasysKom GmbH
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNEARFIELDMANAGER_NEARD_H
#define QNEARFIELDMANAGER_NEARD_H
@@ -73,25 +36,13 @@ public:
QNearFieldManagerPrivateImpl();
~QNearFieldManagerPrivateImpl() override;
- bool isAvailable() const override;
+ bool isEnabled() const override;
- bool isSupported() const override;
+ bool isSupported(QNearFieldTarget::AccessMethod) const override;
- bool startTargetDetection() override;
+ bool startTargetDetection(QNearFieldTarget::AccessMethod) override;
- void stopTargetDetection() override;
-
- // not implemented
- int registerNdefMessageHandler(QObject *object, const QMetaMethod &method) override;
-
- int registerNdefMessageHandler(const QNdefFilter &filter, QObject *object,
- const QMetaMethod &method) override;
-
- bool unregisterNdefMessageHandler(int handlerId) override;
-
- void requestAccess(QNearFieldManager::TargetAccessModes accessModes) override;
-
- void releaseAccess(QNearFieldManager::TargetAccessModes accessModes) override;
+ void stopTargetDetection(const QString& = QString()) override;
private Q_SLOTS:
void handleTagFound(const QDBusObjectPath&);
diff --git a/src/nfc/qnearfieldmanager_p.h b/src/nfc/qnearfieldmanager_p.h
index 351c844a..6ec8ff0e 100644
--- a/src/nfc/qnearfieldmanager_p.h
+++ b/src/nfc/qnearfieldmanager_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 QtNfc 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 QNEARFIELDMANAGER_P_H
#define QNEARFIELDMANAGER_P_H
@@ -68,73 +32,43 @@ class Q_AUTOTEST_EXPORT QNearFieldManagerPrivate : public QObject
Q_OBJECT
public:
- explicit QNearFieldManagerPrivate(QObject *parent = 0)
+ explicit QNearFieldManagerPrivate(QObject *parent = nullptr)
: QObject(parent)
{
}
- ~QNearFieldManagerPrivate()
+ virtual ~QNearFieldManagerPrivate()
{
}
- virtual bool isAvailable() const
+ virtual bool isEnabled() const
{
return false;
}
- virtual bool isSupported() const
+ virtual bool isSupported(QNearFieldTarget::AccessMethod) const
{
return false;
}
- virtual bool startTargetDetection()
+ virtual bool startTargetDetection(QNearFieldTarget::AccessMethod)
{
return false;
}
- virtual void stopTargetDetection()
+ virtual void stopTargetDetection(const QString &)
{
}
- virtual int registerNdefMessageHandler(QObject *object, const QMetaMethod &/*method*/)
+ virtual void setUserInformation(const QString &)
{
- Q_UNUSED(object);
-
- return -1;
- }
-
- virtual int registerNdefMessageHandler(const QNdefFilter &/*filter*/,
- QObject *object, const QMetaMethod &/*method*/)
- {
- Q_UNUSED(object);
-
- return -1;
- }
-
- virtual bool unregisterNdefMessageHandler(int handlerId)
- {
- Q_UNUSED(handlerId);
-
- return false;
- }
-
- virtual void requestAccess(QNearFieldManager::TargetAccessModes accessModes)
- {
- m_requestedModes |= accessModes;
- }
-
- virtual void releaseAccess(QNearFieldManager::TargetAccessModes accessModes)
- {
- m_requestedModes &= ~accessModes;
}
signals:
void adapterStateChanged(QNearFieldManager::AdapterState state);
+ void targetDetectionStopped();
void targetDetected(QNearFieldTarget *target);
void targetLost(QNearFieldTarget *target);
-
-public:
- QNearFieldManager::TargetAccessModes m_requestedModes;
};
QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldmanager_pcsc.cpp b/src/nfc/qnearfieldmanager_pcsc.cpp
new file mode 100644
index 00000000..2ce795d7
--- /dev/null
+++ b/src/nfc/qnearfieldmanager_pcsc.cpp
@@ -0,0 +1,140 @@
+// 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 "qnearfieldmanager_pcsc_p.h"
+#include "qnearfieldtarget_pcsc_p.h"
+#include "pcsc/qpcscmanager_p.h"
+#include "pcsc/qpcsccard_p.h"
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QThread>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+Q_DECLARE_LOGGING_CATEGORY(QT_NFC_PCSC)
+
+/*
+ Constructs a new near field manager private implementation.
+
+ This object creates a worker thread with an instance of QPcscManager in
+ it. All the communication with QPcscManager is done using signal-slot
+ mechanism.
+*/
+QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ m_worker = new QPcscManager;
+ m_workerThread = new QThread(this);
+ m_workerThread->setObjectName(u"QtNfcThread"_s);
+ m_worker->moveToThread(m_workerThread);
+
+ connect(m_worker, &QPcscManager::cardInserted, this,
+ &QNearFieldManagerPrivateImpl::onCardInserted);
+ connect(this, &QNearFieldManagerPrivateImpl::startTargetDetectionRequest, m_worker,
+ &QPcscManager::onStartTargetDetectionRequest);
+ connect(this, &QNearFieldManagerPrivateImpl::stopTargetDetectionRequest, m_worker,
+ &QPcscManager::onStopTargetDetectionRequest);
+
+ m_workerThread->start();
+}
+
+/*
+ Destroys the near field manager private implementation.
+*/
+QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ // Destroy the worker. It calls QThread::quit() on the working thread in
+ // its destructor.
+ QMetaObject::invokeMethod(m_worker, &QObject::deleteLater, Qt::QueuedConnection);
+ m_workerThread->wait();
+}
+
+bool QNearFieldManagerPrivateImpl::isEnabled() const
+{
+ return true;
+}
+
+bool QNearFieldManagerPrivateImpl::isSupported(QNearFieldTarget::AccessMethod accessMethod) const
+{
+ switch (accessMethod) {
+ case QNearFieldTarget::TagTypeSpecificAccess:
+ case QNearFieldTarget::NdefAccess:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::AccessMethod accessMethod)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ Q_EMIT startTargetDetectionRequest(accessMethod);
+
+ return true;
+}
+
+void QNearFieldManagerPrivateImpl::stopTargetDetection(const QString &errorMessage)
+{
+ Q_UNUSED(errorMessage);
+
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ Q_EMIT stopTargetDetectionRequest();
+}
+
+/*
+ Invoked when the worker has detected a new card.
+
+ The worker will ensure that the card object remains valid until the manager
+ emits targetCreatedForCard() signal.
+*/
+void QNearFieldManagerPrivateImpl::onCardInserted(QPcscCard *card, const QByteArray &uid,
+ QNearFieldTarget::AccessMethods accessMethods,
+ int maxInputLength)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ auto priv = new QNearFieldTargetPrivateImpl(uid, accessMethods, maxInputLength, this);
+
+ connect(priv, &QNearFieldTargetPrivateImpl::disconnectRequest, card,
+ &QPcscCard::onDisconnectRequest);
+ connect(priv, &QNearFieldTargetPrivateImpl::destroyed, card, &QPcscCard::onTargetDestroyed);
+ connect(priv, &QNearFieldTargetPrivateImpl::sendCommandRequest, card,
+ &QPcscCard::onSendCommandRequest);
+ connect(priv, &QNearFieldTargetPrivateImpl::readNdefMessagesRequest, card,
+ &QPcscCard::onReadNdefMessagesRequest);
+ connect(priv, &QNearFieldTargetPrivateImpl::writeNdefMessagesRequest, card,
+ &QPcscCard::onWriteNdefMessagesRequest);
+
+ connect(priv, &QNearFieldTargetPrivateImpl::targetLost, this,
+ &QNearFieldManagerPrivateImpl::onTargetLost);
+
+ connect(card, &QPcscCard::disconnected, priv, &QNearFieldTargetPrivateImpl::onDisconnected);
+ connect(card, &QPcscCard::invalidated, priv, &QNearFieldTargetPrivateImpl::onInvalidated);
+ connect(card, &QPcscCard::requestCompleted, priv,
+ &QNearFieldTargetPrivateImpl::onRequestCompleted);
+ connect(card, &QPcscCard::ndefMessageRead, priv,
+ &QNearFieldTargetPrivateImpl::onNdefMessageRead);
+
+ auto target = new QNearFieldTarget(priv, this);
+
+ Q_EMIT targetDetected(target);
+
+ // Let the worker know that the card object can be deleted if it is no
+ // longer needed.
+ QMetaObject::invokeMethod(card, &QPcscCard::enableAutodelete, Qt::QueuedConnection);
+}
+
+void QNearFieldManagerPrivateImpl::onTargetLost(QNearFieldTargetPrivate *target)
+{
+ Q_EMIT targetLost(target->q_ptr);
+}
+
+Q_LOGGING_CATEGORY(QT_NFC_PCSC, "qt.nfc.pcsc")
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldmanager_pcsc_p.h b/src/nfc/qnearfieldmanager_pcsc_p.h
new file mode 100644
index 00000000..a74322af
--- /dev/null
+++ b/src/nfc/qnearfieldmanager_pcsc_p.h
@@ -0,0 +1,55 @@
+// 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 QNEARFIELDMANAGER_PCSC_P_H
+#define QNEARFIELDMANAGER_PCSC_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 "qnearfieldmanager_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QPcscManager;
+class QPcscCard;
+class QThread;
+
+class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivate
+{
+ Q_OBJECT
+public:
+ QNearFieldManagerPrivateImpl();
+ ~QNearFieldManagerPrivateImpl() override;
+
+ bool isEnabled() const override;
+ bool isSupported(QNearFieldTarget::AccessMethod accessMethod) const override;
+
+ bool startTargetDetection(QNearFieldTarget::AccessMethod accessMethod) override;
+ void stopTargetDetection(const QString &errorMessage) override;
+
+public Q_SLOTS:
+ void onCardInserted(QPcscCard *card, const QByteArray &uid,
+ QNearFieldTarget::AccessMethods accessMethods, int maxInputLength);
+ void onTargetLost(QNearFieldTargetPrivate *target);
+
+Q_SIGNALS:
+ void startTargetDetectionRequest(QNearFieldTarget::AccessMethod accessMethod);
+ void stopTargetDetectionRequest();
+
+private:
+ QThread *m_workerThread;
+ QPcscManager *m_worker;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNEARFIELDMANAGER_PCSC_P_H
diff --git a/src/nfc/qnearfieldmanagerimpl_p.cpp b/src/nfc/qnearfieldmanagerimpl_p.cpp
deleted file mode 100644
index c8de0432..00000000
--- a/src/nfc/qnearfieldmanagerimpl_p.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 <QCoreApplication>
-
-#include "qnearfieldmanagerimpl_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*
- Constructs a new near field manager private implementation.
-*/
-QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl()
-{
-}
-
-/*
- Destroys the near field manager private implementation.
-*/
-QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
-{
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldmanagerimpl_p.h b/src/nfc/qnearfieldmanagerimpl_p.h
deleted file mode 100644
index 334d745b..00000000
--- a/src/nfc/qnearfieldmanagerimpl_p.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNEARFIELDMANAGERIMPL_P_H
-#define QNEARFIELDMANAGERIMPL_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 "qnearfieldmanager_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivate
-{
-public:
- QNearFieldManagerPrivateImpl();
- ~QNearFieldManagerPrivateImpl();
-};
-
-QT_END_NAMESPACE
-
-#endif // QNEARFIELDMANAGERIMPL_P_H
diff --git a/src/nfc/qnearfieldmanagervirtualbase.cpp b/src/nfc/qnearfieldmanagervirtualbase.cpp
deleted file mode 100644
index 82e272ce..00000000
--- a/src/nfc/qnearfieldmanagervirtualbase.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 QtNfc 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 "qnearfieldmanagervirtualbase_p.h"
-#include "qndefmessage.h"
-#include "qtlv_p.h"
-
-QT_BEGIN_NAMESPACE
-
-//static inline bool matchesTarget(QNearFieldTarget::Type type,
-// const QList<QNearFieldTarget::Type> &types)
-//{
-// return types.contains(type) || types.contains(QNearFieldTarget::AnyTarget);
-//}
-
-QNearFieldManagerPrivateVirtualBase::QNearFieldManagerPrivateVirtualBase()
-{
-}
-
-QNearFieldManagerPrivateVirtualBase::~QNearFieldManagerPrivateVirtualBase()
-{
-}
-
-bool QNearFieldManagerPrivateVirtualBase::startTargetDetection()
-{
- return true;
-}
-
-void QNearFieldManagerPrivateVirtualBase::stopTargetDetection()
-{
-}
-
-int QNearFieldManagerPrivateVirtualBase::getFreeId()
-{
- if (!m_freeIds.isEmpty())
- return m_freeIds.takeFirst();
-
- m_registeredHandlers.append(Callback());
- return m_registeredHandlers.count() - 1;
-}
-
-int QNearFieldManagerPrivateVirtualBase::registerNdefMessageHandler(QObject *object,
- const QMetaMethod &method)
-{
- int id = getFreeId();
-
- Callback &callback = m_registeredHandlers[id];
-
- callback.filter = QNdefFilter();
- callback.object = object;
- callback.method = method;
-
- return id;
-}
-
-int QNearFieldManagerPrivateVirtualBase::registerNdefMessageHandler(const QNdefFilter &filter,
- QObject *object,
- const QMetaMethod &method)
-{
- int id = getFreeId();
-
- Callback &callback = m_registeredHandlers[id];
-
- callback.filter = filter;
- callback.object = object;
- callback.method = method;
-
- return id;
-}
-
-bool QNearFieldManagerPrivateVirtualBase::unregisterNdefMessageHandler(int id)
-{
- if (id < 0 || id >= m_registeredHandlers.count())
- return false;
-
- m_freeIds.append(id);
-
- while (m_freeIds.contains(m_registeredHandlers.count() - 1)) {
- m_freeIds.removeAll(m_registeredHandlers.count() - 1);
- m_registeredHandlers.removeLast();
- }
-
- return true;
-}
-
-void QNearFieldManagerPrivateVirtualBase::targetActivated(QNearFieldTarget *target)
-{
- //if (matchesTarget(target->type(), m_detectTargetTypes))
- emit targetDetected(target);
-
- if (target->hasNdefMessage()) {
- QTlvReader reader(target);
- while (!reader.atEnd()) {
- if (!reader.readNext()) {
- if (!target->waitForRequestCompleted(reader.requestId()))
- break;
- else
- continue;
- }
-
- // NDEF Message TLV
- if (reader.tag() == 0x03)
- ndefReceived(QNdefMessage::fromByteArray(reader.data()), target);
- }
- }
-}
-
-void QNearFieldManagerPrivateVirtualBase::targetDeactivated(QNearFieldTarget *target)
-{
- emit targetLost(target);
- QMetaObject::invokeMethod(target, "disconnected");
-}
-
-struct VerifyRecord
-{
- QNdefFilter::Record filterRecord;
- unsigned int count;
-};
-
-void QNearFieldManagerPrivateVirtualBase::ndefReceived(const QNdefMessage &message,
- QNearFieldTarget *target)
-{
- for (int i = 0; i < m_registeredHandlers.count(); ++i) {
- if (m_freeIds.contains(i))
- continue;
-
- Callback &callback = m_registeredHandlers[i];
-
- bool matched = true;
-
- QList<VerifyRecord> filterRecords;
- for (int j = 0; j < callback.filter.recordCount(); ++j) {
- VerifyRecord vr;
- vr.count = 0;
- vr.filterRecord = callback.filter.recordAt(j);
-
- filterRecords.append(vr);
- }
-
- for (const QNdefRecord &record : message) {
- for (int j = 0; matched && (j < filterRecords.count()); ++j) {
- VerifyRecord &vr = filterRecords[j];
-
- if (vr.filterRecord.typeNameFormat == record.typeNameFormat() &&
- ( vr.filterRecord.type == record.type() ||
- vr.filterRecord.type.isEmpty()) ) {
- ++vr.count;
- break;
- } else {
- if (callback.filter.orderMatch()) {
- if (vr.filterRecord.minimum <= vr.count &&
- vr.count <= vr.filterRecord.maximum) {
- continue;
- } else {
- matched = false;
- }
- }
- }
- }
- }
-
- for (int j = 0; matched && (j < filterRecords.count()); ++j) {
- const VerifyRecord &vr = filterRecords.at(j);
-
- if (vr.filterRecord.minimum <= vr.count && vr.count <= vr.filterRecord.maximum)
- continue;
- else
- matched = false;
- }
-
- if (matched) {
- callback.method.invoke(callback.object, Q_ARG(QNdefMessage, message),
- Q_ARG(QNearFieldTarget *, target));
- }
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldmanagervirtualbase_p.h b/src/nfc/qnearfieldmanagervirtualbase_p.h
deleted file mode 100644
index 164edaf5..00000000
--- a/src/nfc/qnearfieldmanagervirtualbase_p.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNEARFIELDMANAGERVIRTUALBASE_P_H
-#define QNEARFIELDMANAGERVIRTUALBASE_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 "qnearfieldmanager_p.h"
-
-#include <QtCore/QMetaMethod>
-
-QT_BEGIN_NAMESPACE
-
-class QNearFieldManagerPrivateVirtualBase : public QNearFieldManagerPrivate
-{
- Q_OBJECT
-
-public:
- QNearFieldManagerPrivateVirtualBase();
- ~QNearFieldManagerPrivateVirtualBase() override;
-
- bool startTargetDetection() override;
- void stopTargetDetection() override;
-
- int registerNdefMessageHandler(QObject *object, const QMetaMethod &method) override;
- int registerNdefMessageHandler(const QNdefFilter &filter,
- QObject *object, const QMetaMethod &method) override;
-
- bool unregisterNdefMessageHandler(int id) override;
-
-protected:
- struct Callback {
- QNdefFilter filter;
-
- QObject *object;
- QMetaMethod method;
- };
-
- void targetActivated(QNearFieldTarget *target);
- void targetDeactivated(QNearFieldTarget *target);
-
-private:
- int getFreeId();
- void ndefReceived(const QNdefMessage &message, QNearFieldTarget *target);
-
- QList<Callback> m_registeredHandlers;
- QList<int> m_freeIds;
- QList<QNearFieldTarget::Type> m_detectTargetTypes;
-};
-
-QT_END_NAMESPACE
-
-#endif // QNEARFIELDMANAGERVIRTUALBASE_P_H
diff --git a/src/nfc/qnearfieldsharemanager.cpp b/src/nfc/qnearfieldsharemanager.cpp
deleted file mode 100644
index 0709f60e..00000000
--- a/src/nfc/qnearfieldsharemanager.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 "qnearfieldsharemanager.h"
-#include "qnearfieldsharemanager_p.h"
-
-#include "qnearfieldsharemanagerimpl_p.h"
-
-#include "qnearfieldsharetarget.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QNearFieldShareManager
- \brief The QNearFieldShareManager class manages all interactions related to sharing files and data over NFC.
-
- \ingroup connectivity-nfc
- \inmodule QtNfc
- \since 5.3
-
- Applications can share NDEF data or file content using NFC technology by tapping two NFC-enabled devices
- together. The QNearFieldShareManager provides a high level entry point to access this functionality.
-
- The class allows both NDEF data and/or files to be shared between two devices by calling the setShareModes()
- method. This method specifies either an NDEF Data and/or a File transfer. The targetDetected() signal is emitted
- each time a share target is detected. A QNearFieldShareTarget pointer is passed with the signal, which can
- be used to share either an NDEF message or one or more files.
-
- The process of sharing files via NFC involves other underlying communication transports such as Bluetooth or Wi-Fi Direct.
- It is implementation specific how and what type of transports are used to perform file transfer. The overall time taken to
- transfer content depends on the maximum speed of the transport used. Note that the process of sharing NDEF message/data
- does not require the use of other transports outside NFC.
-
- If an error occurs, shareError() returns the error type.
-
- Platforms that do not support both NDEF data and file content sharing modes can return the supported subset in the
- supportedShareModes() method. Applications that call setShareModes() with an unsupported mode will receive an error
- signal with a UnsupportedShareModeError.
-
- Since sharing data over NFC is effectively a data pipe between two processes (one on the sender and one of
- the receiver), the application developer should only create a single instance of QNearFieldShareManager per
- application. This avoids the possibility that different parts of the same application attempt to all consume
- data transferred over NFC.
-*/
-
-/*!
- \enum QNearFieldShareManager::ShareError
-
- This enum specifies the share error type.
-
- \value NoError No error.
- \value UnknownError Unknown or internal error occurred.
- \value InvalidShareContentError Invalid content was provided for sharing.
- \value ShareCanceledError Data or file sharing is canceled on the local or remote device.
- \value ShareInterruptedError Data or file sharing is interrupted due to an I/O error.
- \value ShareRejectedError Data or file sharing is rejected by the remote device.
- \value UnsupportedShareModeError Data or file sharing is not supported by the share target.
- \value ShareAlreadyInProgressError Data or file sharing is already in progress.
- \value SharePermissionDeniedError File sharing is denied due to insufficient permission.
-*/
-
-/*!
- \enum QNearFieldShareManager::ShareMode
-
- This enum specifies the content type to be shared.
-
- \value NoShare No content is currently set to be shared.
- \value NdefShare Share NDEF message with target.
- \value FileShare Share file with target.
-*/
-
-/*!
- \fn void QNearFieldShareManager::targetDetected(QNearFieldShareTarget* shareTarget)
-
- This signal is emitted whenever a \a shareTarget is detected. The \a shareTarget
- instance is owned by QNearFieldShareManager and must not be deleted by the application.
-*/
-
-/*!
- \fn void QNearFieldShareManager::shareModesChanged(ShareModes modes)
-
- This signal is emitted whenever the share \a modes are changed.
-*/
-
-/*!
- \fn void QNearFieldShareManager::error(ShareError error)
-
- This signal is emitted whenever an \a error occurs related to a share request.
-*/
-
-/*!
- Constructs a new near field share manager with \a parent.
-*/
-QNearFieldShareManager::QNearFieldShareManager(QObject *parent)
-: QObject(parent), d_ptr(new QNearFieldShareManagerPrivateImpl(this))
-{
-}
-
-/*!
- Destroys the near field share manager.
-*/
-QNearFieldShareManager::~QNearFieldShareManager()
-{
-}
-
-/*!
- Initializes the NFC share \a mode to detect a QNearFieldShareTarget for data and/or file sharing.
- Calls to this method will overwrite previous share modes.
-
- A shareModesChanged() signal will be emitted when share modes are different from previous modes.
- A targetDetected() signal will be emitted if a share target is detected.
-*/
-void QNearFieldShareManager::setShareModes(ShareModes mode)
-{
- Q_D(QNearFieldShareManager);
- d->setShareModes(mode);
-}
-
-/*!
- Returns the shared modes supported by NFC.
-*/
-QNearFieldShareManager::ShareModes QNearFieldShareManager::supportedShareModes()
-{
- return QNearFieldShareManagerPrivateImpl::supportedShareModes();
-}
-
-/*!
- Returns which shared modes are set.
-*/
-QNearFieldShareManager::ShareModes QNearFieldShareManager::shareModes() const
-{
- Q_D(const QNearFieldShareManager);
- return d->shareModes();
-}
-
-/*!
- Returns the error code of the error that occurred.
- */
-QNearFieldShareManager::ShareError QNearFieldShareManager::shareError() const
-{
- Q_D(const QNearFieldShareManager);
- return d->shareError();
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldsharemanager.h b/src/nfc/qnearfieldsharemanager.h
deleted file mode 100644
index e34e9a64..00000000
--- a/src/nfc/qnearfieldsharemanager.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 QNEARFIELDSHAREMANAGER_H
-#define QNEARFIELDSHAREMANAGER_H
-
-#include <QtCore/QObject>
-#include <QtNfc/qtnfcglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-class QNearFieldShareManagerPrivate;
-class QNearFieldShareTarget;
-
-class Q_NFC_EXPORT QNearFieldShareManager : public QObject
-{
- Q_OBJECT
-
-public:
- explicit QNearFieldShareManager(QObject *parent = nullptr);
- ~QNearFieldShareManager();
-
- enum ShareError {
- NoError,
- UnknownError,
- InvalidShareContentError,
- ShareCanceledError,
- ShareInterruptedError,
- ShareRejectedError,
- UnsupportedShareModeError,
- ShareAlreadyInProgressError,
- SharePermissionDeniedError
- };
- Q_ENUM(ShareError)
-
- enum ShareMode {
- NoShare = 0x00,
- NdefShare = 0x01,
- FileShare = 0x02
- };
- Q_ENUM(ShareMode)
- Q_DECLARE_FLAGS(ShareModes, ShareMode)
-
-public:
- static QNearFieldShareManager::ShareModes supportedShareModes();
- void setShareModes(ShareModes modes);
- QNearFieldShareManager::ShareModes shareModes() const;
- QNearFieldShareManager::ShareError shareError() const;
-
-Q_SIGNALS:
- void targetDetected(QNearFieldShareTarget* shareTarget);
- void shareModesChanged(QNearFieldShareManager::ShareModes modes);
- void error(QNearFieldShareManager::ShareError error);
-
-private:
- QScopedPointer<QNearFieldShareManagerPrivate> const d_ptr;
- Q_DECLARE_PRIVATE(QNearFieldShareManager)
- Q_DISABLE_COPY(QNearFieldShareManager)
-
- friend class QNearFieldShareManagerPrivateImpl;
- friend class QNearFieldShareTargetPrivateImpl;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QNearFieldShareManager::ShareModes)
-
-QT_END_NAMESPACE
-
-#endif /* QNEARFIELDSHAREMANAGER_H */
diff --git a/src/nfc/qnearfieldsharemanager_p.h b/src/nfc/qnearfieldsharemanager_p.h
deleted file mode 100644
index fc802901..00000000
--- a/src/nfc/qnearfieldsharemanager_p.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 QNEARFIELDSHAREMANAGER_P_H_
-#define QNEARFIELDSHAREMANAGER_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 "qnearfieldsharemanager.h"
-#include <QtCore/QObject>
-
-QT_BEGIN_NAMESPACE
-
-class QNearFieldShareManagerPrivate : public QObject
-{
- Q_OBJECT
-
-public:
- QNearFieldShareManagerPrivate(QNearFieldShareManager* q)
- : QObject(q)
- {
- }
-
- ~QNearFieldShareManagerPrivate()
- {
- }
-
- virtual void setShareModes(QNearFieldShareManager::ShareModes modes)
- {
- Q_UNUSED(modes)
- }
-
- virtual QNearFieldShareManager::ShareModes shareModes() const
- {
- return QNearFieldShareManager::NoShare;
- }
-
- virtual QNearFieldShareManager::ShareError shareError() const
- {
- return QNearFieldShareManager::NoError;
- }
-};
-
-QT_END_NAMESPACE
-
-#endif /* QNEARFIELDSHAREMANAGER_P_H_ */
diff --git a/src/nfc/qnearfieldsharemanagerimpl_p.cpp b/src/nfc/qnearfieldsharemanagerimpl_p.cpp
deleted file mode 100644
index 0187795c..00000000
--- a/src/nfc/qnearfieldsharemanagerimpl_p.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 "qnearfieldsharemanagerimpl_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QNearFieldShareManagerPrivateImpl::QNearFieldShareManagerPrivateImpl(QNearFieldShareManager* q)
- : QNearFieldShareManagerPrivate(q)
-{
-}
-
-QNearFieldShareManagerPrivateImpl::~QNearFieldShareManagerPrivateImpl()
-{
-}
-
-QNearFieldShareManager::ShareModes QNearFieldShareManagerPrivateImpl::supportedShareModes()
-{
- return QNearFieldShareManager::NoShare;
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldsharemanagerimpl_p.h b/src/nfc/qnearfieldsharemanagerimpl_p.h
deleted file mode 100644
index c201f07b..00000000
--- a/src/nfc/qnearfieldsharemanagerimpl_p.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 QNEARFIELDSHAREMANAGERIMPL_P_H_
-#define QNEARFIELDSHAREMANAGERIMPL_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 "qnearfieldsharemanager_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QNearFieldShareManagerPrivateImpl : public QNearFieldShareManagerPrivate
-{
-public:
- QNearFieldShareManagerPrivateImpl(QNearFieldShareManager* q);
- ~QNearFieldShareManagerPrivateImpl();
-
- static QNearFieldShareManager::ShareModes supportedShareModes();
-};
-
-QT_END_NAMESPACE
-
-#endif /* QNEARFIELDSHAREMANAGERIMPL_P_H_ */
diff --git a/src/nfc/qnearfieldsharetarget.cpp b/src/nfc/qnearfieldsharetarget.cpp
deleted file mode 100644
index 16ba88f7..00000000
--- a/src/nfc/qnearfieldsharetarget.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 "qnearfieldsharetarget.h"
-#include "qnearfieldsharetarget_p.h"
-
-#include "qnearfieldsharetargetimpl_p.h"
-
-#include "qnearfieldsharemanager.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QNearFieldShareTarget
- \brief The QNearFieldShareTarget class transfers data to remote device over NFC.
-
- \ingroup connectivity-nfc
- \inmodule QtNfc
- \since 5.3
-
- The QNearFieldShareTarget class can be used for sharing NDEF message or files to a remote
- NFC enabled device supporting the same protocol.
-
- \sa QNearFieldShareManager
-*/
-
-/*!
- \fn void QNearFieldShareTarget::error(QNearFieldShareManager::ShareError error)
-
- This signal is emitted whenever an \a error occurs during transfer.
-*/
-
-/*!
- \fn void QNearFieldShareTarget::shareFinished()
-
- This signal is emitted whenever a data or file transfer has completed successfully.
-*/
-
-/*!
- Constructs a new near field share target with \a parent.
-*/
-QNearFieldShareTarget::QNearFieldShareTarget(QNearFieldShareManager::ShareModes modes, QObject *parent)
-: QObject(parent), d_ptr(new QNearFieldShareTargetPrivateImpl(modes, this))
-{
-}
-
-/*!
- Destroys the near field share target.
-*/
-QNearFieldShareTarget::~QNearFieldShareTarget()
-{
-}
-
-/*!
- Returns the share mode supported by the share target.
-*/
-QNearFieldShareManager::ShareModes QNearFieldShareTarget::shareModes() const
-{
- Q_D(const QNearFieldShareTarget);
- return d->shareModes();
-}
-
-/*!
- Share the NDEF \a message via the share target. This method starts sharing asynchronously and returns immediately.
- The method returns true if the request is accepted, otherwise returns false. Sharing is completed when the shareFinished()
- signal is emitted.
-*/
-bool QNearFieldShareTarget::share(const QNdefMessage &message)
-{
- Q_D(QNearFieldShareTarget);
- return d->share(message);
-}
-
-/*!
- Share the \a files via the share target. This method starts sharing asynchronously and returns immediately.
- The method returns true if the request is accepted, otherwise returns false. Sharing is completed when the shareFinished()
- signal is emitted.
-*/
-bool QNearFieldShareTarget::share(const QList<QFileInfo> &files)
-{
- Q_D(QNearFieldShareTarget);
- return d->share(files);
-}
-
-/*!
- Cancel the data or file sharing in progress.
-*/
-void QNearFieldShareTarget::cancel()
-{
- Q_D(QNearFieldShareTarget);
- d->cancel();
-}
-
-/*!
- Returns true if data or file sharing is in progress, otherwise returns false.
-*/
-bool QNearFieldShareTarget::isShareInProgress() const
-{
- Q_D(const QNearFieldShareTarget);
- return d->isShareInProgress();
-}
-
-/*!
- Returns the error code of the error that occurred.
- */
-QNearFieldShareManager::ShareError QNearFieldShareTarget::shareError() const
-{
- Q_D(const QNearFieldShareTarget);
- return d->shareError();
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldsharetarget.h b/src/nfc/qnearfieldsharetarget.h
deleted file mode 100644
index 441ffda7..00000000
--- a/src/nfc/qnearfieldsharetarget.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 QNEARFIELDSHARETARGET_H
-#define QNEARFIELDSHARETARGET_H
-
-#include <QtCore/QObject>
-#include <QtCore/QFileInfo>
-#include <QtNfc/QNdefMessage>
-#include <QtNfc/QNearFieldShareManager>
-
-QT_BEGIN_NAMESPACE
-
-class QNearFieldShareTargetPrivate;
-
-class Q_NFC_EXPORT QNearFieldShareTarget : public QObject
-{
- Q_OBJECT
-
-public:
- ~QNearFieldShareTarget();
-
- QNearFieldShareManager::ShareModes shareModes() const;
- bool share(const QNdefMessage &message);
- bool share(const QList<QFileInfo> &files);
- void cancel();
- bool isShareInProgress() const;
- QNearFieldShareManager::ShareError shareError() const;
-
-Q_SIGNALS:
- void error(QNearFieldShareManager::ShareError error);
- void shareFinished();
-
-private:
- explicit QNearFieldShareTarget(QNearFieldShareManager::ShareModes modes, QObject *parent = nullptr);
-
- QNearFieldShareTargetPrivate *d_ptr;
- Q_DECLARE_PRIVATE(QNearFieldShareTarget)
- Q_DISABLE_COPY(QNearFieldShareTarget)
-
- friend class QNearFieldShareManagerPrivateImpl;
- friend class QNearFieldShareTargetPrivateImpl;
-};
-
-QT_END_NAMESPACE
-
-#endif /* QNEARFIELDSHARETARGET_H */
diff --git a/src/nfc/qnearfieldsharetarget_p.h b/src/nfc/qnearfieldsharetarget_p.h
deleted file mode 100644
index c6ae59d9..00000000
--- a/src/nfc/qnearfieldsharetarget_p.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 QNEARFIELDSHARETARGET_P_H
-#define QNEARFIELDSHARETARGET_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 "qnearfieldsharetarget.h"
-
-QT_BEGIN_NAMESPACE
-
-class QNearFieldShareTargetPrivate : public QObject
-{
- Q_OBJECT
-
-public:
- QNearFieldShareTargetPrivate(QNearFieldShareManager::ShareModes modes, QNearFieldShareTarget *q)
- : QObject(q)
- {
- Q_UNUSED(modes)
- }
-
- ~QNearFieldShareTargetPrivate()
- {
- }
-
- virtual QNearFieldShareManager::ShareModes shareModes() const
- {
- return QNearFieldShareManager::NoShare;
- }
-
- virtual bool share(const QNdefMessage &message)
- {
- Q_UNUSED(message)
- return false;
- }
-
- virtual bool share(const QList<QFileInfo> &files)
- {
- Q_UNUSED(files)
- return false;
- }
-
- virtual void cancel()
- {
- }
-
- virtual bool isShareInProgress() const
- {
- return false;
- }
-
- virtual QNearFieldShareManager::ShareError shareError() const
- {
- return QNearFieldShareManager::NoError;
- }
-};
-
-QT_END_NAMESPACE
-
-#endif /* QNEARFIELDSHARETARGET_P_H */
diff --git a/src/nfc/qnearfieldsharetargetimpl_p.cpp b/src/nfc/qnearfieldsharetargetimpl_p.cpp
deleted file mode 100644
index fbc35f6c..00000000
--- a/src/nfc/qnearfieldsharetargetimpl_p.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 "qnearfieldsharetargetimpl_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QNearFieldShareTargetPrivateImpl::QNearFieldShareTargetPrivateImpl(QNearFieldShareManager::ShareModes /*modes*/, QNearFieldShareTarget *q)
- : QNearFieldShareTargetPrivate(QNearFieldShareManager::NoShare, q)
-{
-}
-
-QNearFieldShareTargetPrivateImpl::~QNearFieldShareTargetPrivateImpl()
-{
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldsharetargetimpl_p.h b/src/nfc/qnearfieldsharetargetimpl_p.h
deleted file mode 100644
index 3df99271..00000000
--- a/src/nfc/qnearfieldsharetargetimpl_p.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/***************************************************************************
- **
- ** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the QtNfc 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 QNEARFIELDSHARETARGETIMPL_P_H
-#define QNEARFIELDSHARETARGETIMPL_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 "qnearfieldsharetarget_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QNearFieldShareTargetPrivateImpl : public QNearFieldShareTargetPrivate
-{
-public:
- QNearFieldShareTargetPrivateImpl(QNearFieldShareManager::ShareModes modes, QNearFieldShareTarget *q);
- ~QNearFieldShareTargetPrivateImpl();
-};
-
-QT_END_NAMESPACE
-
-#endif /* QNEARFIELDSHARETARGETIMPL_P_H */
diff --git a/src/nfc/qnearfieldtagtype1_p.h b/src/nfc/qnearfieldtagtype1_p.h
deleted file mode 100644
index ea288da7..00000000
--- a/src/nfc/qnearfieldtagtype1_p.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNEARFIELDTAGTYPE1_H
-#define QNEARFIELDTAGTYPE1_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 <QtNfc/QNearFieldTarget>
-
-QT_BEGIN_NAMESPACE
-
-class QNearFieldTagType1Private;
-
-class Q_AUTOTEST_EXPORT QNearFieldTagType1 : public QNearFieldTarget
-{
- Q_OBJECT
-
- Q_DECLARE_PRIVATE(QNearFieldTagType1)
-
-public:
- enum WriteMode {
- EraseAndWrite,
- WriteOnly
- };
- Q_ENUM(WriteMode)
-
- explicit QNearFieldTagType1(QObject *parent = 0);
- ~QNearFieldTagType1();
-
- Type type() const { return NfcTagType1; }
-
- bool hasNdefMessage();
- RequestId readNdefMessages();
- RequestId writeNdefMessages(const QList<QNdefMessage> &messages);
-
- quint8 version();
- virtual int memorySize();
-
- // DIGPROTO
- virtual RequestId readIdentification();
-
- // static memory functions
- virtual RequestId readAll();
- virtual RequestId readByte(quint8 address);
- virtual RequestId writeByte(quint8 address, quint8 data, WriteMode mode = EraseAndWrite);
-
- // dynamic memory functions
- virtual RequestId readSegment(quint8 segmentAddress);
- virtual RequestId readBlock(quint8 blockAddress);
- virtual RequestId writeBlock(quint8 blockAddress, const QByteArray &data,
- WriteMode mode = EraseAndWrite);
-
-protected:
- bool handleResponse(const QNearFieldTarget::RequestId &id, const QByteArray &response);
-
-private:
- QNearFieldTagType1Private *d_ptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QNEARFIELDTAGTYPE1_H
diff --git a/src/nfc/qnearfieldtagtype2_p.h b/src/nfc/qnearfieldtagtype2_p.h
deleted file mode 100644
index 29faa119..00000000
--- a/src/nfc/qnearfieldtagtype2_p.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNEARFIELDTAGTYPE2_H
-#define QNEARFIELDTAGTYPE2_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 <QtNfc/QNearFieldTarget>
-
-QT_BEGIN_NAMESPACE
-
-class QNearFieldTagType2Private;
-
-class Q_AUTOTEST_EXPORT QNearFieldTagType2 : public QNearFieldTarget
-{
- Q_OBJECT
-
- Q_DECLARE_PRIVATE(QNearFieldTagType2)
-
-public:
- explicit QNearFieldTagType2(QObject *parent = 0);
- ~QNearFieldTagType2();
-
- Type type() const { return NfcTagType2; }
-
- bool hasNdefMessage();
- RequestId readNdefMessages();
- RequestId writeNdefMessages(const QList<QNdefMessage> &messages);
-
- quint8 version();
- int memorySize();
-
- virtual RequestId readBlock(quint8 blockAddress);
- virtual RequestId writeBlock(quint8 blockAddress, const QByteArray &data);
- virtual RequestId selectSector(quint8 sector);
-
- void timerEvent(QTimerEvent *event);
-
-protected:
- bool handleResponse(const QNearFieldTarget::RequestId &id, const QByteArray &response);
-
-private:
- QNearFieldTagType2Private *d_ptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QNEARFIELDTAGTYPE2_H
diff --git a/src/nfc/qnearfieldtagtype3.cpp b/src/nfc/qnearfieldtagtype3.cpp
deleted file mode 100644
index 0954d65f..00000000
--- a/src/nfc/qnearfieldtagtype3.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qnearfieldtagtype3_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QNearFieldTagType3
- \brief The QNearFieldTagType3 class provides an interface for communicating with an NFC Tag
- Type 3 tag.
-
- \ingroup connectivity-nfc
- \inmodule QtNfc
- \internal
-*/
-
-/*!
- \fn Type QNearFieldTagType3::type() const
- \reimp
-*/
-
-/*!
- Constructs a new tag type 3 near field target with \a parent.
-*/
-QNearFieldTagType3::QNearFieldTagType3(QObject *parent) :
- QNearFieldTarget(parent)
-{
-}
-
-/*!
- Returns the system code of the target.
-*/
-quint16 QNearFieldTagType3::systemCode()
-{
- return 0;
-}
-
-/*!
- Returns a list of available services.
-*/
-QList<quint16> QNearFieldTagType3::services()
-{
- return QList<quint16>();
-}
-
-/*!
- Returns the memory size of the service specified by \a serviceCode.
-*/
-int QNearFieldTagType3::serviceMemorySize(quint16 serviceCode)
-{
- Q_UNUSED(serviceCode);
-
- return 0;
-}
-
-/*!
- Requests the data contents of the service specified by \a serviceCode. Returns a request id
- which can be used to track the completion status of the request.
-
- Once the request completes successfully the service data can be retrieved from the
- requestResponse() function. The response of this request will be a QByteArray.
-
- \sa requestCompleted(), waitForRequestCompleted()
-*/
-QNearFieldTarget::RequestId QNearFieldTagType3::serviceData(quint16 serviceCode)
-{
- Q_UNUSED(serviceCode);
-
- return RequestId();
-}
-
-/*!
- Writes \a data to the service specified by \a serviceCode. Returns a request id which can
- be used to track the completion status of the request.
-
- Once the request completes the response can be retrieved from the requestResponse() function.
- The response of this request will be a boolean value, true for success; otherwise false.
-
- \sa requestCompleted(), waitForRequestCompleted()
-*/
-QNearFieldTarget::RequestId QNearFieldTagType3::writeServiceData(quint16 serviceCode,
- const QByteArray &data)
-{
- Q_UNUSED(serviceCode);
- Q_UNUSED(data);
-
- return RequestId();
-}
-
-/*!
- Sends the \e check request to the target. Requests the service data blocks specified by
- \a serviceBlockList. Returns a request id which can be used to track the completion status of
- the request.
-
- The \a serviceBlockList parameter is a map with the key being the service code and the value
- being a list of block indexes to retrieve.
-
- Once the request completes the response can be retrieved from the requestResponse() function.
- The response of this request will be a QMap<quint16, QByteArray>, with the key being the
- service code and the value being the concatenated blocks retrieved for that service.
-
- This is a low level function, to retrieve the entire data contents of a service use
- serviceData().
-
- \sa requestCompleted(), waitForRequestCompleted()
-*/
-QNearFieldTarget::RequestId QNearFieldTagType3::check(const QMap<quint16, QList<quint16> > &serviceBlockList)
-{
- Q_UNUSED(serviceBlockList);
-
- return RequestId();
-}
-
-/*!
- Sends the \e update request to the target. Writes \a data to the services and block indexes
- sepecified by \a serviceBlockList. Returns a request id which can be used to track the
- completion status of the request.
-
- The \a serviceBlockList parameter is a map with the key being the service code and the value
- being a list of block indexes to write to.
-
- Once the request completes the response can be retried from the requestResponse() function. The
- response of this request will be a boolean value, true for success; otherwise false.
-
- This is a low level function, to write the entire data contents of a service use
- writeServiceData().
-
- \sa requestCompleted(), waitForRequestCompleted()
-*/
-QNearFieldTarget::RequestId QNearFieldTagType3::update(const QMap<quint16, QList<quint16> > &serviceBlockList,
- const QByteArray &data)
-{
- Q_UNUSED(serviceBlockList);
- Q_UNUSED(data);
-
- return RequestId();
-}
-
-/*!
- \reimp
-*/
-bool QNearFieldTagType3::handleResponse(const QNearFieldTarget::RequestId &id,
- const QByteArray &response)
-{
- return QNearFieldTarget::handleResponse(id, response);
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldtagtype3_p.h b/src/nfc/qnearfieldtagtype3_p.h
deleted file mode 100644
index a91bd7b5..00000000
--- a/src/nfc/qnearfieldtagtype3_p.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNEARFIELDTAGTYPE3_H
-#define QNEARFIELDTAGTYPE3_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/QList>
-#include <QtCore/QMap>
-#include <QtNfc/QNearFieldTarget>
-
-QT_BEGIN_NAMESPACE
-
-class Q_AUTOTEST_EXPORT QNearFieldTagType3 : public QNearFieldTarget
-{
- Q_OBJECT
-
-public:
- explicit QNearFieldTagType3(QObject *parent = 0);
-
- Type type() const { return NfcTagType3; }
-
- quint16 systemCode();
- QList<quint16> services();
- int serviceMemorySize(quint16 serviceCode);
-
- virtual RequestId serviceData(quint16 serviceCode);
- virtual RequestId writeServiceData(quint16 serviceCode, const QByteArray &data);
-
- virtual RequestId check(const QMap<quint16, QList<quint16> > &serviceBlockList);
- virtual RequestId update(const QMap<quint16, QList<quint16> > &serviceBlockList,
- const QByteArray &data);
-
-protected:
- bool handleResponse(const QNearFieldTarget::RequestId &id, const QByteArray &response);
-};
-
-QT_END_NAMESPACE
-
-#endif // QNEARFIELDTAGTYPE3_H
diff --git a/src/nfc/qnearfieldtagtype4.cpp b/src/nfc/qnearfieldtagtype4.cpp
deleted file mode 100644
index ce56a861..00000000
--- a/src/nfc/qnearfieldtagtype4.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qnearfieldtagtype4_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QNearFieldTagType4
- \brief The QNearFieldTagType4 class provides an interface for communicating with an NFC Tag
- Type 4 tag.
-
- \ingroup connectivity-nfc
- \inmodule QtNfc
- \internal
-*/
-
-/*!
- \fn Type QNearFieldTagType4::type() const
- \reimp
-*/
-
-/*!
- Constructs a new tag type 4 near field target with \a parent.
-*/
-QNearFieldTagType4::QNearFieldTagType4(QObject *parent)
-: QNearFieldTarget(parent)
-{
-}
-
-/*!
- Destroys the tag type 4 near field target.
-*/
-QNearFieldTagType4::~QNearFieldTagType4()
-{
-}
-
-/*!
- Returns the NFC Tag Type 4 specification version number that the tag supports.
-*/
-quint8 QNearFieldTagType4::version()
-{
- return 0;
-}
-
-/*!
- Requests that the file specified by \a name be selected. Upon success calls to read() and
- write() will act on the selected file. Returns a request id which can be used to track the
- completion status of the request.
-
- Once the request completes the response can be retrieved from the requestResponse() function.
- The response of this request will be a boolean value, true for success; otherwise false.
-
- \sa requestCompleted(), waitForRequestCompleted()
-*/
-QNearFieldTarget::RequestId QNearFieldTagType4::select(const QByteArray &name)
-{
- Q_UNUSED(name);
-
- return RequestId();
-}
-
-/*!
- Requests that the file specified by \a fileIdentifier be selected. Upon success calls to read()
- and write() will act on the selected file. Returns a request id which can be used to track the
- completion status of the request.
-
- Once the request completes the response can be retrieved from the requestResponse() function.
- The response of this request will be a boolean value, true for success; otherwise false.
-
- \sa requestCompleted(), waitForRequestCompleted()
-*/
-QNearFieldTarget::RequestId QNearFieldTagType4::select(quint16 fileIdentifier)
-{
- Q_UNUSED(fileIdentifier);
-
- return RequestId();
-}
-
-/*!
- Requests that \a length bytes be read from the currently selected file starting from
- \a startOffset. If \a length is 0 all data or the maximum read size bytes will be read,
- whichever is smaller. Returns a request id which can be used to track the completion status of
- the request.
-
- Once the request completes successfully the response can be retrieved from the
- requestResponse() function. The response of this request will be a QByteArray.
-
- \sa requestCompleted(), waitForRequestCompleted()
-*/
-QNearFieldTarget::RequestId QNearFieldTagType4::read(quint16 length, quint16 startOffset)
-{
- Q_UNUSED(length);
- Q_UNUSED(startOffset);
-
- return RequestId();
-}
-
-/*!
- Writes \a data to the currently selected file starting at \a startOffset. Returns a request id
- which can be used to track the completion status of the request.
-
- Once the request completes the response can be retrieved from the requestResponse() function.
- The response of this request will be a boolean value, true for success; otherwise false.
-
- \sa requestCompleted(), waitForRequestCompleted()
-*/
-QNearFieldTarget::RequestId QNearFieldTagType4::write(const QByteArray &data, quint16 startOffset)
-{
- Q_UNUSED(data);
- Q_UNUSED(startOffset);
-
- return RequestId();
-}
-
-/*!
- \reimp
-*/
-bool QNearFieldTagType4::handleResponse(const QNearFieldTarget::RequestId &id,
- const QByteArray &response)
-{
- return QNearFieldTarget::handleResponse(id, response);
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldtagtype4_p.h b/src/nfc/qnearfieldtagtype4_p.h
deleted file mode 100644
index 92bd0aaf..00000000
--- a/src/nfc/qnearfieldtagtype4_p.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNEARFIELDTAGTYPE4_H
-#define QNEARFIELDTAGTYPE4_H
-
-#include <QtNfc/QNearFieldTarget>
-
-//
-// 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.
-//
-
-QT_BEGIN_NAMESPACE
-
-class Q_AUTOTEST_EXPORT QNearFieldTagType4 : public QNearFieldTarget
-{
- Q_OBJECT
-
-public:
- explicit QNearFieldTagType4(QObject *parent = 0);
- ~QNearFieldTagType4();
-
- Type type() const { return NfcTagType4; }
-
- quint8 version();
-
- virtual RequestId select(const QByteArray &name);
- virtual RequestId select(quint16 fileIdentifier);
-
- virtual RequestId read(quint16 length = 0, quint16 startOffset = 0);
- virtual RequestId write(const QByteArray &data, quint16 startOffset = 0);
-
-protected:
- bool handleResponse(const QNearFieldTarget::RequestId &id, const QByteArray &response);
-};
-
-QT_END_NAMESPACE
-
-#endif // QNEARFIELDTAGTYPE4_H
diff --git a/src/nfc/qnearfieldtarget.cpp b/src/nfc/qnearfieldtarget.cpp
index 7d83db78..dbcca2bd 100644
--- a/src/nfc/qnearfieldtarget.cpp
+++ b/src/nfc/qnearfieldtarget.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qnearfieldtarget.h"
#include "qnearfieldtarget_p.h"
@@ -43,15 +7,15 @@
#include <QtCore/QString>
#include <QtCore/QUrl>
-#include <QtCore/QVariant>
#include <QtCore/QDebug>
-#include <QElapsedTimer>
#include <QCoreApplication>
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN_TAGGED(QNearFieldTarget::RequestId, QNearFieldTarget__RequestId)
+
/*!
\class QNearFieldTarget
\brief The QNearFieldTarget class provides an interface for communicating with a target
@@ -75,11 +39,7 @@ QT_BEGIN_NAMESPACE
and set the NDEF message.
If the target supports TagTypeSpecificAccess, sendCommand() can be used to send a single
- proprietary command to the target and retrieve the response. sendCommands() can be used to
- send multiple proprietary commands to the target and retrieve all of the responses.
-
- If the target supports LlcpAccess, the QLlcpSocket class can be used to connected to a
- service provided by the target.
+ proprietary command to the target and retrieve the response.
*/
/*!
@@ -91,7 +51,10 @@ QT_BEGIN_NAMESPACE
\value NfcTagType1 An NFC tag type 1 target.
\value NfcTagType2 An NFC tag type 2 target.
\value NfcTagType3 An NFC tag type 3 target.
- \value NfcTagType4 An NFC tag type 4 target.
+ \value NfcTagType4 An NFC tag type 4 target. This value is used if the NfcTagType4
+ cannot be further refined by NfcTagType4A or NfcTagType4B below.
+ \value NfcTagType4A An NFC tag type 4 target based on ISO/IEC 14443-3A.
+ \value NfcTagType4B An NFC tag type 4 target based on ISO/IEC 14443-3B.
\value MifareTag A Mifare target.
*/
@@ -104,8 +67,8 @@ QT_BEGIN_NAMESPACE
\value NdefAccess The target supports reading and writing NDEF messages using
readNdefMessages() and writeNdefMessages().
\value TagTypeSpecificAccess The target supports sending tag type specific commands using
- sendCommand() and sendCommands().
- \value LlcpAccess The target supports peer-to-peer LLCP communication.
+ sendCommand().
+ \value AnyAccess The target supports any of the known access types.
*/
/*!
@@ -121,23 +84,14 @@ QT_BEGIN_NAMESPACE
\value NoResponseError The target did not respond.
\value ChecksumMismatchError The checksum has detected a corrupted response.
\value InvalidParametersError Invalid parameters were passed to a tag type specific function.
+ \value ConnectionError Failed to connect to the target.
\value NdefReadError Failed to read NDEF messages from the target.
\value NdefWriteError Failed to write NDEF messages to the target.
\value CommandError Failed to send a command to the target.
+ \value TimeoutError The request could not be completed within the time
+ specified in waitForRequestCompleted().
*/
-#if QT_DEPRECATED_SINCE(5, 9)
-/*!
- \relates QNearFieldTarget
-
- Returns the NFC checksum of the first \a len bytes of \a data.
-*/
-quint16 qNfcChecksum(const char *data, uint len)
-{
- return qChecksum(data, len, Qt::ChecksumItuV41);
-}
-#endif
-
/*!
\fn void QNearFieldTarget::disconnected()
@@ -153,14 +107,6 @@ quint16 qNfcChecksum(const char *data, uint len)
*/
/*!
- \fn void QNearFieldTarget::ndefMessagesWritten()
-
- This signal is emitted when NDEF messages have been successfully written to the target.
-
- \sa writeNdefMessages()
-*/
-
-/*!
\fn void QNearFieldTarget::requestCompleted(const QNearFieldTarget::RequestId &id)
This signal is emitted when a request \a id completes.
@@ -176,6 +122,13 @@ quint16 qNfcChecksum(const char *data, uint len)
*/
/*!
+ \class QNearFieldTarget::RequestId
+ \inmodule QtNfc
+ \inheaderfile QNearFieldTarget
+ \brief A request id handle.
+*/
+
+/*!
Constructs a new invalid request id handle.
*/
QNearFieldTarget::RequestId::RequestId()
@@ -206,7 +159,7 @@ QNearFieldTarget::RequestId::~RequestId()
}
/*!
- Returns true if this is a valid request id; otherwise returns false.
+ Returns \c true if this is a valid request id; otherwise returns \c false.
*/
bool QNearFieldTarget::RequestId::isValid() const
{
@@ -219,7 +172,7 @@ bool QNearFieldTarget::RequestId::isValid() const
int QNearFieldTarget::RequestId::refCount() const
{
if (d)
- return d->ref.load();
+ return d->ref.loadRelaxed();
return 0;
}
@@ -229,7 +182,7 @@ int QNearFieldTarget::RequestId::refCount() const
*/
bool QNearFieldTarget::RequestId::operator<(const RequestId &other) const
{
- return d < other.d;
+ return std::less<const RequestIdPrivate*>()(d.constData(), other.d.constData());
}
/*!
@@ -261,11 +214,8 @@ QNearFieldTarget::RequestId &QNearFieldTarget::RequestId::operator=(const Reques
Constructs a new near field target with \a parent.
*/
QNearFieldTarget::QNearFieldTarget(QObject *parent)
-: QObject(parent), d_ptr(new QNearFieldTargetPrivate(this))
+: QNearFieldTarget(new QNearFieldTargetPrivate(this), parent)
{
- qRegisterMetaType<QNearFieldTarget::RequestId>();
- qRegisterMetaType<QNearFieldTarget::Error>();
- qRegisterMetaType<QNdefMessage>();
}
/*!
@@ -273,97 +223,73 @@ QNearFieldTarget::QNearFieldTarget(QObject *parent)
*/
QNearFieldTarget::~QNearFieldTarget()
{
- delete d_ptr;
+ Q_D(QNearFieldTarget);
+
+ d->disconnect();
}
/*!
- \fn QByteArray QNearFieldTarget::uid() const = 0
-
Returns the UID of the near field target.
-*/
-/*!
- Returns the URL of the near field target.
+ \note On iOS, this function returns an empty QByteArray for
+ a near field target discovered using NdefAccess method.
+
+ \sa QNearFieldTarget::AccessMethod
*/
-QUrl QNearFieldTarget::url() const
+QByteArray QNearFieldTarget::uid() const
{
- return QUrl();
+ Q_D(const QNearFieldTarget);
+
+ return d->uid();
}
/*!
- \fn QNearFieldTarget::Type QNearFieldTarget::type() const = 0
-
Returns the type of tag type of this near field target.
*/
-
-/*!
- \fn QNearFieldTarget::AccessMethods QNearFieldTarget::accessMethods() const = 0
-
- Returns the access methods support by this near field target.
-*/
-
-/*!
- \since 5.9
-
- Returns true if this feature is enabled.
-
- \sa setKeepConnection(), disconnect()
-*/
-bool QNearFieldTarget::keepConnection() const
+QNearFieldTarget::Type QNearFieldTarget::type() const
{
- return d_ptr->keepConnection();
+ Q_D(const QNearFieldTarget);
+
+ return d->type();
}
/*!
- \since 5.9
-
- Preserves the connection to the target device after processing a command or
- reading/writing NDEF messages if \a isPersistent is \c true.
- By default, this behavior is not enabled.
-
- Returns \c true if enabling this feature was successful. A possible
- reason for a failure is the lack of support on the used platform.
-
- Enabling this feature requires to use the disconnect() function too, to close the
- connection manually and enable communication with the target from a different instance.
- Disabling this feature will also close an open connection.
-
- \sa keepConnection(), disconnect()
+ Returns the access methods supported by this near field target.
*/
-bool QNearFieldTarget::setKeepConnection(bool isPersistent)
+QNearFieldTarget::AccessMethods QNearFieldTarget::accessMethods() const
{
- return d_ptr->setKeepConnection(isPersistent);
+ Q_D(const QNearFieldTarget);
+
+ return d->accessMethods();
}
/*!
\since 5.9
- Closes the connection to the target.
+ Closes the connection to the target to enable communication with the target
+ from a different instance. The connection will also be closed, when the
+ QNearFieldTarget is destroyed. A connection to the target device is
+ (re)created to process a command or read/write a NDEF messages.
- Returns true only if an existing connection was successfully closed.
-
- \sa keepConnection(), setKeepConnection()
+ Returns \c true only if an existing connection was successfully closed;
+ otherwise returns \c false.
*/
bool QNearFieldTarget::disconnect()
{
- return d_ptr->disconnect();
-}
+ Q_D(QNearFieldTarget);
-/*!
- Returns true if the target is processing commands; otherwise returns false.
-*/
-bool QNearFieldTarget::isProcessingCommand() const
-{
- return false;
+ return d->disconnect();
}
/*!
- Returns true if at least one NDEF message is stored on the near field target; otherwise returns
- false.
+ Returns \c true if at least one NDEF message is stored on the near field
+ target; otherwise returns \c false.
*/
bool QNearFieldTarget::hasNdefMessage()
{
- return false;
+ Q_D(QNearFieldTarget);
+
+ return d->hasNdefMessage();
}
/*!
@@ -374,10 +300,16 @@ bool QNearFieldTarget::hasNdefMessage()
An ndefMessageRead() signal will be emitted for each NDEF message. The requestCompleted()
signal will be emitted was all NDEF messages have been read. The error() signal is emitted if
an error occurs.
+
+ \note An attempt to read an NDEF message from a tag, that is in INITIALIZED
+ state as defined by NFC Forum, will fail with the \l NdefReadError, as the
+ tag is formatted to support NDEF but does not contain a message yet.
*/
QNearFieldTarget::RequestId QNearFieldTarget::readNdefMessages()
{
- return RequestId();
+ Q_D(QNearFieldTarget);
+
+ return d->readNdefMessages();
}
/*!
@@ -385,14 +317,14 @@ QNearFieldTarget::RequestId QNearFieldTarget::readNdefMessages()
to track the completion status of the request. An invalid request id will be returned if the
target does not support reading NDEF messages.
- The ndefMessagesWritten() signal will be emitted when the write operation completes
+ The requestCompleted() signal will be emitted when the write operation completes
successfully; otherwise the error() signal is emitted.
*/
QNearFieldTarget::RequestId QNearFieldTarget::writeNdefMessages(const QList<QNdefMessage> &messages)
{
- Q_UNUSED(messages);
+ Q_D(QNearFieldTarget);
- return RequestId();
+ return d->writeNdefMessages(messages);
}
/*!
@@ -401,11 +333,13 @@ QNearFieldTarget::RequestId QNearFieldTarget::writeNdefMessages(const QList<QNde
Returns the maximum number of bytes that can be sent with sendCommand. 0 will
be returned if the target does not support sending tag type specific commands.
- \sa sendCommand(), sendCommands()
+ \sa sendCommand()
*/
int QNearFieldTarget::maxCommandLength() const
{
- return d_ptr->maxCommandLength();
+ Q_D(const QNearFieldTarget);
+
+ return d->maxCommandLength();
}
/*!
@@ -423,123 +357,59 @@ int QNearFieldTarget::maxCommandLength() const
*/
QNearFieldTarget::RequestId QNearFieldTarget::sendCommand(const QByteArray &command)
{
- Q_UNUSED(command);
-
- emit error(UnsupportedError, RequestId());
-
- return RequestId();
-}
-
-/*!
- Sends multiple \a commands to the near field target. Returns a request id which can be used to
- track the completion status of the request. An invalid request id will be returned if the
- target does not support sending tag type specific commands.
-
- If all commands complete successfully the requestCompleted() signal will be emitted; otherwise
- the error() signal will be emitted. If a command fails succeeding commands from this call will
- not be processed.
-
- Once the request completes the response for successfully completed requests can be retrieved
- from the requestResponse() function. The response of this request will be a QList<QByteArray>.
-
- \sa requestCompleted(), waitForRequestCompleted()
-*/
-QNearFieldTarget::RequestId QNearFieldTarget::sendCommands(const QList<QByteArray> &commands)
-{
- Q_UNUSED(commands);
-
- emit error(UnsupportedError, RequestId());
+ Q_D(QNearFieldTarget);
- return RequestId();
+ return d->sendCommand(command);
}
/*!
- Waits up to \a msecs milliseconds for the request \a id to complete. Returns true if the
- request completes successfully and the requestCompeted() signal is emitted; otherwise returns
- false.
+ Waits up to \a msecs milliseconds for the request \a id to complete.
+ Returns \c true if the request completes successfully and the
+ requestCompeted() signal is emitted; otherwise returns \c false.
*/
bool QNearFieldTarget::waitForRequestCompleted(const RequestId &id, int msecs)
{
Q_D(QNearFieldTarget);
- QElapsedTimer timer;
- timer.start();
-
- do {
- if (d->m_decodedResponses.contains(id))
- return true;
- else
- QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents, 1);
- } while (timer.elapsed() <= msecs);
-
- return false;
+ return d->waitForRequestCompleted(id, msecs);
}
/*!
Returns the decoded response for request \a id. If the request is unknown or has not yet been
completed an invalid QVariant is returned.
*/
-QVariant QNearFieldTarget::requestResponse(const RequestId &id)
+QVariant QNearFieldTarget::requestResponse(const RequestId &id) const
{
- Q_D(QNearFieldTarget);
+ Q_D(const QNearFieldTarget);
- return d->m_decodedResponses.value(id);
+ return d->requestResponse(id);
}
/*!
- Sets the decoded response for request \a id to \a response. If \a emitRequestCompleted is true
- the requestCompleted() signal will be emitted for \a id; otherwise no signal will be emitted.
-
- \sa requestResponse()
+ \internal
*/
-void QNearFieldTarget::setResponseForRequest(const QNearFieldTarget::RequestId &id,
- const QVariant &response, bool emitRequestCompleted)
+QNearFieldTarget::QNearFieldTarget(QNearFieldTargetPrivate *backend, QObject *parent)
+: QObject(parent), d_ptr(backend)
{
Q_D(QNearFieldTarget);
- for (auto i = d->m_decodedResponses.begin(), end = d->m_decodedResponses.end(); i != end; /* erasing */) {
- // no more external references
- if (i.key().refCount() == 1)
- i = d->m_decodedResponses.erase(i);
- else
- ++i;
- }
-
- d->m_decodedResponses.insert(id, response);
+ d->q_ptr = this;
+ d->setParent(this);
- if (emitRequestCompleted)
- emit requestCompleted(id);
-}
-
-/*!
- Handles the \a response received for the request \a id. Returns true if the response is
- handled; otherwise returns false.
-
- Classes reimplementing this virtual function should call the base class implementation to
- ensure that requests initiated by those classes are handled correctly.
-
- The default implementation stores the response such that it can be retrieved by
- requestResponse().
-*/
-bool QNearFieldTarget::handleResponse(const QNearFieldTarget::RequestId &id,
- const QByteArray &response)
-{
- setResponseForRequest(id, response);
-
- return true;
-}
-
-/*!
- \since 5.12
+ qRegisterMetaType<QNearFieldTarget::RequestId>();
+ qRegisterMetaType<QNearFieldTarget::Error>();
+ qRegisterMetaType<QNdefMessage>();
- Reports the \a error for the request \a id by appending the signal emission to the event queue.
-*/
-void QNearFieldTarget::reportError(QNearFieldTarget::Error error,
- const QNearFieldTarget::RequestId &id)
-{
- QMetaObject::invokeMethod(this, [this, error, id]() {
- Q_EMIT this->error(error, id);
- }, Qt::QueuedConnection);
+ connect(d, &QNearFieldTargetPrivate::disconnected,
+ this, &QNearFieldTarget::disconnected);
+ connect(d, &QNearFieldTargetPrivate::ndefMessageRead,
+ this, &QNearFieldTarget::ndefMessageRead);
+ connect(d, &QNearFieldTargetPrivate::requestCompleted,
+ this, &QNearFieldTarget::requestCompleted);
+ connect(d, &QNearFieldTargetPrivate::error,
+ this, &QNearFieldTarget::error);
}
QT_END_NAMESPACE
+
+#include "moc_qnearfieldtarget.cpp"
diff --git a/src/nfc/qnearfieldtarget.h b/src/nfc/qnearfieldtarget.h
index 868b52d5..0d67011d 100644
--- a/src/nfc/qnearfieldtarget.h
+++ b/src/nfc/qnearfieldtarget.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNEARFIELDTARGET_H
#define QNEARFIELDTARGET_H
@@ -45,23 +9,21 @@
#include <QtCore/QMetaType>
#include <QtCore/QObject>
#include <QtCore/QSharedDataPointer>
+#include <QtCore/QVariant>
#include <QtNfc/qtnfcglobal.h>
QT_BEGIN_NAMESPACE
-class QString;
-class QUrl;
-QT_END_NAMESPACE
-
-QT_BEGIN_NAMESPACE
class QNdefMessage;
class QNearFieldTargetPrivate;
+class QNearFieldManagerPrivateImpl;
class Q_NFC_EXPORT QNearFieldTarget : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QNearFieldTarget)
+ friend class QNearFieldManagerPrivateImpl;
public:
enum Type {
@@ -70,6 +32,8 @@ public:
NfcTagType2,
NfcTagType3,
NfcTagType4,
+ NfcTagType4A,
+ NfcTagType4B,
MifareTag
};
Q_ENUM(Type)
@@ -78,7 +42,7 @@ public:
UnknownAccess = 0x00,
NdefAccess = 0x01,
TagTypeSpecificAccess = 0x02,
- LlcpAccess = 0x04
+ AnyAccess = 0xff
};
Q_ENUM(AccessMethod)
Q_DECLARE_FLAGS(AccessMethods, AccessMethod)
@@ -91,9 +55,11 @@ public:
NoResponseError,
ChecksumMismatchError,
InvalidParametersError,
+ ConnectionError,
NdefReadError,
NdefWriteError,
- CommandError
+ CommandError,
+ TimeoutError
};
Q_ENUM(Error)
@@ -119,64 +85,47 @@ public:
};
explicit QNearFieldTarget(QObject *parent = nullptr);
- virtual ~QNearFieldTarget();
+ ~QNearFieldTarget();
- virtual QByteArray uid() const = 0;
- virtual QUrl url() const;
+ QByteArray uid() const;
+ Type type() const;
+ AccessMethods accessMethods() const;
- virtual Type type() const = 0;
- virtual AccessMethods accessMethods() const = 0;
-
- bool keepConnection() const;
- bool setKeepConnection(bool isPersistent);
bool disconnect();
- bool isProcessingCommand() const;
-
// NdefAccess
- virtual bool hasNdefMessage();
- virtual RequestId readNdefMessages();
- virtual RequestId writeNdefMessages(const QList<QNdefMessage> &messages);
+ bool hasNdefMessage();
+ RequestId readNdefMessages();
+ RequestId writeNdefMessages(const QList<QNdefMessage> &messages);
// TagTypeSpecificAccess
int maxCommandLength() const;
- virtual RequestId sendCommand(const QByteArray &command);
- virtual RequestId sendCommands(const QList<QByteArray> &commands);
-
- virtual bool waitForRequestCompleted(const RequestId &id, int msecs = 5000);
+ RequestId sendCommand(const QByteArray &command);
- QVariant requestResponse(const RequestId &id);
- void setResponseForRequest(const QNearFieldTarget::RequestId &id, const QVariant &response,
- bool emitRequestCompleted = true);
-
-protected:
- Q_INVOKABLE virtual bool handleResponse(const QNearFieldTarget::RequestId &id,
- const QByteArray &response);
-
- void reportError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id);
+ bool waitForRequestCompleted(const RequestId &id, int msecs = 5000);
+ QVariant requestResponse(const RequestId &id) const;
Q_SIGNALS:
void disconnected();
void ndefMessageRead(const QNdefMessage &message);
- void ndefMessagesWritten();
void requestCompleted(const QNearFieldTarget::RequestId &id);
void error(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id);
+protected:
+ QNearFieldTarget(QNearFieldTargetPrivate *backend, QObject *parent = nullptr);
+
private:
QNearFieldTargetPrivate *d_ptr;
};
-#if QT_DEPRECATED_SINCE(5, 9)
-Q_NFC_EXPORT quint16 qNfcChecksum(const char * data, uint len);
-#endif
-
Q_DECLARE_OPERATORS_FOR_FLAGS(QNearFieldTarget::AccessMethods)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QNearFieldTarget::RequestId)
+QT_DECL_METATYPE_EXTERN_TAGGED(QNearFieldTarget::RequestId, QNearFieldTarget__RequestId,
+ Q_NFC_EXPORT)
#endif // QNEARFIELDTARGET_H
diff --git a/src/nfc/qnearfieldtarget_android.cpp b/src/nfc/qnearfieldtarget_android.cpp
index 78da6ac2..c7f842ae 100644
--- a/src/nfc/qnearfieldtarget_android.cpp
+++ b/src/nfc/qnearfieldtarget_android.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Centria research and development
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 Centria research and development
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnearfieldtarget_android_p.h"
#include "android/androidjninfc_p.h"
@@ -57,88 +21,73 @@
#define NFCTAGTYPE3 QStringLiteral("org.nfcforum.ndef.type3")
#define NFCTAGTYPE4 QStringLiteral("org.nfcforum.ndef.type4")
-NearFieldTarget::NearFieldTarget(QAndroidJniObject intent, const QByteArray uid, QObject *parent) :
- QNearFieldTarget(parent),
- m_intent(intent),
- m_uid(uid),
- m_keepConnection(false)
+QNearFieldTargetPrivateImpl::QNearFieldTargetPrivateImpl(QJniObject intent,
+ const QByteArray uid,
+ QObject *parent)
+: QNearFieldTargetPrivate(parent),
+ targetIntent(intent),
+ targetUid(uid)
{
updateTechList();
updateType();
setupTargetCheckTimer();
}
-NearFieldTarget::~NearFieldTarget()
+QNearFieldTargetPrivateImpl::~QNearFieldTargetPrivateImpl()
{
releaseIntent();
- emit targetDestroyed(m_uid);
+ Q_EMIT targetDestroyed(targetUid);
}
-QByteArray NearFieldTarget::uid() const
+QByteArray QNearFieldTargetPrivateImpl::uid() const
{
- return m_uid;
+ return targetUid;
}
-QNearFieldTarget::Type NearFieldTarget::type() const
+QNearFieldTarget::Type QNearFieldTargetPrivateImpl::type() const
{
- return m_type;
+ return tagType;
}
-QNearFieldTarget::AccessMethods NearFieldTarget::accessMethods() const
+QNearFieldTarget::AccessMethods QNearFieldTargetPrivateImpl::accessMethods() const
{
- AccessMethods result = UnknownAccess;
+ QNearFieldTarget::AccessMethods result = QNearFieldTarget::UnknownAccess;
- if (m_techList.contains(NDEFTECHNOLOGY)
- || m_techList.contains(NDEFFORMATABLETECHNOLOGY))
- result |= NdefAccess;
+ if (techList.contains(NDEFTECHNOLOGY)
+ || techList.contains(NDEFFORMATABLETECHNOLOGY))
+ result |= QNearFieldTarget::NdefAccess;
- if (m_techList.contains(ISODEPTECHNOLOGY)
- || m_techList.contains(NFCATECHNOLOGY)
- || m_techList.contains(NFCBTECHNOLOGY)
- || m_techList.contains(NFCFTECHNOLOGY)
- || m_techList.contains(NFCVTECHNOLOGY))
- result |= TagTypeSpecificAccess;
+ if (techList.contains(ISODEPTECHNOLOGY)
+ || techList.contains(NFCATECHNOLOGY)
+ || techList.contains(NFCBTECHNOLOGY)
+ || techList.contains(NFCFTECHNOLOGY)
+ || techList.contains(NFCVTECHNOLOGY))
+ result |= QNearFieldTarget::TagTypeSpecificAccess;
return result;
}
-bool NearFieldTarget::keepConnection() const
+bool QNearFieldTargetPrivateImpl::disconnect()
{
- return m_keepConnection;
-}
-
-bool NearFieldTarget::setKeepConnection(bool isPersistent)
-{
- m_keepConnection = isPersistent;
-
- if (!m_keepConnection)
- disconnect();
-
- return true;
-}
-
-bool NearFieldTarget::disconnect()
-{
- if (!m_tagTech.isValid())
+ if (!tagTech.isValid())
return false;
-
- bool connected = m_tagTech.callMethod<jboolean>("isConnected");
- if (catchJavaExceptions())
- return false;
-
+ QJniEnvironment env;
+ bool connected = tagTech.callMethod<jboolean>("isConnected");
if (!connected)
return false;
-
- m_tagTech.callMethod<void>("close");
- return !catchJavaExceptions();
+ auto methodId = env.findMethod<void>(tagTech.objectClass(), "close");
+ if (!methodId)
+ return false;
+ env->CallVoidMethod(tagTech.object(), methodId);
+ return !env.checkAndClearExceptions();
}
-bool NearFieldTarget::hasNdefMessage()
+bool QNearFieldTargetPrivateImpl::hasNdefMessage()
{
- return m_techList.contains(NDEFTECHNOLOGY);
+ return techList.contains(NDEFTECHNOLOGY);
}
-QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages()
+QNearFieldTarget::RequestId QNearFieldTargetPrivateImpl::readNdefMessages()
{
// Making sure that target has NDEF messages
if (!hasNdefMessage())
@@ -146,7 +95,7 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages()
// Making sure that target is still in range
QNearFieldTarget::RequestId requestId(new QNearFieldTarget::RequestIdPrivate);
- if (!m_intent.isValid()) {
+ if (!targetIntent.isValid()) {
reportError(QNearFieldTarget::TargetOutOfRangeError, requestId);
return requestId;
}
@@ -159,32 +108,25 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages()
// Connect
if (!connect()) {
- reportError(QNearFieldTarget::TargetOutOfRangeError, requestId);
+ reportError(QNearFieldTarget::ConnectionError, requestId);
return requestId;
}
// Get NdefMessage object
- QAndroidJniObject ndefMessage = m_tagTech.callObjectMethod("getNdefMessage", "()Landroid/nfc/NdefMessage;");
- if (catchJavaExceptions())
- ndefMessage = QAndroidJniObject();
+ QJniObject ndefMessage = tagTech.callMethod<QtJniTypes::NdefMessage>("getNdefMessage");
if (!ndefMessage.isValid()) {
reportError(QNearFieldTarget::NdefReadError, requestId);
return requestId;
}
// Convert to byte array
- QAndroidJniObject ndefMessageBA = ndefMessage.callObjectMethod("toByteArray", "()[B");
+ QJniObject ndefMessageBA = ndefMessage.callMethod<jbyteArray>("toByteArray");
QByteArray ndefMessageQBA = jbyteArrayToQByteArray(ndefMessageBA.object<jbyteArray>());
- if (!m_keepConnection) {
- // Closing connection
- disconnect(); // IOException at this point does not matter anymore.
- }
-
// Sending QNdefMessage, requestCompleted and exit.
QNdefMessage qNdefMessage = QNdefMessage::fromByteArray(ndefMessageQBA);
QMetaObject::invokeMethod(this, [this, qNdefMessage]() {
- Q_EMIT this->QNearFieldTarget::ndefMessageRead(qNdefMessage);
+ Q_EMIT this->q_ptr->ndefMessageRead(qNdefMessage);
}, Qt::QueuedConnection);
QMetaObject::invokeMethod(this, [this, requestId]() {
Q_EMIT this->requestCompleted(requestId);
@@ -197,51 +139,47 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages()
return requestId;
}
-int NearFieldTarget::maxCommandLength() const
+int QNearFieldTargetPrivateImpl::maxCommandLength() const
{
- QAndroidJniObject tagTech;
- if (m_techList.contains(ISODEPTECHNOLOGY))
+ QJniObject tagTech;
+ if (techList.contains(ISODEPTECHNOLOGY))
tagTech = getTagTechnology(ISODEPTECHNOLOGY);
- else if (m_techList.contains(NFCATECHNOLOGY))
+ else if (techList.contains(NFCATECHNOLOGY))
tagTech = getTagTechnology(NFCATECHNOLOGY);
- else if (m_techList.contains(NFCBTECHNOLOGY))
+ else if (techList.contains(NFCBTECHNOLOGY))
tagTech = getTagTechnology(NFCBTECHNOLOGY);
- else if (m_techList.contains(NFCFTECHNOLOGY))
+ else if (techList.contains(NFCFTECHNOLOGY))
tagTech = getTagTechnology(NFCFTECHNOLOGY);
- else if (m_techList.contains(NFCVTECHNOLOGY))
+ else if (techList.contains(NFCVTECHNOLOGY))
tagTech = getTagTechnology(NFCVTECHNOLOGY);
else
return 0;
- int returnVal = tagTech.callMethod<jint>("getMaxTransceiveLength");
- if (catchJavaExceptions())
- return 0;
-
- return returnVal;
+ return tagTech.callMethod<jint>("getMaxTransceiveLength");
}
-QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &command)
+QNearFieldTarget::RequestId QNearFieldTargetPrivateImpl::sendCommand(const QByteArray &command)
{
if (command.size() == 0 || command.size() > maxCommandLength()) {
- Q_EMIT QNearFieldTarget::error(QNearFieldTarget::InvalidParametersError, QNearFieldTarget::RequestId());
+ Q_EMIT error(QNearFieldTarget::InvalidParametersError, QNearFieldTarget::RequestId());
return QNearFieldTarget::RequestId();
}
// Making sure that target has commands
- if (!(accessMethods() & TagTypeSpecificAccess))
+ if (!(accessMethods() & QNearFieldTarget::TagTypeSpecificAccess))
return QNearFieldTarget::RequestId();
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
if (!setTagTechnology({ISODEPTECHNOLOGY, NFCATECHNOLOGY, NFCBTECHNOLOGY, NFCFTECHNOLOGY, NFCVTECHNOLOGY})) {
- Q_EMIT QNearFieldTarget::error(QNearFieldTarget::UnsupportedError, QNearFieldTarget::RequestId());
+ Q_EMIT error(QNearFieldTarget::UnsupportedError, QNearFieldTarget::RequestId());
return QNearFieldTarget::RequestId();
}
// Connecting
QNearFieldTarget::RequestId requestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate());
if (!connect()) {
- reportError(QNearFieldTarget::TargetOutOfRangeError, requestId);
+ reportError(QNearFieldTarget::ConnectionError, requestId);
return requestId;
}
@@ -251,20 +189,22 @@ QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &comma
env->SetByteArrayRegion(jba, 0, ba.size(), reinterpret_cast<jbyte*>(ba.data()));
// Writing
- QAndroidJniObject myNewVal = m_tagTech.callObjectMethod("transceive", "([B)[B", jba);
- if (catchJavaExceptions()) {
+ QJniObject myNewVal = tagTech.callMethod<jbyteArray>("transceive", jba);
+ if (!myNewVal.isValid()) {
+ // Some devices (Samsung, Huawei) throw an exception when the card is lost:
+ // "android.nfc.TagLostException: Tag was lost". But there seems to be a bug that
+ // isConnected still reports true. So we need to invalidate the target as soon as
+ // possible and treat the card as lost.
+ handleTargetLost();
+
reportError(QNearFieldTarget::CommandError, requestId);
return requestId;
}
QByteArray result = jbyteArrayToQByteArray(myNewVal.object<jbyteArray>());
env->DeleteLocalRef(jba);
- handleResponse(requestId, result);
+ setResponseForRequest(requestId, result, false);
- if (!m_keepConnection) {
- // Closing connection
- disconnect(); // IOException at this point does not matter anymore.
- }
QMetaObject::invokeMethod(this, [this, requestId]() {
Q_EMIT this->requestCompleted(requestId);
}, Qt::QueuedConnection);
@@ -272,15 +212,7 @@ QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &comma
return requestId;
}
-QNearFieldTarget::RequestId NearFieldTarget::sendCommands(const QList<QByteArray> &commands)
-{
- QNearFieldTarget::RequestId requestId;
- for (int i=0; i < commands.size(); i++)
- requestId = sendCommand(commands.at(i));
- return requestId;
-}
-
-QNearFieldTarget::RequestId NearFieldTarget::writeNdefMessages(const QList<QNdefMessage> &messages)
+QNearFieldTarget::RequestId QNearFieldTargetPrivateImpl::writeNdefMessages(const QList<QNdefMessage> &messages)
{
if (messages.size() == 0)
return QNearFieldTarget::RequestId();
@@ -288,14 +220,14 @@ QNearFieldTarget::RequestId NearFieldTarget::writeNdefMessages(const QList<QNdef
if (messages.size() > 1)
qWarning("QNearFieldTarget::writeNdefMessages: Android supports writing only one NDEF message per tag.");
- QAndroidJniEnvironment env;
+ QJniEnvironment env;
const char *writeMethod;
if (!setTagTechnology({NDEFFORMATABLETECHNOLOGY, NDEFTECHNOLOGY}))
return QNearFieldTarget::RequestId();
// Getting write method
- if (m_tech == NDEFFORMATABLETECHNOLOGY)
+ if (selectedTech == NDEFFORMATABLETECHNOLOGY)
writeMethod = "format";
else
writeMethod = "writeNdefMessage";
@@ -303,58 +235,65 @@ QNearFieldTarget::RequestId NearFieldTarget::writeNdefMessages(const QList<QNdef
// Connecting
QNearFieldTarget::RequestId requestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate());
if (!connect()) {
- reportError(QNearFieldTarget::TargetOutOfRangeError, requestId);
+ reportError(QNearFieldTarget::ConnectionError, requestId);
return requestId;
}
// Making NdefMessage object
const QNdefMessage &message = messages.first();
QByteArray ba = message.toByteArray();
- QAndroidJniObject jba = env->NewByteArray(ba.size());
+ QJniObject jba = env->NewByteArray(ba.size());
env->SetByteArrayRegion(jba.object<jbyteArray>(), 0, ba.size(), reinterpret_cast<jbyte*>(ba.data()));
- QAndroidJniObject jmessage = QAndroidJniObject("android/nfc/NdefMessage", "([B)V", jba.object<jbyteArray>());
- if (catchJavaExceptions()) {
+ QJniObject jmessage = QJniObject::construct<QtJniTypes::NdefMessage>(jba.object<jbyteArray>());
+ if (!jmessage.isValid()) {
reportError(QNearFieldTarget::UnknownError, requestId);
return requestId;
}
// Writing
- m_tagTech.callMethod<void>(writeMethod, "(Landroid/nfc/NdefMessage;)V", jmessage.object<jobject>());
- if (catchJavaExceptions()) {
+ auto methodId =
+ env.findMethod<void, QtJniTypes::NdefMessage>(tagTech.objectClass(), writeMethod);
+ if (methodId)
+ env->CallVoidMethod(tagTech.object(), methodId, jmessage.object<jobject>());
+ if (!methodId || env.checkAndClearExceptions()) {
reportError(QNearFieldTarget::NdefWriteError, requestId);
return requestId;
}
- if (!m_keepConnection)
- disconnect(); // IOException at this point does not matter anymore.
- QMetaObject::invokeMethod(this, "ndefMessagesWritten", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(this, [this, requestId]() {
+ Q_EMIT this->requestCompleted(requestId);
+ }, Qt::QueuedConnection);
return requestId;
}
-void NearFieldTarget::setIntent(QAndroidJniObject intent)
+void QNearFieldTargetPrivateImpl::setIntent(QJniObject intent)
{
- if (m_intent == intent)
+ if (targetIntent == intent)
return;
releaseIntent();
- m_intent = intent;
- if (m_intent.isValid()) {
+ targetIntent = intent;
+ if (targetIntent.isValid()) {
// Updating tech list and type in case of there is another tag with same UID as one before.
updateTechList();
updateType();
- m_targetCheckTimer->start();
+ targetCheckTimer->start();
}
}
-void NearFieldTarget::checkIsTargetLost()
+void QNearFieldTargetPrivateImpl::checkIsTargetLost()
{
- if (!m_intent.isValid() || !setTagTechnology(m_techList)) {
+ if (!targetIntent.isValid() || !setTagTechnology({selectedTech})) {
handleTargetLost();
return;
}
- bool connected = m_tagTech.callMethod<jboolean>("isConnected");
- if (catchJavaExceptions()) {
+ QJniEnvironment env;
+ bool connected = false;
+ auto methodId = env.findMethod<jboolean>(tagTech.objectClass(), "isConnected");
+ if (methodId)
+ connected = env->CallBooleanMethod(tagTech.object(), methodId);
+ if (!methodId || env.checkAndClearExceptions()) {
handleTargetLost();
return;
}
@@ -362,184 +301,194 @@ void NearFieldTarget::checkIsTargetLost()
if (connected)
return;
- m_tagTech.callMethod<void>("connect");
- if (catchJavaExceptions(false)) {
+ methodId = env.findMethod<void>(tagTech.objectClass(), "connect");
+ if (methodId)
+ env->CallVoidMethod(tagTech.object(), methodId);
+ if (!methodId || env.checkAndClearExceptions(QJniEnvironment::OutputMode::Silent)) {
handleTargetLost();
return;
}
- m_tagTech.callMethod<void>("close");
- if (catchJavaExceptions(false))
+ methodId = env.findMethod<void>(tagTech.objectClass(), "close");
+ if (methodId)
+ env->CallVoidMethod(tagTech.object(), methodId);
+ if (!methodId || env.checkAndClearExceptions(QJniEnvironment::OutputMode::Silent))
handleTargetLost();
}
-void NearFieldTarget::releaseIntent()
+void QNearFieldTargetPrivateImpl::releaseIntent()
{
- m_targetCheckTimer->stop();
+ targetCheckTimer->stop();
- m_intent = QAndroidJniObject();
+ targetIntent = QJniObject();
}
-void NearFieldTarget::updateTechList()
+void QNearFieldTargetPrivateImpl::updateTechList()
{
- if (!m_intent.isValid())
+ if (!targetIntent.isValid())
return;
// Getting tech list
- QAndroidJniEnvironment env;
- QAndroidJniObject tag = AndroidNfc::getTag(m_intent);
+ QJniEnvironment env;
+ QJniObject tag = QtNfc::getTag(targetIntent);
Q_ASSERT_X(tag.isValid(), "updateTechList", "could not get Tag object");
- QAndroidJniObject techListArray = tag.callObjectMethod("getTechList", "()[Ljava/lang/String;");
+ QJniObject techListArray = tag.callMethod<QtJniTypes::StringArray>("getTechList");
if (!techListArray.isValid()) {
handleTargetLost();
return;
}
// Converting tech list array to QStringList.
- m_techList.clear();
+ techList.clear();
jsize techCount = env->GetArrayLength(techListArray.object<jobjectArray>());
for (jsize i = 0; i < techCount; ++i) {
- QAndroidJniObject tech = env->GetObjectArrayElement(techListArray.object<jobjectArray>(), i);
- m_techList.append(tech.callObjectMethod<jstring>("toString").toString());
+ QJniObject tech = env->GetObjectArrayElement(techListArray.object<jobjectArray>(), i);
+ techList.append(tech.callMethod<jstring>("toString").toString());
}
}
-void NearFieldTarget::updateType()
+void QNearFieldTargetPrivateImpl::updateType()
{
- m_type = getTagType();
+ tagType = getTagType();
}
-QNearFieldTarget::Type NearFieldTarget::getTagType() const
+QNearFieldTarget::Type QNearFieldTargetPrivateImpl::getTagType() const
{
- QAndroidJniEnvironment env;
-
- if (m_techList.contains(NDEFTECHNOLOGY)) {
- QAndroidJniObject ndef = getTagTechnology(NDEFTECHNOLOGY);
- QString qtype = ndef.callObjectMethod("getType", "()Ljava/lang/String;").toString();
+ if (techList.contains(NDEFTECHNOLOGY)) {
+ QJniObject ndef = getTagTechnology(NDEFTECHNOLOGY);
+ QString qtype = ndef.callMethod<jstring>("getType").toString();
if (qtype.compare(MIFARETAG) == 0)
- return MifareTag;
+ return QNearFieldTarget::MifareTag;
if (qtype.compare(NFCTAGTYPE1) == 0)
- return NfcTagType1;
+ return QNearFieldTarget::NfcTagType1;
if (qtype.compare(NFCTAGTYPE2) == 0)
- return NfcTagType2;
+ return QNearFieldTarget::NfcTagType2;
if (qtype.compare(NFCTAGTYPE3) == 0)
- return NfcTagType3;
+ return QNearFieldTarget::NfcTagType3;
if (qtype.compare(NFCTAGTYPE4) == 0)
- return NfcTagType4;
- return ProprietaryTag;
- } else if (m_techList.contains(NFCATECHNOLOGY)) {
- if (m_techList.contains(MIFARECLASSICTECHNOLOGY))
- return MifareTag;
+ return QNearFieldTarget::NfcTagType4;
+ return QNearFieldTarget::ProprietaryTag;
+ } else if (techList.contains(NFCATECHNOLOGY)) {
+ if (techList.contains(MIFARECLASSICTECHNOLOGY))
+ return QNearFieldTarget::MifareTag;
// Checking ATQA/SENS_RES
// xxx0 0000 xxxx xxxx: Identifies tag Type 1 platform
- QAndroidJniObject nfca = getTagTechnology(NFCATECHNOLOGY);
- QAndroidJniObject atqaBA = nfca.callObjectMethod("getAtqa", "()[B");
+ QJniObject nfca = getTagTechnology(NFCATECHNOLOGY);
+ QJniObject atqaBA = nfca.callMethod<jbyteArray>("getAtqa");
QByteArray atqaQBA = jbyteArrayToQByteArray(atqaBA.object<jbyteArray>());
if (atqaQBA.isEmpty())
- return ProprietaryTag;
+ return QNearFieldTarget::ProprietaryTag;
if ((atqaQBA[0] & 0x1F) == 0x00)
- return NfcTagType1;
+ return QNearFieldTarget::NfcTagType1;
// Checking SAK/SEL_RES
// xxxx xxxx x00x x0xx: Identifies tag Type 2 platform
// xxxx xxxx x01x x0xx: Identifies tag Type 4 platform
jshort sakS = nfca.callMethod<jshort>("getSak");
if ((sakS & 0x0064) == 0x0000)
- return NfcTagType2;
+ return QNearFieldTarget::NfcTagType2;
else if ((sakS & 0x0064) == 0x0020)
- return NfcTagType4;
- return ProprietaryTag;
- } else if (m_techList.contains(NFCBTECHNOLOGY)) {
- return NfcTagType4;
- } else if (m_techList.contains(NFCFTECHNOLOGY)) {
- return NfcTagType3;
+ return QNearFieldTarget::NfcTagType4A;
+ return QNearFieldTarget::ProprietaryTag;
+ } else if (techList.contains(NFCBTECHNOLOGY)) {
+ return QNearFieldTarget::NfcTagType4B;
+ } else if (techList.contains(NFCFTECHNOLOGY)) {
+ return QNearFieldTarget::NfcTagType3;
}
- return ProprietaryTag;
+ return QNearFieldTarget::ProprietaryTag;
}
-void NearFieldTarget::setupTargetCheckTimer()
+void QNearFieldTargetPrivateImpl::setupTargetCheckTimer()
{
- m_targetCheckTimer = new QTimer(this);
- m_targetCheckTimer->setInterval(1000);
- QObject::connect(m_targetCheckTimer, &QTimer::timeout, this, &NearFieldTarget::checkIsTargetLost);
- m_targetCheckTimer->start();
+ targetCheckTimer = new QTimer(this);
+ targetCheckTimer->setInterval(1000);
+ QObject::connect(targetCheckTimer, &QTimer::timeout, this, &QNearFieldTargetPrivateImpl::checkIsTargetLost);
+ targetCheckTimer->start();
}
-void NearFieldTarget::handleTargetLost()
+void QNearFieldTargetPrivateImpl::handleTargetLost()
{
releaseIntent();
- emit targetLost(this);
+ Q_EMIT targetLost(this);
}
-QAndroidJniObject NearFieldTarget::getTagTechnology(const QString &tech) const
+QJniObject QNearFieldTargetPrivateImpl::getTagTechnology(const QString &tech) const
{
QString techClass(tech);
techClass.replace(QLatin1Char('.'), QLatin1Char('/'));
// Getting requested technology
- QAndroidJniObject tag = AndroidNfc::getTag(m_intent);
+ QJniObject tag = QtNfc::getTag(targetIntent);
Q_ASSERT_X(tag.isValid(), "getTagTechnology", "could not get Tag object");
const QString sig = QString::fromUtf8("(Landroid/nfc/Tag;)L%1;");
- QAndroidJniObject tagTech = QAndroidJniObject::callStaticObjectMethod(techClass.toUtf8().constData(), "get",
+ QJniObject tagTech = QJniObject::callStaticObjectMethod(techClass.toUtf8().constData(), "get",
sig.arg(techClass).toUtf8().constData(), tag.object<jobject>());
return tagTech;
}
-bool NearFieldTarget::setTagTechnology(const QStringList &techList)
+bool QNearFieldTargetPrivateImpl::setTagTechnology(const QStringList &technologies)
{
- for (const QString &tech : techList) {
- if (m_techList.contains(tech)) {
- if (m_tech == tech) {
+ for (const QString &tech : technologies) {
+ if (techList.contains(tech)) {
+ if (selectedTech == tech) {
return true;
}
- m_tech = tech;
- m_tagTech = getTagTechnology(tech);
- return m_tagTech.isValid();
+ selectedTech = tech;
+ tagTech = getTagTechnology(tech);
+ return tagTech.isValid();
}
}
return false;
}
-bool NearFieldTarget::connect()
+bool QNearFieldTargetPrivateImpl::connect()
{
- if (!m_tagTech.isValid())
+ if (!tagTech.isValid())
return false;
- bool connected = m_tagTech.callMethod<jboolean>("isConnected");
- if (catchJavaExceptions())
+ QJniEnvironment env;
+ auto methodId = env.findMethod<jboolean>(tagTech.objectClass(), "isConnected");
+ bool connected = false;
+ if (methodId)
+ connected = env->CallBooleanMethod(tagTech.object(), methodId);
+ if (!methodId || env.checkAndClearExceptions())
return false;
if (connected)
return true;
- m_tagTech.callMethod<void>("connect");
- return !catchJavaExceptions();
+ setCommandTimeout(2000);
+ methodId = env.findMethod<void>(tagTech.objectClass(), "connect");
+ if (!methodId)
+ return false;
+ env->CallVoidMethod(tagTech.object(), methodId);
+ return !env.checkAndClearExceptions();
}
-QByteArray NearFieldTarget::jbyteArrayToQByteArray(const jbyteArray &byteArray) const
+bool QNearFieldTargetPrivateImpl::setCommandTimeout(int timeout)
{
- QAndroidJniEnvironment env;
+ if (!tagTech.isValid())
+ return false;
+
+ QJniEnvironment env;
+ auto methodId = env.findMethod<void, jint>(tagTech.objectClass(), "setTimeout");
+ if (methodId)
+ env->CallVoidMethod(tagTech.object(), methodId, timeout);
+ return methodId && !env.checkAndClearExceptions();
+}
+
+QByteArray QNearFieldTargetPrivateImpl::jbyteArrayToQByteArray(const jbyteArray &byteArray) const
+{
+ QJniEnvironment env;
QByteArray resultArray;
jsize len = env->GetArrayLength(byteArray);
resultArray.resize(len);
env->GetByteArrayRegion(byteArray, 0, len, reinterpret_cast<jbyte*>(resultArray.data()));
return resultArray;
}
-
-bool NearFieldTarget::catchJavaExceptions(bool verbose) const
-{
- QAndroidJniEnvironment env;
- if (env->ExceptionCheck()) {
- if (verbose)
- env->ExceptionDescribe();
- env->ExceptionClear();
- return true;
- }
- return false;
-}
diff --git a/src/nfc/qnearfieldtarget_android_p.cpp b/src/nfc/qnearfieldtarget_android_p.cpp
deleted file mode 100644
index de553ea9..00000000
--- a/src/nfc/qnearfieldtarget_android_p.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Governikus GmbH & Co. KG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 <QCoreApplication>
-
-#include "qnearfieldtarget_p.h"
-#include "qnearfieldtarget_android_p.h"
-
-QT_BEGIN_NAMESPACE
-
-bool QNearFieldTargetPrivate::keepConnection() const
-{
- NEARFIELDTARGET_Q();
- return q->keepConnection();
-}
-
-bool QNearFieldTargetPrivate::setKeepConnection(bool isPersistent)
-{
- NEARFIELDTARGET_Q();
- return q->setKeepConnection(isPersistent);
-}
-
-bool QNearFieldTargetPrivate::disconnect()
-{
- NEARFIELDTARGET_Q();
- return q->disconnect();
-}
-
-int QNearFieldTargetPrivate::maxCommandLength() const
-{
- NEARFIELDTARGET_Q();
- return q->maxCommandLength();
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldtarget_android_p.h b/src/nfc/qnearfieldtarget_android_p.h
index 0063e9a5..bdfe6b19 100644
--- a/src/nfc/qnearfieldtarget_android_p.h
+++ b/src/nfc/qnearfieldtarget_android_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Centria research and development
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 Centria research and development
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNEARFIELDTARGET_ANDROID_P_H
#define QNEARFIELDTARGET_ANDROID_P_H
@@ -52,43 +16,44 @@
//
#include "android/androidjninfc_p.h"
-#include "qnearfieldtarget.h"
#include "qnearfieldtarget_p.h"
#include "qndefmessage.h"
#include "qlist.h"
#include "qstringlist.h"
#include <QTimer>
-#include <QtAndroidExtras/QAndroidJniObject>
-#include <QtAndroidExtras/QAndroidJniEnvironment>
+#include <QtCore/QJniObject>
+#include <QtCore/QJniEnvironment>
QT_BEGIN_NAMESPACE
-class NearFieldTarget : public QNearFieldTarget
+class QNearFieldTargetPrivateImpl : public QNearFieldTargetPrivate
{
Q_OBJECT
public:
- NearFieldTarget(QAndroidJniObject intent,
- const QByteArray uid,
- QObject *parent = 0);
- virtual ~NearFieldTarget();
- virtual QByteArray uid() const;
- virtual Type type() const;
- virtual AccessMethods accessMethods() const;
- bool keepConnection() const;
- bool setKeepConnection(bool isPersistent);
- bool disconnect();
- virtual bool hasNdefMessage();
- virtual RequestId readNdefMessages();
- int maxCommandLength() const;
- virtual RequestId sendCommand(const QByteArray &command);
- virtual RequestId sendCommands(const QList<QByteArray> &commands);
- virtual RequestId writeNdefMessages(const QList<QNdefMessage> &messages);
- void setIntent(QAndroidJniObject intent);
+ QNearFieldTargetPrivateImpl(QJniObject intent,
+ const QByteArray uid,
+ QObject *parent = nullptr);
+ ~QNearFieldTargetPrivateImpl() override;
+
+ QByteArray uid() const override;
+ QNearFieldTarget::Type type() const override;
+ QNearFieldTarget::AccessMethods accessMethods() const override;
+
+ bool disconnect() override;
+
+ bool hasNdefMessage() override;
+ QNearFieldTarget::RequestId readNdefMessages() override;
+ QNearFieldTarget::RequestId writeNdefMessages(const QList<QNdefMessage> &messages) override;
+
+ int maxCommandLength() const override;
+ QNearFieldTarget::RequestId sendCommand(const QByteArray &command) override;
+
+ void setIntent(QJniObject intent);
signals:
void targetDestroyed(const QByteArray &tagId);
- void targetLost(QNearFieldTarget *target);
+ void targetLost(QNearFieldTargetPrivateImpl *target);
void ndefMessageRead(const QNdefMessage &message, const QNearFieldTarget::RequestId &id);
protected slots:
@@ -98,24 +63,24 @@ protected:
void releaseIntent();
void updateTechList();
void updateType();
- Type getTagType() const;
+ QNearFieldTarget::Type getTagType() const;
void setupTargetCheckTimer();
void handleTargetLost();
- QAndroidJniObject getTagTechnology(const QString &tech) const;
- bool setTagTechnology(const QStringList &techList);
+ QJniObject getTagTechnology(const QString &tech) const;
+ bool setTagTechnology(const QStringList &technologies);
bool connect();
+ bool setCommandTimeout(int timeout);
QByteArray jbyteArrayToQByteArray(const jbyteArray &byteArray) const;
- bool catchJavaExceptions(bool verbose = true) const;
protected:
- QAndroidJniObject m_intent;
- QByteArray m_uid;
- QStringList m_techList;
- Type m_type;
- QTimer *m_targetCheckTimer;
- QString m_tech;
- QAndroidJniObject m_tagTech;
- bool m_keepConnection;
+ QJniObject targetIntent;
+ QByteArray targetUid;
+ QTimer *targetCheckTimer;
+
+ QString selectedTech;
+ QStringList techList;
+ QNearFieldTarget::Type tagType;
+ QJniObject tagTech;
};
QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldtarget_emulator.cpp b/src/nfc/qnearfieldtarget_emulator.cpp
deleted file mode 100644
index aecd743e..00000000
--- a/src/nfc/qnearfieldtarget_emulator.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qnearfieldtarget_emulator_p.h"
-#include "qnearfieldtarget_p.h"
-
-#include <QtCore/QByteArray>
-#include <QtCore/QCoreApplication>
-#include <QtCore/QDateTime>
-#include <QtCore/QDirIterator>
-#include <QtCore/QMutex>
-#include <QtCore/QSettings>
-
-QT_BEGIN_NAMESPACE
-
-static QMutex tagMutex;
-static QMap<TagBase *, bool> tagMap;
-
-Q_GLOBAL_STATIC(TagActivator, globalTagActivator);
-
-TagType1::TagType1(TagBase *tag, QObject *parent)
-: QNearFieldTagType1(parent), m_tag(tag)
-{
-}
-
-TagType1::~TagType1()
-{
-}
-
-QByteArray TagType1::uid() const
-{
- QMutexLocker locker(&tagMutex);
-
- return m_tag->uid();
-}
-
-QNearFieldTarget::AccessMethods TagType1::accessMethods() const
-{
- return NdefAccess | TagTypeSpecificAccess;
-}
-
-QNearFieldTarget::RequestId TagType1::sendCommand(const QByteArray &command)
-{
- QMutexLocker locker(&tagMutex);
-
- RequestId id(new RequestIdPrivate);
-
- // tag not in proximity
- if (!tagMap.value(m_tag)) {
- reportError(QNearFieldTarget::TargetOutOfRangeError, id);
- return id;
- }
-
- quint16 crc = qChecksum(command.constData(), command.length(), Qt::ChecksumItuV41);
-
- QByteArray response = m_tag->processCommand(command + char(crc & 0xff) + char(crc >> 8));
-
- if (response.isEmpty()) {
- reportError(QNearFieldTarget::NoResponseError, id);
- return id;
- }
-
- // check crc
- if (qChecksum(response.constData(), response.length(), Qt::ChecksumItuV41) != 0) {
- reportError(QNearFieldTarget::ChecksumMismatchError, id);
- return id;
- }
-
- response.chop(2);
-
- QMetaObject::invokeMethod(this, "handleResponse", Qt::QueuedConnection,
- Q_ARG(QNearFieldTarget::RequestId, id), Q_ARG(QByteArray, response));
-
- return id;
-}
-
-bool TagType1::waitForRequestCompleted(const RequestId &id, int msecs)
-{
- QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
-
- return QNearFieldTagType1::waitForRequestCompleted(id, msecs);
-}
-
-
-TagType2::TagType2(TagBase *tag, QObject *parent)
-: QNearFieldTagType2(parent), m_tag(tag)
-{
-}
-
-TagType2::~TagType2()
-{
-}
-
-QByteArray TagType2::uid() const
-{
- QMutexLocker locker(&tagMutex);
-
- return m_tag->uid();
-}
-
-QNearFieldTarget::AccessMethods TagType2::accessMethods() const
-{
- return NdefAccess | TagTypeSpecificAccess;
-}
-
-QNearFieldTarget::RequestId TagType2::sendCommand(const QByteArray &command)
-{
- QMutexLocker locker(&tagMutex);
-
- RequestId id(new RequestIdPrivate);
-
- // tag not in proximity
- if (!tagMap.value(m_tag)) {
- reportError(QNearFieldTarget::TargetOutOfRangeError, id);
- return id;
- }
-
- quint16 crc = qChecksum(command.constData(), command.length(), Qt::ChecksumItuV41);
-
- QByteArray response = m_tag->processCommand(command + char(crc & 0xff) + char(crc >> 8));
-
- if (response.isEmpty())
- return id;
-
- if (response.length() > 1) {
- // check crc
- if (qChecksum(response.constData(), response.length(), Qt::ChecksumItuV41) != 0) {
- reportError(QNearFieldTarget::ChecksumMismatchError, id);
- return id;
- }
-
- response.chop(2);
- }
-
- QMetaObject::invokeMethod(this, "handleResponse", Qt::QueuedConnection,
- Q_ARG(QNearFieldTarget::RequestId, id), Q_ARG(QByteArray, response));
-
- return id;
-}
-
-bool TagType2::waitForRequestCompleted(const RequestId &id, int msecs)
-{
- QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
-
- return QNearFieldTagType2::waitForRequestCompleted(id, msecs);
-}
-
-
-TagActivator::TagActivator()
-: timerId(-1)
-{
- qRegisterMetaType<QNearFieldTarget::Error>();
-}
-
-TagActivator::~TagActivator()
-{
- QMutexLocker locker(&tagMutex);
- qDeleteAll(tagMap.keys());
- tagMap.clear();
-}
-
-void TagActivator::initialize()
-{
- QMutexLocker locker(&tagMutex);
-
- if (!tagMap.isEmpty())
- return;
-
-#ifndef BUILTIN_TESTDATA
- QDirIterator nfcTargets(QDir::currentPath(), QStringList(QStringLiteral("*.nfc")), QDir::Files);
-#else
- QDirIterator nfcTargets(":/nfcdata", QStringList(QStringLiteral("*.nfc")), QDir::Files);
-#endif
- while (nfcTargets.hasNext()) {
- const QString targetFilename = nfcTargets.next();
-
- QSettings target(targetFilename, QSettings::IniFormat);
-
- target.beginGroup(QStringLiteral("Target"));
-
- const QString tagType = target.value(QStringLiteral("Type")).toString();
-
- target.endGroup();
-
- if (tagType == QLatin1String("TagType1")) {
- NfcTagType1 *tag = new NfcTagType1;
- tag->load(&target);
-
- tagMap.insert(tag, false);
- } else if (tagType == QLatin1String("TagType2")) {
- NfcTagType2 *tag = new NfcTagType2;
- tag->load(&target);
-
- tagMap.insert(tag, false);
- } else {
- qWarning("Unknown tag type %s\n", qPrintable(tagType));
- }
- }
-
- m_current = tagMap.end();
-
- timerId = startTimer(1000);
-}
-
-void TagActivator::reset()
-{
- QMutexLocker locker(&tagMutex);
-
- killTimer(timerId);
- timerId = -1;
-
- qDeleteAll(tagMap.keys());
- tagMap.clear();
-}
-
-TagActivator *TagActivator::instance()
-{
- return globalTagActivator();
-}
-
-void TagActivator::timerEvent(QTimerEvent *e)
-{
- Q_UNUSED(e);
-
- tagMutex.lock();
-
- if (m_current != tagMap.end()) {
- if (m_current.key()->lastAccessTime() + 1500 > QDateTime::currentMSecsSinceEpoch()) {
- tagMutex.unlock();
- return;
- }
-
- *m_current = false;
-
- TagBase *tag = m_current.key();
-
- tagMutex.unlock();
- emit tagDeactivated(tag);
- tagMutex.lock();
- }
-
- if (m_current != tagMap.end())
- ++m_current;
-
- if (m_current == tagMap.end())
- m_current = tagMap.begin();
-
- if (m_current != tagMap.end()) {
- *m_current = true;
-
- TagBase *tag = m_current.key();
-
- tagMutex.unlock();
- emit tagActivated(tag);
- tagMutex.lock();
- }
-
- tagMutex.unlock();
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldtarget_emulator_p.h b/src/nfc/qnearfieldtarget_emulator_p.h
deleted file mode 100644
index 70a67be8..00000000
--- a/src/nfc/qnearfieldtarget_emulator_p.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QNEARFIELDTARGET_EMULATOR_P_H
-#define QNEARFIELDTARGET_EMULATOR_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 "qnearfieldtagtype1_p.h"
-#include "qnearfieldtagtype2_p.h"
-#include "targetemulator_p.h"
-
-#include <QtCore/QMap>
-
-QT_BEGIN_NAMESPACE
-
-class TagType1 : public QNearFieldTagType1
-{
- Q_OBJECT
-
-public:
- TagType1(TagBase *tag, QObject *parent);
- ~TagType1();
-
- QByteArray uid() const;
-
- AccessMethods accessMethods() const;
-
- RequestId sendCommand(const QByteArray &command);
- bool waitForRequestCompleted(const RequestId &id, int msecs = 5000);
-
-private:
- TagBase *m_tag;
-};
-
-class TagType2 : public QNearFieldTagType2
-{
- Q_OBJECT
-
-public:
- TagType2(TagBase *tag, QObject *parent);
- ~TagType2();
-
- QByteArray uid() const;
-
- AccessMethods accessMethods() const;
-
- RequestId sendCommand(const QByteArray &command);
- bool waitForRequestCompleted(const RequestId &id, int msecs = 5000);
-
-private:
- TagBase *m_tag;
-};
-
-class TagActivator : public QObject
-{
- Q_OBJECT
-
-public:
- TagActivator();
- ~TagActivator();
-
- void initialize();
- void reset();
-
- static TagActivator *instance();
-
-protected:
- void timerEvent(QTimerEvent *e);
-
-signals:
- void tagActivated(TagBase *tag);
- void tagDeactivated(TagBase *tag);
-
-private:
- QMap<TagBase *, bool>::Iterator m_current;
- int timerId;
-};
-
-QT_END_NAMESPACE
-
-#endif // QNEARFIELDTARGET_EMULATOR_P_H
diff --git a/src/nfc/qnearfieldtarget_ios.mm b/src/nfc/qnearfieldtarget_ios.mm
new file mode 100644
index 00000000..b058ad75
--- /dev/null
+++ b/src/nfc/qnearfieldtarget_ios.mm
@@ -0,0 +1,467 @@
+// Copyright (C) 2020 Governikus GmbH & Co. KG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "ios/qiosnfcndefsessiondelegate_p.h"
+#include "ios/qiosndefnotifier_p.h"
+
+#include "qnearfieldtarget_ios_p.h"
+
+#import <CoreNFC/NFCNDEFReaderSession.h>
+#import <CoreNFC/NFCReaderSession.h>
+#import <CoreNFC/NFCTagReaderSession.h>
+#import <CoreNFC/NFCISO7816Tag.h>
+#import <CoreNFC/NFCTag.h>
+
+#include <QtCore/qapplicationstatic.h>
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_APPLICATION_STATIC(ResponseProvider, responseProvider)
+
+void ResponseProvider::provideResponse(QNearFieldTarget::RequestId requestId, bool success, QByteArray recvBuffer) {
+ Q_EMIT responseReceived(requestId, success, recvBuffer);
+}
+
+void NfcDeleter::operator()(void *obj)
+{
+ id some = static_cast<id>(obj);
+
+ if ([some conformsToProtocol:@protocol(NFCNDEFTag)])
+ [static_cast<id<NFCNDEFTag>>(some) release];
+ else if ([some conformsToProtocol:@protocol(NFCTag)])
+ [static_cast<id<NFCTag>>(some) release];
+ else
+ Q_UNREACHABLE();
+}
+
+QNearFieldTargetPrivateImpl:: QNearFieldTargetPrivateImpl(void *tag, QObject *parent) :
+ QNearFieldTargetPrivate(parent),
+ nfcTag(tag)
+{
+ Q_ASSERT(nfcTag);
+
+ QObject::connect(this, &QNearFieldTargetPrivate::error, this, &QNearFieldTargetPrivateImpl::onTargetError);
+ QObject::connect(responseProvider, &ResponseProvider::responseReceived, this, &QNearFieldTargetPrivateImpl::onResponseReceived);
+ QObject::connect(&targetCheckTimer, &QTimer::timeout, this, &QNearFieldTargetPrivateImpl::onTargetCheck);
+ targetCheckTimer.start(500);
+}
+
+QNearFieldTargetPrivateImpl:: QNearFieldTargetPrivateImpl(void *delegate, void *tag, QObject *parent) :
+ QNearFieldTargetPrivate(parent),
+ nfcTag(tag)
+{
+ Q_ASSERT(delegate && tag);
+ Q_ASSERT([id(tag) conformsToProtocol:@protocol(NFCNDEFTag)]);
+
+ auto qtDelegate = static_cast<QIosNfcNdefSessionDelegate *>(sessionDelegate = delegate);
+ notifier = [qtDelegate ndefNotifier];
+ Q_ASSERT(notifier);
+
+ // The 'notifier' lives on a (potentially different, unspecified) thread,
+ // thus connection is 'queued'.
+ QObject::connect(notifier, &QNfcNdefNotifier::tagError, this,
+ &QNearFieldTargetPrivate::error, Qt::QueuedConnection);
+
+ QObject::connect(this, &QNearFieldTargetPrivate::error, this, &QNearFieldTargetPrivateImpl::onTargetError);
+ QObject::connect(&targetCheckTimer, &QTimer::timeout, this, &QNearFieldTargetPrivateImpl::onTargetCheck);
+
+ targetCheckTimer.start(500);
+}
+
+QNearFieldTargetPrivateImpl::~QNearFieldTargetPrivateImpl()
+{
+}
+
+void QNearFieldTargetPrivateImpl::invalidate()
+{
+ queue.clear();
+ ndefOperations.clear();
+
+ if (isNdefTag()) {
+ Q_ASSERT(notifier);
+
+ QObject::disconnect(notifier, nullptr, this, nullptr);
+ notifier = nullptr;
+ }
+
+ nfcTag.reset();
+ sessionDelegate = nil;
+
+ targetCheckTimer.stop();
+
+ QMetaObject::invokeMethod(this, [this]() {
+ Q_EMIT targetLost(this);
+ }, Qt::QueuedConnection);
+}
+
+QByteArray QNearFieldTargetPrivateImpl::uid() const
+{
+ if (!nfcTag || isNdefTag()) // NFCNDEFTag does not have this information ...
+ return {};
+
+ if (@available(iOS 13, *)) {
+ id<NFCTag> tag = static_cast<id<NFCTag>>(nfcTag.get());
+ id<NFCISO7816Tag> iso7816Tag = tag.asNFCISO7816Tag;
+ if (iso7816Tag)
+ return QByteArray::fromNSData(iso7816Tag.identifier);
+ }
+
+ return {};
+}
+
+QNearFieldTarget::Type QNearFieldTargetPrivateImpl::type() const
+{
+ if (!nfcTag || isNdefTag()) // No information provided by NFCNDEFTag.
+ return QNearFieldTarget::ProprietaryTag;
+
+ if (@available(iOS 13, *)) {
+ id<NFCTag> tag = static_cast<id<NFCTag>>(nfcTag.get());
+ id<NFCISO7816Tag> iso7816Tag = tag.asNFCISO7816Tag;
+
+ if (tag.type != NFCTagTypeISO7816Compatible || iso7816Tag == nil)
+ return QNearFieldTarget::ProprietaryTag;
+
+ if (iso7816Tag.historicalBytes != nil && iso7816Tag.applicationData == nil)
+ return QNearFieldTarget::NfcTagType4A;
+
+ if (iso7816Tag.historicalBytes == nil && iso7816Tag.applicationData != nil)
+ return QNearFieldTarget::NfcTagType4B;
+
+ return QNearFieldTarget::NfcTagType4;
+ }
+
+ return QNearFieldTarget::ProprietaryTag;
+}
+
+QNearFieldTarget::AccessMethods QNearFieldTargetPrivateImpl::accessMethods() const
+{
+ if (isNdefTag())
+ return QNearFieldTarget::NdefAccess;
+
+ if (@available(iOS 13, *)) {
+ id<NFCTag> tag = static_cast<id<NFCTag>>(nfcTag.get());
+ if (tag && [tag conformsToProtocol:@protocol(NFCISO7816Tag)])
+ return QNearFieldTarget::TagTypeSpecificAccess;
+ }
+
+ return QNearFieldTarget::UnknownAccess;
+}
+
+int QNearFieldTargetPrivateImpl::maxCommandLength() const
+{
+ if (accessMethods() & QNearFieldTarget::TagTypeSpecificAccess)
+ return 0xFEFF;
+
+ // TODO: check if 'capacity' of NFCNDEFTag can be used?
+ return 0;
+}
+
+QNearFieldTarget::RequestId QNearFieldTargetPrivateImpl::sendCommand(const QByteArray &command)
+{
+ QNearFieldTarget::RequestId requestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate());
+
+ if (!(accessMethods() & QNearFieldTarget::TagTypeSpecificAccess)) {
+ reportError(QNearFieldTarget::UnsupportedError, requestId);
+ return requestId;
+ }
+
+ queue.enqueue(std::pair(requestId, command));
+
+ if (!connect()) {
+ reportError(QNearFieldTarget::TargetOutOfRangeError, requestId);
+ return requestId;
+ }
+
+ onExecuteRequest();
+ return requestId;
+}
+
+bool QNearFieldTargetPrivateImpl::hasNdefMessage()
+{
+ return hasNDEFMessage;
+}
+
+QNearFieldTarget::RequestId QNearFieldTargetPrivateImpl::readNdefMessages()
+{
+ hasNDEFMessage = false;
+
+ QNearFieldTarget::RequestId requestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate);
+
+ if (!(accessMethods() & QNearFieldTarget::NdefAccess) || !isNdefTag()) {
+ qCWarning(QT_IOS_NFC, "Target does not allow to read NDEF messages, "
+ "was not detected as NDEF tag by the reader session?");
+ reportError(QNearFieldTarget::UnsupportedError, requestId);
+ return requestId;
+ }
+
+ NdefOperation op;
+ op.type = NdefOperation::Read;
+ op.requestId = requestId;
+
+ ndefOperations.push_back(op);
+ onExecuteRequest();
+
+ return requestId;
+}
+
+QNearFieldTarget::RequestId QNearFieldTargetPrivateImpl::writeNdefMessages(const QList<QNdefMessage> &messages)
+{
+ auto requestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate);
+
+ if (!(accessMethods() & QNearFieldTarget::NdefAccess) || !isNdefTag()) {
+ qCWarning(QT_IOS_NFC, "Target does not allow to write NDEF messages, "
+ "was not detected as NDEF tag by the reader session?");
+ reportError(QNearFieldTarget::UnsupportedError, requestId);
+ return requestId;
+ }
+
+ if (messages.size() != 1) {
+ // The native framework does not allow to write 'messages', only _one_ message
+ // at a time. Not to multiply the complexity of having 'ndefOperations' queue
+ // with some queue inside the delegate's code (plus some unpredictable errors
+ // handling) - require a single message as a single request.
+ qCWarning(QT_IOS_NFC, "Only one NDEF message per request ID can be written");
+ return requestId;
+ }
+
+ NdefOperation op;
+ op.type = NdefOperation::Write;
+ op.requestId = requestId;
+ op.message = messages.first();
+
+ ndefOperations.push_back(op);
+ onExecuteRequest();
+
+ return requestId;
+}
+
+bool QNearFieldTargetPrivateImpl::isAvailable() const
+{
+ if (requestInProgress.isValid())
+ return true;
+
+ const auto tagIsAvailable = [this](auto tag) {
+ return tag && (!connected || tag.available);
+ };
+
+ if (isNdefTag())
+ return tagIsAvailable(static_cast<id<NFCNDEFTag>>(nfcTag.get()));
+
+ if (@available(iOS 13, *))
+ return tagIsAvailable(static_cast<id<NFCTag>>(nfcTag.get()));
+
+ return false;
+}
+
+bool QNearFieldTargetPrivateImpl::connect()
+{
+ if (connected || requestInProgress.isValid())
+ return true;
+
+ if (isNdefTag())
+ return connected = true;
+
+ if (!isAvailable() || queue.isEmpty())
+ return false;
+
+ if (@available(iOS 13, *)) {
+ requestInProgress = queue.head().first;
+ id<NFCTag> tag = static_cast<id<NFCTag>>(nfcTag.get());
+ NFCTagReaderSession* session = tag.session;
+ [session connectToTag: tag completionHandler: ^(NSError* error){
+ const bool success = error == nil;
+ QMetaObject::invokeMethod(this, [this, success] {
+ requestInProgress = QNearFieldTarget::RequestId();
+ if (success) {
+ connected = true;
+ onExecuteRequest();
+ } else {
+ const auto requestId = queue.dequeue().first;
+ reportError(QNearFieldTarget::ConnectionError, requestId);
+ invalidate();
+ }
+ });
+ }];
+ return true;
+ }
+
+ return false;
+}
+
+bool QNearFieldTargetPrivateImpl::isNdefTag() const
+{
+ const id tag = static_cast<id>(nfcTag.get());
+ if ([tag conformsToProtocol:@protocol(NFCMiFareTag)])
+ return false;
+ if ([tag conformsToProtocol:@protocol(NFCFeliCaTag)])
+ return false;
+ if ([tag conformsToProtocol:@protocol(NFCISO15693Tag)])
+ return false;
+ if ([tag conformsToProtocol:@protocol(NFCISO7816Tag)])
+ return false;
+ return [tag conformsToProtocol:@protocol(NFCNDEFTag)];
+}
+
+void QNearFieldTargetPrivateImpl::onTargetCheck()
+{
+ if (!isAvailable())
+ invalidate();
+}
+
+void QNearFieldTargetPrivateImpl::onTargetError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id)
+{
+ Q_UNUSED(id);
+
+ if (error == QNearFieldTarget::TimeoutError)
+ invalidate();
+}
+
+namespace {
+
+QNdefMessage ndefToQtNdefMessage(NFCNDEFMessage *nativeMessage)
+{
+ if (!nativeMessage)
+ return {};
+
+ QList<QNdefRecord> ndefRecords;
+ for (NFCNDEFPayload *ndefRecord in nativeMessage.records) {
+ QNdefRecord qtNdefRecord;
+ if (ndefRecord.typeNameFormat != NFCTypeNameFormatUnchanged) // Does not match anything in Qt.
+ qtNdefRecord.setTypeNameFormat(QNdefRecord::TypeNameFormat(ndefRecord.typeNameFormat));
+ if (ndefRecord.identifier)
+ qtNdefRecord.setId(QByteArray::fromNSData(ndefRecord.identifier));
+ if (ndefRecord.type)
+ qtNdefRecord.setType(QByteArray::fromNSData(ndefRecord.type));
+ if (ndefRecord.payload)
+ qtNdefRecord.setPayload(QByteArray::fromNSData(ndefRecord.payload));
+ ndefRecords.push_back(qtNdefRecord);
+ }
+
+ return QNdefMessage{ndefRecords};
+}
+
+} // Unnamed namespace.
+
+void QNearFieldTargetPrivateImpl::onExecuteRequest()
+{
+ if (!nfcTag || requestInProgress.isValid())
+ return;
+
+ if (isNdefTag()) {
+ if (ndefOperations.empty())
+ return;
+
+ auto *ndefDelegate = static_cast<QIosNfcNdefSessionDelegate *>(sessionDelegate);
+ Q_ASSERT(ndefDelegate);
+
+ Q_ASSERT(qt_Nfc_Queue()); // This is where callbacks get called.
+
+ const auto op = ndefOperations.front();
+ ndefOperations.pop_front();
+ requestInProgress = op.requestId;
+ auto requestId = requestInProgress; // Copy so we capture by value in the block.
+
+ id<NFCNDEFTag> ndefTag = static_cast<id<NFCNDEFTag>>(nfcTag.get());
+
+ std::unique_ptr<QNfcNdefNotifier> guard(new QNfcNdefNotifier);
+ auto *cbNotifier = guard.get();
+
+ QObject::connect(cbNotifier, &QNfcNdefNotifier::tagError, this,
+ &QNearFieldTargetPrivate::error, Qt::QueuedConnection);
+
+ if (op.type == NdefOperation::Read) {
+ QObject::connect(cbNotifier, &QNfcNdefNotifier::ndefMessageRead,
+ this, &QNearFieldTargetPrivateImpl::messageRead,
+ Qt::QueuedConnection);
+
+ // We call it here, but the callback will be executed on an unspecified thread.
+ [ndefTag readNDEFWithCompletionHandler:^(NFCNDEFMessage * _Nullable msg, NSError * _Nullable err) {
+ const std::unique_ptr<QNfcNdefNotifier> notifierGuard(cbNotifier);
+ if (err) {
+ NSLog(@"Reading NDEF messaged ended with error: %@", err);
+ emit cbNotifier->tagError(QNearFieldTarget::NdefReadError, requestId);
+ return;
+ }
+
+ const QNdefMessage ndefMessage(ndefToQtNdefMessage(msg));
+ emit cbNotifier->ndefMessageRead(ndefMessage, requestId);
+ }];
+ } else {
+ QObject::connect(cbNotifier, &QNfcNdefNotifier::ndefMessageWritten,
+ this, &QNearFieldTargetPrivateImpl::messageWritten,
+ Qt::QueuedConnection);
+
+ NSData *ndefData = op.message.toByteArray().toNSData(); // autoreleased.
+ Q_ASSERT(ndefData);
+
+ NFCNDEFMessage *ndefMessage = [NFCNDEFMessage ndefMessageWithData:ndefData]; // autoreleased.
+ Q_ASSERT(ndefMessage);
+
+ [ndefTag writeNDEF:ndefMessage completionHandler:^(NSError *err) {
+ const std::unique_ptr<QNfcNdefNotifier> notifierGuard(cbNotifier);
+ if (err) {
+ NSLog(@"Writing NDEF messaged ended with error: %@", err);
+ emit cbNotifier->tagError(QNearFieldTarget::NdefWriteError, requestId);
+ return;
+ }
+
+ emit cbNotifier->ndefMessageWritten(requestId);
+ }];
+ }
+ guard.release(); // Owned by the completion handler now.
+ return;
+ }
+
+ if (@available(iOS 13, *)) {
+ if (queue.isEmpty())
+ return;
+ const auto request = queue.dequeue();
+ requestInProgress = request.first;
+ const auto tag = static_cast<id<NFCISO7816Tag>>(nfcTag.get());
+ auto *apdu = [[[NFCISO7816APDU alloc] initWithData: request.second.toNSData()] autorelease];
+ [tag sendCommandAPDU: apdu completionHandler: ^(NSData* responseData, uint8_t sw1, uint8_t sw2, NSError* error){
+ QByteArray recvBuffer = QByteArray::fromNSData(responseData);
+ recvBuffer += static_cast<char>(sw1);
+ recvBuffer += static_cast<char>(sw2);
+ const bool success = error == nil;
+ responseProvider->provideResponse(request.first, success, recvBuffer);
+ }];
+ }
+}
+
+void QNearFieldTargetPrivateImpl::onResponseReceived(QNearFieldTarget::RequestId requestId, bool success, QByteArray recvBuffer)
+{
+ if (requestInProgress != requestId)
+ return;
+
+ requestInProgress = QNearFieldTarget::RequestId();
+ if (success) {
+ setResponseForRequest(requestId, recvBuffer, true);
+ onExecuteRequest();
+ } else {
+ reportError(QNearFieldTarget::CommandError, requestId);
+ invalidate();
+ }
+}
+
+void QNearFieldTargetPrivateImpl::messageRead(const QNdefMessage &message, QNearFieldTarget::RequestId requestId)
+{
+ hasNDEFMessage = message.size() != 0;
+
+ setResponseForRequest(requestId, message.toByteArray(), true);
+ requestInProgress = {}; // Invalidating, so we can execute the next one.
+ onExecuteRequest();
+
+ Q_EMIT ndefMessageRead(message);
+}
+
+void QNearFieldTargetPrivateImpl::messageWritten(QNearFieldTarget::RequestId requestId)
+{
+ requestInProgress = {}; // Invalidating, so we can execute the next one.
+ onExecuteRequest();
+
+ Q_EMIT requestCompleted(requestId);
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldtarget_ios_p.h b/src/nfc/qnearfieldtarget_ios_p.h
new file mode 100644
index 00000000..c0cde0b6
--- /dev/null
+++ b/src/nfc/qnearfieldtarget_ios_p.h
@@ -0,0 +1,119 @@
+// Copyright (C) 2020 Governikus GmbH & Co. KG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNEARFIELDTARGET_IOS_P_H
+#define QNEARFIELDTARGET_IOS_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 "qnearfieldtarget_p.h"
+#include "qnearfieldtarget.h"
+
+#include "qndefmessage.h"
+
+#include <QQueue>
+#include <QTimer>
+
+#include <memory>
+#include <deque>
+
+QT_BEGIN_NAMESPACE
+
+class ResponseProvider : public QObject
+{
+ Q_OBJECT
+
+ public:
+ void provideResponse(QNearFieldTarget::RequestId requestId, bool success, QByteArray recvBuffer);
+
+ Q_SIGNALS:
+ void responseReceived(QNearFieldTarget::RequestId requestId, bool success, QByteArray recvBuffer);
+};
+
+struct NfcDeleter
+{
+ void operator()(void *tag);
+};
+
+struct NdefOperation
+{
+ enum Type {
+ Read,
+ Write
+ } type = Read;
+
+ QNearFieldTarget::RequestId requestId;
+ QNdefMessage message;
+};
+
+class QNfcNdefNotifier;
+
+class QNearFieldTargetPrivateImpl : public QNearFieldTargetPrivate
+{
+ Q_OBJECT
+
+public:
+ QNearFieldTargetPrivateImpl(void *tag, QObject *parent = nullptr);
+ QNearFieldTargetPrivateImpl(void *sessionDelegate, void *tag, QObject *parent = nullptr);
+ ~QNearFieldTargetPrivateImpl() override;
+ void invalidate();
+
+ QByteArray uid() const override;
+ QNearFieldTarget::Type type() const override;
+ QNearFieldTarget::AccessMethods accessMethods() const override;
+
+ int maxCommandLength() const override;
+ QNearFieldTarget::RequestId sendCommand(const QByteArray &command) override;
+
+ // NdefAccess
+ bool hasNdefMessage() override;
+ QNearFieldTarget::RequestId readNdefMessages() override;
+ QNearFieldTarget::RequestId writeNdefMessages(const QList<QNdefMessage> &messages) override;
+
+
+ bool isAvailable() const;
+
+Q_SIGNALS:
+ void targetLost(QNearFieldTargetPrivateImpl *target);
+
+private:
+ std::unique_ptr<void, NfcDeleter> nfcTag;
+
+ // Owned by the near field manager.
+ void *sessionDelegate = nil;
+ // Owned by the session delegate.
+ QNfcNdefNotifier *notifier = nullptr;
+ bool hasNDEFMessage = false;
+
+ bool connected = false;
+ QTimer targetCheckTimer;
+ QNearFieldTarget::RequestId requestInProgress;
+ QQueue<std::pair<QNearFieldTarget::RequestId, QByteArray>> queue;
+ std::deque<NdefOperation> ndefOperations;
+
+ bool connect();
+
+ bool isNdefTag() const;
+
+private Q_SLOTS:
+ void onTargetCheck();
+ void onTargetError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id);
+ void onExecuteRequest();
+ void onResponseReceived(QNearFieldTarget::RequestId requestId, bool success, QByteArray recvBuffer);
+ // NDEF:
+ void messageRead(const QNdefMessage &ndefMessage, QNearFieldTarget::RequestId request);
+ void messageWritten(QNearFieldTarget::RequestId request);
+};
+
+QT_END_NAMESPACE
+
+#endif // QNEARFIELDTARGET_IOS_P_H
diff --git a/src/nfc/qnearfieldtarget_neard_p.cpp b/src/nfc/qnearfieldtarget_neard_p.cpp
index 4ed17a15..d6982030 100644
--- a/src/nfc/qnearfieldtarget_neard_p.cpp
+++ b/src/nfc/qnearfieldtarget_neard_p.cpp
@@ -1,68 +1,325 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Governikus GmbH & Co. K
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 <QCoreApplication>
-
-#include "qnearfieldtarget.h"
-#include "qnearfieldtarget_p.h"
+// Copyright (C) 2016 BlackBerry Limited, Copyright (C) 2016 BasysKom GmbH
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qnearfieldtarget_neard_p.h"
+
+#include <qndefnfctextrecord.h>
+#include <qndefnfcsmartposterrecord.h>
+#include <qndefnfcurirecord.h>
QT_BEGIN_NAMESPACE
-bool QNearFieldTargetPrivate::keepConnection() const
+Q_DECLARE_LOGGING_CATEGORY(QT_NFC_NEARD)
+
+QNearFieldTargetPrivateImpl::QNearFieldTargetPrivateImpl(QObject *parent, QDBusObjectPath interfacePath)
+ : QNearFieldTargetPrivate(parent),
+ m_tagPath(interfacePath),
+ m_readRequested(false)
+{
+ m_readErrorTimer.setSingleShot(true);
+ m_recordPathsCollectedTimer.setSingleShot(true);
+ m_delayedWriteTimer.setSingleShot(true);
+
+ qCDebug(QT_NFC_NEARD) << "tag found at path" << interfacePath.path();
+ m_dbusProperties = new OrgFreedesktopDBusPropertiesInterface(QStringLiteral("org.neard"),
+ interfacePath.path(), QDBusConnection::systemBus(), this);
+ if (!m_dbusProperties->isValid()) {
+ qCWarning(QT_NFC_NEARD) << "Could not connect to dbus property interface at path"
+ << interfacePath.path();
+ return;
+ }
+
+ QDBusPendingReply<QVariantMap> reply = m_dbusProperties->GetAll(QStringLiteral("org.neard.Tag"));
+ reply.waitForFinished();
+ if (reply.isError()) {
+ qCWarning(QT_NFC_NEARD) << "Could not get properties of org.neard.Tag dbus interface";
+ return;
+ }
+
+ const QString &type = reply.value().value(QStringLiteral("Type")).toString();
+ m_type = QNearFieldTarget::ProprietaryTag;
+
+ if (type == QStringLiteral("Type 1"))
+ m_type = QNearFieldTarget::NfcTagType1;
+ else if (type == QStringLiteral("Type 2"))
+ m_type = QNearFieldTarget::NfcTagType2;
+ else if (type == QStringLiteral("Type 3"))
+ m_type = QNearFieldTarget::NfcTagType3;
+ else if (type == QStringLiteral("Type 4"))
+ m_type = QNearFieldTarget::NfcTagType4;
+
+ qCDebug(QT_NFC_NEARD) << "tag type" << type;
+
+ connect(&m_recordPathsCollectedTimer, &QTimer::timeout,
+ this, &QNearFieldTargetPrivateImpl::createNdefMessage);
+ connect(&m_readErrorTimer, &QTimer::timeout,
+ this, &QNearFieldTargetPrivateImpl::handleReadError);
+ connect(&m_delayedWriteTimer, &QTimer::timeout,
+ this, &QNearFieldTargetPrivateImpl::handleWriteRequest);
+ connect(NeardHelper::instance(), &NeardHelper::recordFound,
+ this, &QNearFieldTargetPrivateImpl::handleRecordFound);
+}
+
+QNearFieldTargetPrivateImpl::~QNearFieldTargetPrivateImpl()
+{
+}
+
+bool QNearFieldTargetPrivateImpl::isValid()
+{
+ return m_dbusProperties->isValid() && NeardHelper::instance()->dbusObjectManager()->isValid();
+}
+
+QByteArray QNearFieldTargetPrivateImpl::uid() const
+{
+ return QByteArray(); // TODO figure out a workaround because neard does not offer
+ // this property
+}
+
+QNearFieldTarget::Type QNearFieldTargetPrivateImpl::type() const
+{
+ return m_type;
+}
+
+QNearFieldTarget::AccessMethods QNearFieldTargetPrivateImpl::accessMethods() const
+{
+ return QNearFieldTarget::NdefAccess;
+}
+
+bool QNearFieldTargetPrivateImpl::hasNdefMessage()
+{
+ return !m_recordPaths.isEmpty();
+}
+
+QNearFieldTarget::RequestId QNearFieldTargetPrivateImpl::readNdefMessages()
+{
+ if (isValid()) {
+ // if the user calls readNdefMessages before the previous request has been completed
+ // return the current request id.
+ if (m_currentReadRequestId.isValid())
+ return m_currentReadRequestId;
+
+ QNearFieldTarget::RequestId requestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate());
+ // save the id so it can be passed along with requestCompleted
+ m_currentReadRequestId = requestId;
+ // since the triggering of interfaceAdded will ultimately lead to createNdefMessage being called
+ // we need to make sure that ndefMessagesRead will only be triggered when readNdefMessages has
+ // been called before. In case readNdefMessages is called again after that we can directly call
+ // call createNdefMessage.
+ m_readRequested = true;
+ if (hasNdefMessage())
+ createNdefMessage();
+ else
+ m_readErrorTimer.start(1000);
+
+ return requestId;
+ } else {
+ return QNearFieldTarget::RequestId();
+ }
+}
+
+QNearFieldTarget::RequestId QNearFieldTargetPrivateImpl::sendCommand(const QByteArray &command)
+{
+ Q_UNUSED(command);
+ return QNearFieldTarget::RequestId();
+}
+
+QNearFieldTarget::RequestId QNearFieldTargetPrivateImpl::writeNdefMessages(const QList<QNdefMessage> &messages)
+{
+ // disabling write due to neard crash (see QTBUG-43802)
+ qWarning("QNearFieldTarget::WriteNdefMessages() disabled. See QTBUG-43802\n");
+ return QNearFieldTarget::RequestId();
+
+
+ // return old request id when previous write request hasn't completed
+ if (m_currentWriteRequestId.isValid())
+ return m_currentWriteRequestId;
+
+ qCDebug(QT_NFC_NEARD) << "writing messages";
+ if (messages.isEmpty() || messages.first().isEmpty()) {
+ qCWarning(QT_NFC_NEARD) << "No record specified";
+ return QNearFieldTarget::RequestId();
+ }
+ if (messages.count() > 1 || messages.first().count() > 1) {
+ // neard only supports one ndef record per tag
+ qCWarning(QT_NFC_NEARD) << "Writing of only one NDEF record and message is supported";
+ return QNearFieldTarget::RequestId();
+ }
+ QNdefRecord record = messages.first().first();
+
+ if (record.typeNameFormat() == QNdefRecord::NfcRtd) {
+ m_currentWriteRequestData.clear();
+ if (record.isRecordType<QNdefNfcUriRecord>()) {
+ m_currentWriteRequestData.insert(QStringLiteral("Type"), QStringLiteral("URI"));
+ QNdefNfcUriRecord uriRecord = static_cast<QNdefNfcUriRecord>(record);
+ m_currentWriteRequestData.insert(QStringLiteral("URI"), uriRecord.uri().toString());
+ } else if (record.isRecordType<QNdefNfcSmartPosterRecord>()) {
+ m_currentWriteRequestData.insert(QStringLiteral("Type"), QStringLiteral("SmartPoster"));
+ QNdefNfcSmartPosterRecord spRecord = static_cast<QNdefNfcSmartPosterRecord>(record);
+ m_currentWriteRequestData.insert(QStringLiteral("URI"), spRecord.uri().toString());
+ // Currently neard only supports the uri property for writing
+ } else if (record.isRecordType<QNdefNfcTextRecord>()) {
+ m_currentWriteRequestData.insert(QStringLiteral("Type"), QStringLiteral("Text"));
+ QNdefNfcTextRecord textRecord = static_cast<QNdefNfcTextRecord>(record);
+ m_currentWriteRequestData.insert(QStringLiteral("Representation"), textRecord.text());
+ m_currentWriteRequestData.insert(QStringLiteral("Encoding"),
+ textRecord.encoding() == QNdefNfcTextRecord::Utf8 ?
+ QStringLiteral("UTF-8") : QStringLiteral("UTF-16") );
+ m_currentWriteRequestData.insert(QStringLiteral("Language"), textRecord.locale());
+ } else {
+ qCWarning(QT_NFC_NEARD) << "Record type not supported for writing";
+ return QNearFieldTarget::RequestId();
+ }
+
+ m_currentWriteRequestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate());
+ // trigger delayed write
+ m_delayedWriteTimer.start(100);
+
+ return m_currentWriteRequestId;
+ }
+
+ return QNearFieldTarget::RequestId();
+}
+
+QNdefRecord QNearFieldTargetPrivateImpl::readRecord(const QDBusObjectPath &path)
+{
+ qCDebug(QT_NFC_NEARD) << "reading record for path" << path.path();
+ OrgFreedesktopDBusPropertiesInterface recordInterface(QStringLiteral("org.neard"), path.path(),
+ QDBusConnection::systemBus());
+ if (!recordInterface.isValid())
+ return QNdefRecord();
+
+ QDBusPendingReply<QVariantMap> reply = recordInterface.GetAll(QStringLiteral("org.neard.Record"));
+ reply.waitForFinished();
+ if (reply.isError())
+ return QNdefRecord();
+
+ const QString &value = reply.value().value(QStringLiteral("Representation")).toString();
+ const QString &locale = reply.value().value(QStringLiteral("Language")).toString();
+ const QString &encoding = reply.value().value(QStringLiteral("Encoding")).toString();
+ const QString &uri = reply.value().value(QStringLiteral("URI")).toString();
+
+ //const QString &mime = reply.value().value(QStringLiteral("MIME")).toString();
+ //const QString &arr = reply.value().value(QStringLiteral("ARR")).toString();
+
+ const QString type = reply.value().value(QStringLiteral("Type")).toString();
+ if (type == QStringLiteral("Text")) {
+ QNdefNfcTextRecord textRecord;
+ textRecord.setText(value);
+ textRecord.setLocale(locale);
+ textRecord.setEncoding((encoding == QStringLiteral("UTF-8")) ? QNdefNfcTextRecord::Utf8
+ : QNdefNfcTextRecord::Utf16);
+ return textRecord;
+ } else if (type == QStringLiteral("SmartPoster")) {
+ QNdefNfcSmartPosterRecord spRecord;
+ if (!value.isEmpty()) {
+ spRecord.addTitle(value, locale, (encoding == QStringLiteral("UTF-8"))
+ ? QNdefNfcTextRecord::Utf8
+ : QNdefNfcTextRecord::Utf16);
+ }
+
+ if (!uri.isEmpty())
+ spRecord.setUri(QUrl(uri));
+
+ const QString &action = reply.value().value(QStringLiteral("Action")).toString();
+ if (!action.isEmpty()) {
+ if (action == QStringLiteral("Do"))
+ spRecord.setAction(QNdefNfcSmartPosterRecord::DoAction);
+ else if (action == QStringLiteral("Save"))
+ spRecord.setAction(QNdefNfcSmartPosterRecord::SaveAction);
+ else if (action == QStringLiteral("Edit"))
+ spRecord.setAction(QNdefNfcSmartPosterRecord::EditAction);
+ }
+
+ if (reply.value().contains(QStringLiteral("Size"))) {
+ uint size = reply.value().value(QStringLiteral("Size")).toUInt();
+ spRecord.setSize(size);
+ }
+
+ const QString &mimeType = reply.value().value(QStringLiteral("MIMEType")).toString();
+ if (!mimeType.isEmpty()) {
+ spRecord.setTypeInfo(mimeType);
+ }
+
+
+ return spRecord;
+ } else if (type == QStringLiteral("URI")) {
+ QNdefNfcUriRecord uriRecord;
+ uriRecord.setUri(QUrl(uri));
+ return uriRecord;
+ } else if (type == QStringLiteral("MIME")) {
+
+ } else if (type == QStringLiteral("AAR")) {
+
+ }
+
+ return QNdefRecord();
+}
+
+void QNearFieldTargetPrivateImpl::handleRecordFound(const QDBusObjectPath &path)
{
- return false;
+ m_recordPaths.append(path);
+ // FIXME: this timer only exists because neard doesn't currently supply enough
+ // information to let us know when all record interfaces have been added or
+ // how many records are actually contained on a tag. We assume that when no
+ // signal has been received for 100ms all record interfaces have been added.
+ m_recordPathsCollectedTimer.start(100);
+ // as soon as record paths have been added we can handle errors without the timer.
+ m_readErrorTimer.stop();
}
-bool QNearFieldTargetPrivate::setKeepConnection(bool isPersistent)
+void QNearFieldTargetPrivateImpl::createNdefMessage()
{
- Q_UNUSED(isPersistent);
- return false;
+ if (m_readRequested) {
+ qCDebug(QT_NFC_NEARD) << "creating Ndef message, reading" << m_recordPaths.length() << "record paths";
+ QNdefMessage newNdefMessage;
+ for (const QDBusObjectPath &recordPath : std::as_const(m_recordPaths))
+ newNdefMessage.append(readRecord(recordPath));
+
+ if (!newNdefMessage.isEmpty()) {
+ QMetaObject::invokeMethod(this, "ndefMessageRead", Qt::QueuedConnection,
+ Q_ARG(QNdefMessage, newNdefMessage));
+ // the request id in requestCompleted has to match the one created in readNdefMessages
+ QMetaObject::invokeMethod(this, [this]() {
+ Q_EMIT requestCompleted(m_currentReadRequestId);
+ }, Qt::QueuedConnection);
+ } else {
+ reportError(QNearFieldTarget::UnknownError, m_currentReadRequestId);
+ }
+
+ m_readRequested = false;
+ // invalidate the current request id
+ m_currentReadRequestId = QNearFieldTarget::RequestId(0);
+ }
}
-bool QNearFieldTargetPrivate::disconnect()
+void QNearFieldTargetPrivateImpl::handleReadError()
{
- return false;
+ reportError(QNearFieldTarget::UnknownError, m_currentReadRequestId);
+ m_currentReadRequestId = QNearFieldTarget::RequestId(0);
}
-int QNearFieldTargetPrivate::maxCommandLength() const
+void QNearFieldTargetPrivateImpl::handleWriteRequest()
{
- return 0;
+ OrgNeardTagInterface tagInterface(QStringLiteral("org.neard"), m_tagPath.path(),
+ QDBusConnection::systemBus());
+ if (!tagInterface.isValid()) {
+ qCWarning(QT_NFC_NEARD) << "tag interface invalid";
+ } else {
+ QDBusPendingReply<> reply;
+ reply = tagInterface.Write(m_currentWriteRequestData);
+ reply.waitForFinished();
+ if (reply.isError()) {
+ qCWarning(QT_NFC_NEARD) << "Error writing to NFC tag" << reply.error();
+ reportError(QNearFieldTarget::UnknownError, m_currentWriteRequestId);
+ }
+
+ QMetaObject::invokeMethod(this, [this]() {
+ Q_EMIT requestCompleted(m_currentWriteRequestId);
+ }, Qt::QueuedConnection);
+ }
+
+ // invalidate current write request
+ m_currentWriteRequestId = QNearFieldTarget::RequestId(0);
}
QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldtarget_neard_p.h b/src/nfc/qnearfieldtarget_neard_p.h
index 9844d99e..8e403e86 100644
--- a/src/nfc/qnearfieldtarget_neard_p.h
+++ b/src/nfc/qnearfieldtarget_neard_p.h
@@ -1,42 +1,5 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Copyright (C) 2016 BasysKom GmbH.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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, Copyright (C) 2016 BasysKom GmbH
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QNEARFIELDTARGET_NEARD_P_H
#define QNEARFIELDTARGET_NEARD_P_H
@@ -61,346 +24,39 @@
#include <qndefmessage.h>
#include "neard/neard_helper_p.h"
-#include "neard/dbusproperties_p.h"
-#include "neard/dbusobjectmanager_p.h"
-#include "neard/tag_p.h"
-
-#include <qndefnfctextrecord.h>
-#include <qndefnfcsmartposterrecord.h>
-#include <qndefnfcurirecord.h>
+#include "properties_interface.h"
+#include "objectmanager_interface.h"
+#include "tag_interface.h"
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QT_NFC_NEARD)
-template <typename T>
-class NearFieldTarget : public T
+class QNearFieldTargetPrivateImpl : public QNearFieldTargetPrivate
{
public:
+ QNearFieldTargetPrivateImpl(QObject *parent, QDBusObjectPath interfacePath);
- NearFieldTarget(QObject *parent, QDBusObjectPath interfacePath)
- : T(parent),
- m_tagPath(interfacePath),
- m_readRequested(false)
- {
- m_readErrorTimer.setSingleShot(true);
- m_recordPathsCollectedTimer.setSingleShot(true);
- m_delayedWriteTimer.setSingleShot(true);
-
- qCDebug(QT_NFC_NEARD) << "tag found at path" << interfacePath.path();
- m_dbusProperties = new OrgFreedesktopDBusPropertiesInterface(QStringLiteral("org.neard"),
- interfacePath.path(),
- QDBusConnection::systemBus(),
- this);
- if (!m_dbusProperties->isValid()) {
- qCWarning(QT_NFC_NEARD) << "Could not connect to dbus property interface at path" << interfacePath.path();
- return;
- }
-
- QDBusPendingReply<QVariantMap> reply = m_dbusProperties->GetAll(QStringLiteral("org.neard.Tag"));
- reply.waitForFinished();
- if (reply.isError()) {
- qCWarning(QT_NFC_NEARD) << "Could not get properties of org.neard.Tag dbus interface";
- return;
- }
-
- const QString &type = reply.value().value(QStringLiteral("Type")).toString();
- m_type = QNearFieldTarget::ProprietaryTag;
-
- if (type == QStringLiteral("Type 1"))
- m_type = QNearFieldTarget::NfcTagType1;
- else if (type == QStringLiteral("Type 2"))
- m_type = QNearFieldTarget::NfcTagType2;
- else if (type == QStringLiteral("Type 3"))
- m_type = QNearFieldTarget::NfcTagType3;
- else if (type == QStringLiteral("Type 4"))
- m_type = QNearFieldTarget::NfcTagType4;
-
- qCDebug(QT_NFC_NEARD) << "tag type" << type;
-
- QObject::connect(&m_recordPathsCollectedTimer, &QTimer::timeout,
- this, &NearFieldTarget::createNdefMessage);
- QObject::connect(&m_readErrorTimer, &QTimer::timeout,
- this, &NearFieldTarget::handleReadError);
- QObject::connect(&m_delayedWriteTimer, &QTimer::timeout,
- this, &NearFieldTarget::handleWriteRequest);
- QObject::connect(NeardHelper::instance(), &NeardHelper::recordFound,
- this, &NearFieldTarget::handleRecordFound);
- }
-
- ~NearFieldTarget()
- {
- }
-
- bool isValid()
- {
- return m_dbusProperties->isValid() && NeardHelper::instance()->dbusObjectManager()->isValid();
- }
-
- QByteArray uid() const
- {
- return QByteArray(); // TODO figure out a workaround because neard does not offer
- // this property
- }
-
- QNearFieldTarget::Type type() const
- {
- return m_type;
- }
-
- QNearFieldTarget::AccessMethods accessMethods() const
- {
- return QNearFieldTarget::NdefAccess;
- }
-
- bool hasNdefMessage()
- {
- return !m_recordPaths.isEmpty();
- }
-
- QNearFieldTarget::RequestId readNdefMessages()
- {
- if (isValid()) {
- // if the user calls readNdefMessages before the previous request has been completed
- // return the current request id.
- if (m_currentReadRequestId.isValid())
- return m_currentReadRequestId;
-
- QNearFieldTarget::RequestId requestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate());
- // save the id so it can be passed along with requestCompleted
- m_currentReadRequestId = requestId;
- // since the triggering of interfaceAdded will ultimately lead to createNdefMessage being called
- // we need to make sure that ndefMessagesRead will only be triggered when readNdefMessages has
- // been called before. In case readNdefMessages is called again after that we can directly call
- // call createNdefMessage.
- m_readRequested = true;
- if (hasNdefMessage())
- createNdefMessage();
- else
- m_readErrorTimer.start(1000);
-
- return requestId;
- } else {
- return QNearFieldTarget::RequestId();
- }
- }
-
- QNearFieldTarget::RequestId sendCommand(const QByteArray &command)
- {
- Q_UNUSED(command);
- return QNearFieldTarget::RequestId();
- }
-
- QNearFieldTarget::RequestId sendCommands(const QList<QByteArray> &commands)
- {
- Q_UNUSED(commands);
- return QNearFieldTarget::RequestId();
- }
-
- QNearFieldTarget::RequestId writeNdefMessages(const QList<QNdefMessage> &messages)
- {
- // disabling write due to neard crash (see QTBUG-43802)
- qWarning("QNearFieldTarget::WriteNdefMessages() disabled. See QTBUG-43802\n");
- return QNearFieldTarget::RequestId();
-
-
- // return old request id when previous write request hasn't completed
- if (m_currentWriteRequestId.isValid())
- return m_currentReadRequestId;
-
- qCDebug(QT_NFC_NEARD) << "writing messages";
- if (messages.isEmpty() || messages.first().isEmpty()) {
- qCWarning(QT_NFC_NEARD) << "No record specified";
- return QNearFieldTarget::RequestId();
- }
- if (messages.count() > 1 || messages.first().count() > 1) {
- // neard only supports one ndef record per tag
- qCWarning(QT_NFC_NEARD) << "Writing of only one NDEF record and message is supported";
- return QNearFieldTarget::RequestId();
- }
- QNdefRecord record = messages.first().first();
+ ~QNearFieldTargetPrivateImpl();
- if (record.typeNameFormat() == QNdefRecord::NfcRtd) {
- m_currentWriteRequestData.clear();
- if (record.isRecordType<QNdefNfcUriRecord>()) {
- m_currentWriteRequestData.insert(QStringLiteral("Type"), QStringLiteral("URI"));
- QNdefNfcUriRecord uriRecord = static_cast<QNdefNfcUriRecord>(record);
- m_currentWriteRequestData.insert(QStringLiteral("URI"), uriRecord.uri().toString());
- } else if (record.isRecordType<QNdefNfcSmartPosterRecord>()) {
- m_currentWriteRequestData.insert(QStringLiteral("Type"), QStringLiteral("SmartPoster"));
- QNdefNfcSmartPosterRecord spRecord = static_cast<QNdefNfcSmartPosterRecord>(record);
- m_currentWriteRequestData.insert(QStringLiteral("URI"), spRecord.uri().toString());
- // Currently neard only supports the uri property for writing
- } else if (record.isRecordType<QNdefNfcTextRecord>()) {
- m_currentWriteRequestData.insert(QStringLiteral("Type"), QStringLiteral("Text"));
- QNdefNfcTextRecord textRecord = static_cast<QNdefNfcTextRecord>(record);
- m_currentWriteRequestData.insert(QStringLiteral("Representation"), textRecord.text());
- m_currentWriteRequestData.insert(QStringLiteral("Encoding"),
- textRecord.encoding() == QNdefNfcTextRecord::Utf8 ?
- QStringLiteral("UTF-8") : QStringLiteral("UTF-16") );
- m_currentWriteRequestData.insert(QStringLiteral("Language"), textRecord.locale());
- } else {
- qCWarning(QT_NFC_NEARD) << "Record type not supported for writing";
- return QNearFieldTarget::RequestId();
- }
+ bool isValid();
+ QByteArray uid() const override;
- m_currentWriteRequestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate());
- // trigger delayed write
- m_delayedWriteTimer.start(100);
+ QNearFieldTarget::Type type() const override;
+ QNearFieldTarget::AccessMethods accessMethods() const override;
- return m_currentWriteRequestId;
- }
-
- return QNearFieldTarget::RequestId();
- }
+ bool hasNdefMessage() override;
+ QNearFieldTarget::RequestId readNdefMessages() override;
+ QNearFieldTarget::RequestId sendCommand(const QByteArray &command) override;
+ QNearFieldTarget::RequestId writeNdefMessages(const QList<QNdefMessage> &messages) override;
private:
- QNdefRecord readRecord(const QDBusObjectPath &path)
- {
- qCDebug(QT_NFC_NEARD) << "reading record for path" << path.path();
- OrgFreedesktopDBusPropertiesInterface recordInterface(QStringLiteral("org.neard"),
- path.path(),
- QDBusConnection::systemBus());
- if (!recordInterface.isValid())
- return QNdefRecord();
-
- QDBusPendingReply<QVariantMap> reply = recordInterface.GetAll(QStringLiteral("org.neard.Record"));
- reply.waitForFinished();
- if (reply.isError())
- return QNdefRecord();
-
- const QString &value = reply.value().value(QStringLiteral("Representation")).toString();
- const QString &locale = reply.value().value(QStringLiteral("Language")).toString();
- const QString &encoding = reply.value().value(QStringLiteral("Encoding")).toString();
- const QString &uri = reply.value().value(QStringLiteral("URI")).toString();
-
-// const QString &mime = reply.value().value(QStringLiteral("MIME")).toString();
-// const QString &arr = reply.value().value(QStringLiteral("ARR")).toString();
-
- const QString type = reply.value().value(QStringLiteral("Type")).toString();
- if (type == QStringLiteral("Text")) {
- QNdefNfcTextRecord textRecord;
- textRecord.setText(value);
- textRecord.setLocale(locale);
- textRecord.setEncoding((encoding == QStringLiteral("UTF-8")) ? QNdefNfcTextRecord::Utf8
- : QNdefNfcTextRecord::Utf16);
- return textRecord;
- } else if (type == QStringLiteral("SmartPoster")) {
- QNdefNfcSmartPosterRecord spRecord;
- if (!value.isEmpty()) {
- spRecord.addTitle(value, locale, (encoding == QStringLiteral("UTF-8"))
- ? QNdefNfcTextRecord::Utf8
- : QNdefNfcTextRecord::Utf16);
- }
-
- if (!uri.isEmpty())
- spRecord.setUri(QUrl(uri));
-
- const QString &action = reply.value().value(QStringLiteral("Action")).toString();
- if (!action.isEmpty()) {
- if (action == QStringLiteral("Do"))
- spRecord.setAction(QNdefNfcSmartPosterRecord::DoAction);
- else if (action == QStringLiteral("Save"))
- spRecord.setAction(QNdefNfcSmartPosterRecord::SaveAction);
- else if (action == QStringLiteral("Edit"))
- spRecord.setAction(QNdefNfcSmartPosterRecord::EditAction);
- }
-
- if (reply.value().contains(QStringLiteral("Size"))) {
- uint size = reply.value().value(QStringLiteral("Size")).toUInt();
- spRecord.setSize(size);
- }
-
- const QString &mimeType = reply.value().value(QStringLiteral("MIMEType")).toString();
- if (!mimeType.isEmpty()) {
- spRecord.setTypeInfo(mimeType.toUtf8());
- }
-
-
- return spRecord;
- } else if (type == QStringLiteral("URI")) {
- QNdefNfcUriRecord uriRecord;
- uriRecord.setUri(QUrl(uri));
- return uriRecord;
- } else if (type == QStringLiteral("MIME")) {
-
- } else if (type == QStringLiteral("AAR")) {
-
- }
-
- return QNdefRecord();
- }
-
- void handleRecordFound(const QDBusObjectPath &path)
- {
- m_recordPaths.append(path);
- // FIXME: this timer only exists because neard doesn't currently supply enough
- // information to let us know when all record interfaces have been added or
- // how many records are actually contained on a tag. We assume that when no
- // signal has been received for 100ms all record interfaces have been added.
- m_recordPathsCollectedTimer.start(100);
- // as soon as record paths have been added we can handle errors without the timer.
- m_readErrorTimer.stop();
- }
-
- void createNdefMessage()
- {
- if (m_readRequested) {
- qCDebug(QT_NFC_NEARD) << "creating Ndef message, reading" << m_recordPaths.length() << "record paths";
- QNdefMessage newNdefMessage;
- for (const QDBusObjectPath &recordPath : qAsConst(m_recordPaths))
- newNdefMessage.append(readRecord(recordPath));
-
- if (!newNdefMessage.isEmpty()) {
- QMetaObject::invokeMethod(this, "ndefMessageRead", Qt::QueuedConnection,
- Q_ARG(QNdefMessage, newNdefMessage));
- // the request id in requestCompleted has to match the one created in readNdefMessages
- QMetaObject::invokeMethod(this, [this]() {
- Q_EMIT this->requestCompleted(this->m_currentReadRequestId);
- }, Qt::QueuedConnection);
- } else {
- this->reportError(QNearFieldTarget::UnknownError, m_currentReadRequestId);
- }
-
- m_readRequested = false;
- // invalidate the current request id
- m_currentReadRequestId = QNearFieldTarget::RequestId(0);
- }
- }
-
- void handleReadError()
- {
- emit QNearFieldTarget::error(QNearFieldTarget::UnknownError, m_currentReadRequestId);
- m_currentReadRequestId = QNearFieldTarget::RequestId(0);
- }
-
- void handleWriteRequest()
- {
- OrgNeardTagInterface tagInterface(QStringLiteral("org.neard"),
- m_tagPath.path(),
- QDBusConnection::systemBus());
- if (!tagInterface.isValid()) {
- qCWarning(QT_NFC_NEARD) << "tag interface invalid";
- } else {
- QDBusPendingReply<> reply;
- reply = tagInterface.Write(m_currentWriteRequestData);
- reply.waitForFinished();
- if (reply.isError()) {
- qCWarning(QT_NFC_NEARD) << "Error writing to NFC tag" << reply.error();
- this->reportError(QNearFieldTarget::UnknownError, m_currentWriteRequestId);
- }
-
- QMetaObject::invokeMethod(this, "ndefMessagesWritten", Qt::QueuedConnection);
- QMetaObject::invokeMethod(this, [this]() {
- Q_EMIT this->requestCompleted(this->m_currentWriteRequestId);
- }, Qt::QueuedConnection);
- }
-
- // invalidate current write request
- m_currentWriteRequestId = QNearFieldTarget::RequestId(0);
- }
+ QNdefRecord readRecord(const QDBusObjectPath &path);
+ void handleRecordFound(const QDBusObjectPath &path);
+ void createNdefMessage();
+ void handleReadError();
+ void handleWriteRequest();
-protected:
QDBusObjectPath m_tagPath;
OrgFreedesktopDBusPropertiesInterface *m_dbusProperties;
QList<QDBusObjectPath> m_recordPaths;
diff --git a/src/nfc/qnearfieldtarget_p.cpp b/src/nfc/qnearfieldtarget_p.cpp
index 4ed17a15..ff69eecd 100644
--- a/src/nfc/qnearfieldtarget_p.cpp
+++ b/src/nfc/qnearfieldtarget_p.cpp
@@ -1,58 +1,34 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Governikus GmbH & Co. K
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 <QCoreApplication>
-
-#include "qnearfieldtarget.h"
+// Copyright (C) 2017 Governikus GmbH & Co. K
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
#include "qnearfieldtarget_p.h"
+#include <QtCore/QCoreApplication>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QPointer>
+
QT_BEGIN_NAMESPACE
-bool QNearFieldTargetPrivate::keepConnection() const
+
+QNearFieldTargetPrivate::QNearFieldTargetPrivate(QObject *parent)
+: QObject(parent)
+, q_ptr(nullptr)
{
- return false;
}
-bool QNearFieldTargetPrivate::setKeepConnection(bool isPersistent)
+QByteArray QNearFieldTargetPrivate::uid() const
{
- Q_UNUSED(isPersistent);
- return false;
+ return QByteArray();
+}
+
+QNearFieldTarget::Type QNearFieldTargetPrivate::type() const
+{
+ return QNearFieldTarget::Type::ProprietaryTag;
+}
+
+QNearFieldTarget::AccessMethods QNearFieldTargetPrivate::accessMethods() const
+{
+ return QNearFieldTarget::AccessMethod::UnknownAccess;
}
bool QNearFieldTargetPrivate::disconnect()
@@ -60,9 +36,99 @@ bool QNearFieldTargetPrivate::disconnect()
return false;
}
+// NdefAccess
+bool QNearFieldTargetPrivate::hasNdefMessage()
+{
+ return false;
+}
+
+QNearFieldTarget::RequestId QNearFieldTargetPrivate::readNdefMessages()
+{
+ const QNearFieldTarget::RequestId id;
+ Q_EMIT error(QNearFieldTarget::UnsupportedError, id);
+ return id;
+}
+
+QNearFieldTarget::RequestId
+QNearFieldTargetPrivate::writeNdefMessages(const QList<QNdefMessage> &messages)
+{
+ Q_UNUSED(messages);
+
+ const QNearFieldTarget::RequestId id;
+ Q_EMIT error(QNearFieldTarget::UnsupportedError, id);
+ return id;
+}
+
+// TagTypeSpecificAccess
int QNearFieldTargetPrivate::maxCommandLength() const
{
return 0;
}
+QNearFieldTarget::RequestId QNearFieldTargetPrivate::sendCommand(const QByteArray &command)
+{
+ Q_UNUSED(command);
+
+ const QNearFieldTarget::RequestId id;
+ Q_EMIT error(QNearFieldTarget::UnsupportedError, id);
+ return id;
+}
+
+bool QNearFieldTargetPrivate::waitForRequestCompleted(const QNearFieldTarget::RequestId &id,
+ int msecs)
+{
+ QElapsedTimer timer;
+ timer.start();
+
+ const QPointer<QNearFieldTargetPrivate> weakThis = this;
+
+ do {
+ if (!weakThis)
+ return false;
+
+ if (m_decodedResponses.contains(id))
+ return true;
+ else
+ QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents, 1);
+ } while (timer.elapsed() <= msecs);
+
+ reportError(QNearFieldTarget::TimeoutError, id);
+
+ return false;
+}
+
+QVariant QNearFieldTargetPrivate::requestResponse(const QNearFieldTarget::RequestId &id) const
+{
+ return m_decodedResponses.value(id);
+}
+
+void QNearFieldTargetPrivate::setResponseForRequest(const QNearFieldTarget::RequestId &id,
+ const QVariant &response,
+ bool emitRequestCompleted)
+{
+ for (auto i = m_decodedResponses.begin(), end = m_decodedResponses.end(); i != end; /* erasing */) {
+ // no more external references
+ if (i.key().refCount() == 1)
+ i = m_decodedResponses.erase(i);
+ else
+ ++i;
+ }
+
+ m_decodedResponses.insert(id, response);
+
+ if (emitRequestCompleted)
+ Q_EMIT requestCompleted(id);
+}
+
+void QNearFieldTargetPrivate::reportError(QNearFieldTarget::Error error,
+ const QNearFieldTarget::RequestId &id)
+{
+ setResponseForRequest(id, QVariant(), false);
+ QMetaObject::invokeMethod(this, [this, error, id]() {
+ Q_EMIT this->error(error, id);
+ }, Qt::QueuedConnection);
+}
+
QT_END_NAMESPACE
+
+#include "moc_qnearfieldtarget_p.cpp"
diff --git a/src/nfc/qnearfieldtarget_p.h b/src/nfc/qnearfieldtarget_p.h
index 9c1a2954..dd7550ad 100644
--- a/src/nfc/qnearfieldtarget_p.h
+++ b/src/nfc/qnearfieldtarget_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 QtNfc 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 QNEARFIELDTARGET_P_H
#define QNEARFIELDTARGET_P_H
@@ -51,15 +15,14 @@
// We mean it.
//
-#include "qtnfcglobal.h"
-
#include "qnearfieldtarget.h"
-#include <QtCore/QMap>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QObject>
#include <QtCore/QSharedData>
#include <QtCore/QVariant>
-
-#define NEARFIELDTARGET_Q() NearFieldTarget * const q = reinterpret_cast<NearFieldTarget *>(q_ptr)
+#include <QtCore/QMap>
QT_BEGIN_NAMESPACE
@@ -67,20 +30,51 @@ class QNearFieldTarget::RequestIdPrivate : public QSharedData
{
};
-class QNearFieldTargetPrivate
+class Q_AUTOTEST_EXPORT QNearFieldTargetPrivate : public QObject
{
- QNearFieldTarget *q_ptr;
- Q_DECLARE_PUBLIC(QNearFieldTarget)
+ Q_OBJECT
public:
- QNearFieldTargetPrivate(QNearFieldTarget *q) : q_ptr(q) {}
+ QNearFieldTarget *q_ptr;
+
+ explicit QNearFieldTargetPrivate(QObject *parent = nullptr);
+ virtual ~QNearFieldTargetPrivate() = default;
+
+ virtual QByteArray uid() const;
+ virtual QNearFieldTarget::Type type() const;
+ virtual QNearFieldTarget::AccessMethods accessMethods() const;
+
+ virtual bool disconnect();
+ // NdefAccess
+ virtual bool hasNdefMessage();
+ virtual QNearFieldTarget::RequestId readNdefMessages();
+ virtual QNearFieldTarget::RequestId writeNdefMessages(const QList<QNdefMessage> &messages);
+
+ // TagTypeSpecificAccess
+ virtual int maxCommandLength() const;
+ virtual QNearFieldTarget::RequestId sendCommand(const QByteArray &command);
+
+ bool waitForRequestCompleted(const QNearFieldTarget::RequestId &id, int msecs = 5000);
+ QVariant requestResponse(const QNearFieldTarget::RequestId &id) const;
+
+Q_SIGNALS:
+ void disconnected();
+
+ void ndefMessageRead(const QNdefMessage &message);
+
+ void requestCompleted(const QNearFieldTarget::RequestId &id);
+
+ void error(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id);
+
+protected:
QMap<QNearFieldTarget::RequestId, QVariant> m_decodedResponses;
- bool keepConnection() const;
- bool setKeepConnection(bool isPersistent);
- bool disconnect();
- int maxCommandLength() const;
+ virtual void setResponseForRequest(const QNearFieldTarget::RequestId &id,
+ const QVariant &response,
+ bool emitRequestCompleted = true);
+
+ void reportError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id);
};
QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldtarget_pcsc.cpp b/src/nfc/qnearfieldtarget_pcsc.cpp
new file mode 100644
index 00000000..76bc685f
--- /dev/null
+++ b/src/nfc/qnearfieldtarget_pcsc.cpp
@@ -0,0 +1,161 @@
+// 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 "qnearfieldtarget_pcsc_p.h"
+#include "qndefmessage.h"
+#include <QtCore/QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_NFC_PCSC)
+
+/*
+ Construct QNearFieldTargetPrivateImpl instance.
+
+ This object communicates with a QPcscCard object that lives inside the
+ worker thread via signal-slot mechanism.
+*/
+QNearFieldTargetPrivateImpl::QNearFieldTargetPrivateImpl(
+ const QByteArray &uid, QNearFieldTarget::AccessMethods accessMethods, int maxInputLength,
+ QObject *parent)
+ : QNearFieldTargetPrivate(parent),
+ m_uid(uid),
+ m_accessMethods(accessMethods),
+ m_maxInputLength(maxInputLength)
+{
+ qCDebug(QT_NFC_PCSC) << "New card with UID" << m_uid.toHex(':');
+}
+
+QNearFieldTargetPrivateImpl::~QNearFieldTargetPrivateImpl()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+}
+
+QByteArray QNearFieldTargetPrivateImpl::uid() const
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+ return m_uid;
+}
+
+QNearFieldTarget::Type QNearFieldTargetPrivateImpl::type() const
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ // Currently NDEF access is only supported for Type 4 tags
+ if (m_accessMethods & QNearFieldTarget::NdefAccess)
+ return QNearFieldTarget::NfcTagType4;
+
+ return QNearFieldTarget::ProprietaryTag;
+}
+
+QNearFieldTarget::AccessMethods QNearFieldTargetPrivateImpl::accessMethods() const
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+ return m_accessMethods;
+}
+
+bool QNearFieldTargetPrivateImpl::disconnect()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ if (!m_connected || !m_isValid)
+ return false;
+
+ Q_EMIT disconnectRequest();
+ return true;
+}
+
+int QNearFieldTargetPrivateImpl::maxCommandLength() const
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+ return m_maxInputLength;
+}
+
+void QNearFieldTargetPrivateImpl::onRequestCompleted(const QNearFieldTarget::RequestId &request,
+ QNearFieldTarget::Error reason,
+ const QVariant &result)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ if (reason == QNearFieldTarget::NoError)
+ setResponseForRequest(request, result);
+ else
+ reportError(reason, request);
+}
+
+void QNearFieldTargetPrivateImpl::onNdefMessageRead(const QNdefMessage &message)
+{
+ Q_EMIT ndefMessageRead(message);
+}
+
+QNearFieldTarget::RequestId QNearFieldTargetPrivateImpl::sendCommand(const QByteArray &command)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ if (!m_isValid)
+ return QNearFieldTarget::RequestId(nullptr);
+
+ m_connected = true;
+
+ QNearFieldTarget::RequestId reqId(new QNearFieldTarget::RequestIdPrivate);
+ Q_EMIT sendCommandRequest(reqId, command);
+
+ return reqId;
+}
+
+QNearFieldTarget::RequestId QNearFieldTargetPrivateImpl::readNdefMessages()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ if (!m_isValid)
+ return QNearFieldTarget::RequestId(nullptr);
+
+ m_connected = true;
+
+ QNearFieldTarget::RequestId reqId(new QNearFieldTarget::RequestIdPrivate);
+ Q_EMIT readNdefMessagesRequest(reqId);
+
+ return reqId;
+}
+
+QNearFieldTarget::RequestId
+QNearFieldTargetPrivateImpl::writeNdefMessages(const QList<QNdefMessage> &messages)
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ if (!m_isValid)
+ return QNearFieldTarget::RequestId(nullptr);
+
+ m_connected = true;
+
+ QNearFieldTarget::RequestId reqId(new QNearFieldTarget::RequestIdPrivate);
+ Q_EMIT writeNdefMessagesRequest(reqId, messages);
+
+ return reqId;
+}
+
+void QNearFieldTargetPrivateImpl::onDisconnected()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ if (!m_connected)
+ return;
+
+ m_connected = false;
+
+ Q_EMIT disconnected();
+}
+
+void QNearFieldTargetPrivateImpl::onInvalidated()
+{
+ qCDebug(QT_NFC_PCSC) << Q_FUNC_INFO;
+
+ if (!m_isValid)
+ return;
+
+ m_isValid = false;
+
+ Q_EMIT targetLost(this);
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldtarget_pcsc_p.h b/src/nfc/qnearfieldtarget_pcsc_p.h
new file mode 100644
index 00000000..c5631af1
--- /dev/null
+++ b/src/nfc/qnearfieldtarget_pcsc_p.h
@@ -0,0 +1,67 @@
+// Copyright (C) 2022q 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 QNEARFIELDTARGET_PCSC_P_H
+#define QNEARFIELDTARGET_PCSC_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 "qnearfieldtarget_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldTargetPrivateImpl : public QNearFieldTargetPrivate
+{
+ Q_OBJECT
+public:
+ QNearFieldTargetPrivateImpl(const QByteArray &uid,
+ QNearFieldTarget::AccessMethods accessMethods, int maxInputLength,
+ QObject *parent);
+ ~QNearFieldTargetPrivateImpl() override;
+
+ QByteArray uid() const override;
+ QNearFieldTarget::Type type() const override;
+ QNearFieldTarget::AccessMethods accessMethods() const override;
+
+ bool disconnect() override;
+
+ int maxCommandLength() const override;
+ QNearFieldTarget::RequestId sendCommand(const QByteArray &command) override;
+ QNearFieldTarget::RequestId readNdefMessages() override;
+ QNearFieldTarget::RequestId writeNdefMessages(const QList<QNdefMessage> &messages) override;
+
+private:
+ const QByteArray m_uid;
+ QNearFieldTarget::AccessMethods m_accessMethods;
+ int m_maxInputLength;
+ bool m_connected = false;
+ bool m_isValid = true;
+
+public Q_SLOTS:
+ void onDisconnected();
+ void onInvalidated();
+ void onRequestCompleted(const QNearFieldTarget::RequestId &request,
+ QNearFieldTarget::Error reason, const QVariant &result);
+ void onNdefMessageRead(const QNdefMessage &message);
+
+Q_SIGNALS:
+ void disconnectRequest();
+ void sendCommandRequest(const QNearFieldTarget::RequestId &request, const QByteArray &command);
+ void readNdefMessagesRequest(const QNearFieldTarget::RequestId &request);
+ void writeNdefMessagesRequest(const QNearFieldTarget::RequestId &request,
+ const QList<QNdefMessage> &messages);
+ void targetLost(QNearFieldTargetPrivate *target);
+};
+
+QT_END_NAMESPACE
+
+#endif // QNEARFIELDTARGET_PCSC_P_H
diff --git a/src/nfc/qnfc.cpp b/src/nfc/qnfc.cpp
deleted file mode 100644
index 56a4f4f3..00000000
--- a/src/nfc/qnfc.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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/QLoggingCategory>
-#include <QtNfc/qtnfcglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(QT_NFC_NEARD, "qt.nfc.neard")
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qqmlndefrecord.cpp b/src/nfc/qqmlndefrecord.cpp
deleted file mode 100644
index 5a96bec8..00000000
--- a/src/nfc/qqmlndefrecord.cpp
+++ /dev/null
@@ -1,356 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 "qqmlndefrecord.h"
-
-#include <QtCore/QMap>
-#include <QtCore/QRegularExpression>
-
-#include <QtCore/qglobalstatic.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QQmlNdefRecord
- \brief The QQmlNdefRecord class implements the NdefRecord type in QML.
-
- \ingroup connectivity-nfc
- \inmodule QtNfc
- \since 5.2
-
- \sa NdefRecord
-
- The QQmlNdefRecord class is the base class for all NdefRecord types in QML. To
- support a new NDEF record type in QML subclass this class and expose new properties, member
- functions and signals appropriate for the new record type. The following must be done to
- create a new NDEF record type in QML:
-
- \list
- \li The subclass must have a Q_OBJECT macro in its declaration.
- \li The subclass must have an \l {Q_INVOKABLE}{invokable} constructor that takes a
- QNdefRecord and a QObject pointer.
- \li The subclass must be declared as an NDEF record by expanding the Q_DECLARE_NDEFRECORD()
- macro in the implementation file of the subclass.
- \li The subclass must be registered with QML.
- \endlist
-
- For example the declaration of such a class may look like the following.
-
- \snippet foorecord.h Foo declaration
-
- Within the implementation file the Q_DECLARE_NDEFRECORD() macro is expanded:
-
- \snippet foorecord.cpp Declare foo record
-
- Finially the application or plugin code calls qmlRegisterType():
-
- \code
- qmlRegisterType<QQmlNdefFooRecord>(uri, 1, 0, "NdefFooRecord");
- \endcode
-*/
-
-/*!
- \qmltype NdefRecord
- \instantiates QQmlNdefRecord
- \brief The NdefRecord type represents a record in an NDEF message.
-
- \ingroup nfc-qml
- \inqmlmodule QtNfc
-
- \sa NdefFilter
- \sa NearField
-
- \sa QNdefRecord
-
- The NdefRecord type is the base type for all NDEF record types in QML. It contains
- a single property holding the type of record.
-
- This class is not intended to be used directly, but extended from C++.
-
- \sa QQmlNdefRecord
-*/
-
-/*!
- \qmlproperty string NdefRecord::type
-
- This property holds the type of the NDEF record.
-*/
-
-/*!
- \qmlproperty enumeration NdefRecord::typeNameFormat
-
- This property holds the TNF of the NDEF record.
-
- \table
- \header \li Property \li Description
- \row \li \c NdefRecord.Empty
- \li An empty NDEF record, the record does not contain a payload.
- \row \li \c NdefRecord.NfcRtd
- \li The NDEF record type is defined by an NFC RTD Specification.
- \row \li \c NdefRecord.Mime
- \li The NDEF record type follows the construct described in RFC 2046.
- \row \li \c NdefRecord.Uri
- \li The NDEF record type follows the construct described in RFC 3986.
- \row \li \c NdefRecord.ExternalRtd
- \li The NDEF record type follows the construct for external type names
- described the NFC RTD Specification.
- \endtable
-
- \sa QNdefRecord::typeNameFormat()
-*/
-
-/*!
- \qmlproperty string NdefRecord::record
-
- This property holds the NDEF record.
-*/
-
-/*!
- \fn void QQmlNdefRecord::typeChanged()
-
- This signal is emitted when the record type changes.
-*/
-
-/*!
- \property QQmlNdefRecord::record
-
- This property hold the NDEF record that this class represents.
-*/
-
-/*!
- \property QQmlNdefRecord::type
-
- This property hold the type of the NDEF record.
-*/
-
-/*!
- \property QQmlNdefRecord::typeNameFormat
-
- This property hold the TNF of the NDEF record.
-*/
-
-/*!
- \macro Q_DECLARE_NDEFRECORD(className, typeNameFormat, type)
- \relates QQmlNdefRecord
-
- This macro ensures that \a className is declared as the class implementing the NDEF record
- identified by \a typeNameFormat and \a type.
-
- This macro should be expanded in the implementation file for \a className.
-*/
-
-typedef QMap<QString, const QMetaObject *> NDefRecordTypesMap;
-Q_GLOBAL_STATIC(NDefRecordTypesMap, registeredNdefRecordTypes)
-
-class QQmlNdefRecordPrivate
-{
-public:
- QNdefRecord record;
-};
-
-static QString urnForRecordType(QNdefRecord::TypeNameFormat typeNameFormat, const QByteArray &type)
-{
- switch (typeNameFormat) {
- case QNdefRecord::NfcRtd:
- return QStringLiteral("urn:nfc:wkt:") + QString::fromLatin1(type);
- case QNdefRecord::ExternalRtd:
- return QStringLiteral("urn:nfc:ext:") + QString::fromLatin1(type);
- case QNdefRecord::Mime:
- return QStringLiteral("urn:nfc:mime:") + QString::fromLatin1(type);
- default:
- return QString();
- }
-}
-
-/*!
- \internal
-*/
-void qRegisterNdefRecordTypeHelper(const QMetaObject *metaObject,
- QNdefRecord::TypeNameFormat typeNameFormat,
- const QByteArray &type)
-{
- registeredNdefRecordTypes()->insert(urnForRecordType(typeNameFormat, type), metaObject);
-}
-
-/*!
- \internal
-*/
-QQmlNdefRecord *qNewDeclarativeNdefRecordForNdefRecord(const QNdefRecord &record)
-{
- const QString urn = urnForRecordType(record.typeNameFormat(), record.type());
-
- const auto *rt = registeredNdefRecordTypes();
-
- for (auto i = rt->cbegin(), end = rt->cend(); i != end; ++i) {
- QRegularExpression rx(QRegularExpression::anchoredPattern(i.key()));
- if (!rx.match(urn).hasMatch())
- continue;
-
- const QMetaObject *metaObject = i.value();
- if (!metaObject)
- continue;
-
- return static_cast<QQmlNdefRecord *>(metaObject->newInstance(
- Q_ARG(QNdefRecord, record), Q_ARG(QObject*, 0)));
- }
-
- return new QQmlNdefRecord(record);
-}
-
-/*!
- Constructs a new empty QQmlNdefRecord with \a parent.
-*/
-QQmlNdefRecord::QQmlNdefRecord(QObject *parent)
-: QObject(parent), d_ptr(new QQmlNdefRecordPrivate)
-{
-}
-
-/*!
- Constructs a new QQmlNdefRecord representing \a record. The parent of the newly
- constructed object will be set to \a parent.
-*/
-QQmlNdefRecord::QQmlNdefRecord(const QNdefRecord &record, QObject *parent)
-: QObject(parent), d_ptr(new QQmlNdefRecordPrivate)
-{
- d_ptr->record = record;
-}
-
-/*!
- Destroys the QQmlNdefRecord instance.
-*/
-QQmlNdefRecord::~QQmlNdefRecord()
-{
- delete d_ptr;
-}
-
-/*!
- \enum QQmlNdefRecord::TypeNameFormat
-
- This enum describes the type name format of an NDEF record. The values of this enum are according to
- \l QNdefRecord::TypeNameFormat
-
- \value Empty An empty NDEF record, the record does not contain a payload.
- \value NfcRtd The NDEF record type is defined by an NFC RTD Specification.
- \value Mime The NDEF record type follows the construct described in RFC 2046.
- \value Uri The NDEF record type follows the construct described in RFC 3986.
- \value ExternalRtd The NDEF record type follows the construct for external type names
- described the NFC RTD Specification.
- \value Unknown The NDEF record type is unknown.
-*/
-
-/*!
- Returns the type of the record.
-
- \sa QNdefRecord::setType(), QNdefRecord::type()
-*/
-QString QQmlNdefRecord::type() const
-{
- Q_D(const QQmlNdefRecord);
-
- return QLatin1String(d->record.type());
-}
-
-/*!
- Sets the record type to \a newtype if it is not currently equal to \l type(); otherwise does
- nothing. If the record type is set the typeChanged() signal will be emitted.
-
- \sa QNdefRecord::setType(), QNdefRecord::type()
-*/
-void QQmlNdefRecord::setType(const QString &newtype)
-{
- if (newtype == type())
- return;
-
- Q_D(QQmlNdefRecord);
- d->record.setType(newtype.toUtf8());
-
- emit typeChanged();
-}
-
-/*!
- Sets the type name format of the NDEF record to \a newTypeNameFormat.
-*/
-void QQmlNdefRecord::setTypeNameFormat(QQmlNdefRecord::TypeNameFormat newTypeNameFormat)
-{
- if (newTypeNameFormat == typeNameFormat())
- return;
-
- Q_D(QQmlNdefRecord);
- d->record.setTypeNameFormat(static_cast<QNdefRecord::TypeNameFormat>(newTypeNameFormat));
-
- emit typeNameFormatChanged();
-}
-
-/*!
- \fn QQmlNdefRecord::TypeNameFormat QQmlNdefRecord::typeNameFormat() const
-
- Returns the type name format of the NDEF record.
-*/
-QQmlNdefRecord::TypeNameFormat QQmlNdefRecord::typeNameFormat() const
-{
- Q_D(const QQmlNdefRecord);
- return static_cast<QQmlNdefRecord::TypeNameFormat>(d->record.typeNameFormat());
-}
-
-/*!
- Returns a copy of the record.
-*/
-QNdefRecord QQmlNdefRecord::record() const
-{
- Q_D(const QQmlNdefRecord);
-
- return d->record;
-}
-
-/*!
- Sets the record to \a record. If the record is set the recordChanged() signal will
- be emitted.
-*/
-void QQmlNdefRecord::setRecord(const QNdefRecord &record)
-{
- Q_D(QQmlNdefRecord);
-
- if (d->record == record)
- return;
-
- d->record = record;
- emit recordChanged();
-}
-
-QT_END_NAMESPACE
diff --git a/src/nfc/qqmlndefrecord.h b/src/nfc/qqmlndefrecord.h
deleted file mode 100644
index 0f624505..00000000
--- a/src/nfc/qqmlndefrecord.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QQMLNDEFRECORD_H
-#define QQMLNDEFRECORD_H
-
-#include <QtCore/QObject>
-#include <QtCore/QMetaType>
-#include <QtNfc/QNdefRecord>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlNdefRecordPrivate;
-
-class Q_NFC_EXPORT QQmlNdefRecord : public QObject
-{
- Q_OBJECT
-
- Q_DECLARE_PRIVATE(QQmlNdefRecord)
-
- Q_PROPERTY(QString type READ type WRITE setType NOTIFY typeChanged)
- Q_PROPERTY(TypeNameFormat typeNameFormat READ typeNameFormat WRITE setTypeNameFormat NOTIFY typeNameFormatChanged)
- Q_PROPERTY(QNdefRecord record READ record WRITE setRecord NOTIFY recordChanged)
-
-public:
- enum TypeNameFormat {
- Empty = QNdefRecord::Empty,
- NfcRtd = QNdefRecord::NfcRtd,
- Mime = QNdefRecord::Mime,
- Uri = QNdefRecord::Uri,
- ExternalRtd = QNdefRecord::ExternalRtd,
- Unknown = QNdefRecord::Unknown
- };
- Q_ENUM(TypeNameFormat)
-
- explicit QQmlNdefRecord(QObject *parent = nullptr);
- explicit QQmlNdefRecord(const QNdefRecord &record, QObject *parent = nullptr);
- ~QQmlNdefRecord();
-
- QString type() const;
- void setType(const QString &t);
-
- void setTypeNameFormat(TypeNameFormat typeNameFormat);
- TypeNameFormat typeNameFormat() const;
-
- QNdefRecord record() const;
- void setRecord(const QNdefRecord &record);
-
-Q_SIGNALS:
- void typeChanged();
- void typeNameFormatChanged();
- void recordChanged();
-
-private:
- QQmlNdefRecordPrivate *d_ptr;
-};
-
-void Q_NFC_EXPORT qRegisterNdefRecordTypeHelper(const QMetaObject *metaObject,
- QNdefRecord::TypeNameFormat typeNameFormat,
- const QByteArray &type);
-
-Q_NFC_EXPORT QQmlNdefRecord *qNewDeclarativeNdefRecordForNdefRecord(const QNdefRecord &record);
-
-template<typename T>
-bool qRegisterNdefRecordType(QNdefRecord::TypeNameFormat typeNameFormat, const QByteArray &type)
-{
- qRegisterNdefRecordTypeHelper(&T::staticMetaObject, typeNameFormat, type);
- return true;
-}
-
-#define Q_DECLARE_NDEFRECORD(className, typeNameFormat, type) \
-static bool _q_##className##_registered = qRegisterNdefRecordType<className>(typeNameFormat, type);
-
-QT_END_NAMESPACE
-
-#endif // QQMLNDEFRECORD_H
diff --git a/src/nfc/qtlv_p.h b/src/nfc/qtlv_p.h
deleted file mode 100644
index 1a4c6def..00000000
--- a/src/nfc/qtlv_p.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QTLV_P_H
-#define QTLV_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 "qtnfcglobal.h"
-
-#include "qnearfieldtarget.h"
-
-#include <QtCore/QByteArray>
-#include <QtCore/QMap>
-#include <QtCore/QPair>
-
-QT_BEGIN_NAMESPACE
-
-class QNearFieldTarget;
-class Q_AUTOTEST_EXPORT QTlvReader
-{
-public:
- explicit QTlvReader(QNearFieldTarget *target);
- explicit QTlvReader(const QByteArray &data);
-
- void addReservedMemory(int offset, int length);
- int reservedMemorySize() const;
-
- QNearFieldTarget::RequestId requestId() const;
-
- bool atEnd() const;
-
- bool readNext();
-
- quint8 tag() const;
- int length();
- QByteArray data();
-
-private:
- bool readMoreData(int sparseOffset);
- int absoluteOffset(int sparseOffset) const;
- int dataLength(int startOffset) const;
-
- QNearFieldTarget *m_target;
- QByteArray m_rawData;
- QNearFieldTarget::RequestId m_requestId;
-
- QByteArray m_tlvData;
- int m_index;
- QMap<int, int> m_reservedMemory;
-};
-
-class QTlvWriter
-{
-public:
- explicit QTlvWriter(QNearFieldTarget *target);
- explicit QTlvWriter(QByteArray *data);
- ~QTlvWriter();
-
- void addReservedMemory(int offset, int length);
-
- void writeTlv(quint8 tag, const QByteArray &data = QByteArray());
-
- bool process(bool all = false);
-
- QNearFieldTarget::RequestId requestId() const;
-
-private:
- int moveToNextAvailable();
-
- QNearFieldTarget *m_target;
- QByteArray *m_rawData;
-
- int m_index;
- int m_tagMemorySize;
- QMap<int, int> m_reservedMemory;
-
- QByteArray m_buffer;
-
- QNearFieldTarget::RequestId m_requestId;
-};
-
-QPair<int, int> qParseReservedMemoryControlTlv(const QByteArray &tlvData);
-QPair<int, int> qParseLockControlTlv(const QByteArray &tlvData);
-
-QT_END_NAMESPACE
-
-#endif // QTLV_P_H
diff --git a/src/nfc/qtnfcglobal.h b/src/nfc/qtnfcglobal.h
index 2a1e40b4..d80b25bf 100644
--- a/src/nfc/qtnfcglobal.h
+++ b/src/nfc/qtnfcglobal.h
@@ -1,59 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 QTNFC_H
#define QTNFC_H
#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifndef QT_STATIC
-# if defined(QT_BUILD_NFC_LIB)
-# define Q_NFC_EXPORT Q_DECL_EXPORT
-# else
-# define Q_NFC_EXPORT Q_DECL_IMPORT
-# endif
-#else
-# define Q_NFC_EXPORT
-#endif
-
-QT_END_NAMESPACE
+#include <QtNfc/qtnfcexports.h>
#endif // QTNFC_H
diff --git a/src/nfc/qtnfcglobal_p.h b/src/nfc/qtnfcglobal_p.h
index 2f40d464..f4ec0497 100644
--- a/src/nfc/qtnfcglobal_p.h
+++ b/src/nfc/qtnfcglobal_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 QTNFCGLOBAL_P_H
#define QTNFCGLOBAL_P_H
diff --git a/src/nfc/targetemulator_p.h b/src/nfc/targetemulator_p.h
deleted file mode 100644
index 1f682704..00000000
--- a/src/nfc/targetemulator_p.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 TARGETEMULATOR_P_H
-#define TARGETEMULATOR_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/QtGlobal>
-#include <QtCore/QByteArray>
-#include <QtNfc/qtnfcglobal.h>
-
-QT_FORWARD_DECLARE_CLASS(QSettings)
-
-QT_BEGIN_NAMESPACE
-
-class TagBase
-{
-public:
- TagBase();
- virtual ~TagBase();
-
- virtual void load(QSettings *settings) = 0;
-
- virtual QByteArray processCommand(const QByteArray &command) = 0;
-
- virtual QByteArray uid() const = 0;
-
- qint64 lastAccessTime() const { return lastAccess; }
-
-protected:
- mutable qint64 lastAccess;
-};
-
-class NfcTagType1 : public TagBase
-{
-public:
- NfcTagType1();
- ~NfcTagType1();
-
- void load(QSettings *settings);
-
- QByteArray processCommand(const QByteArray &command);
-
- QByteArray uid() const;
-
-private:
- quint8 readData(quint8 block, quint8 byte);
-
- quint8 hr0;
- quint8 hr1;
-
- QByteArray memory;
-};
-
-class NfcTagType2 : public TagBase
-{
-public:
- NfcTagType2();
- ~NfcTagType2();
-
- void load(QSettings *settings);
-
- QByteArray processCommand(const QByteArray &command);
-
- QByteArray uid() const;
-
-private:
- QByteArray memory;
- quint8 currentSector;
- bool expectPacket2;
-};
-
-QT_END_NAMESPACE
-
-#endif // TARGETEMULATOR_P_H
diff --git a/src/src.pro b/src/src.pro
deleted file mode 100644
index dba9de4b..00000000
--- a/src/src.pro
+++ /dev/null
@@ -1,30 +0,0 @@
-TEMPLATE = subdirs
-
-SUBDIRS += bluetooth nfc
-android {
- SUBDIRS += android
- android.depends += bluetooth nfc
-}
-
-contains(QT_CONFIG, private_tests) {
- bluetooth_doc_snippets.subdir = bluetooth/doc/snippets
- bluetooth_doc_snippets.depends = bluetooth
-
- nfc_doc_snippets.subdir = nfc/doc/snippets
- nfc_doc_snippets.depends = nfc
-
- SUBDIRS += bluetooth_doc_snippets nfc_doc_snippets
-}
-
-qtHaveModule(quick) {
- imports.depends += bluetooth nfc
- SUBDIRS += imports
-}
-
-include($$OUT_PWD/bluetooth/qtbluetooth-config.pri)
-QT_FOR_CONFIG += bluetooth
-qtConfig(bluez) {
- sdpscanner.subdir = tools/sdpscanner
- sdpscanner.depends = bluetooth
- SUBDIRS += sdpscanner
-}
diff --git a/src/tools/sdpscanner/CMakeLists.txt b/src/tools/sdpscanner/CMakeLists.txt
new file mode 100644
index 00000000..a490605a
--- /dev/null
+++ b/src/tools/sdpscanner/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## sdpscanner Tool:
+#####################################################################
+
+if(NOT TARGET PkgConfig::BLUEZ)
+ qt_find_package(BlueZ PROVIDED_TARGETS PkgConfig::BLUEZ)
+endif()
+
+qt_internal_add_app(sdpscanner
+ INSTALL_DIR "${INSTALL_LIBEXECDIR}"
+ SOURCES
+ main.cpp
+ DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
+ LIBRARIES
+ PkgConfig::BLUEZ
+)
diff --git a/src/tools/sdpscanner/main.cpp b/src/tools/sdpscanner/main.cpp
index 7e09ca6e..4a7f7d27 100644
--- a/src/tools/sdpscanner/main.cpp
+++ b/src/tools/sdpscanner/main.cpp
@@ -1,44 +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 GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/QByteArray>
#include <QtCore/QDebug>
+#include <QtCore/QUrl>
#include <stdio.h>
#include <string>
#include <bluetooth/bluetooth.h>
@@ -153,13 +118,15 @@ static void parseAttributeValues(sdp_data_t *data, int indentation, QByteArray &
QByteArray text = QByteArray::fromRawData(data->val.str, data->unitSize);
bool hasNonPrintableChar = false;
- for (int i = 0; i < text.count(); i++) {
+ for (qsizetype i = 0; i < text.size(); ++i) {
if (text[i] == '\0') {
text.resize(i); // cut trailing content
break;
} else if (!isprint(text[i])) {
hasNonPrintableChar = true;
- text.resize(text.indexOf('\0')); // cut trailing content
+ const auto firstNullIdx = text.indexOf('\0');
+ if (firstNullIdx > 0)
+ text.resize(firstNullIdx); // cut trailing content
break;
}
}
@@ -211,11 +178,17 @@ static void parseAttributeValues(sdp_data_t *data, int indentation, QByteArray &
case SDP_URL_STR8:
case SDP_URL_STR16:
case SDP_URL_STR32:
- strncpy(snBuffer, data->val.str, data->unitSize - 1);
+ {
xmlOutput.append("<url value=\"");
- xmlOutput.append(snBuffer);
+ const QByteArray urlData =
+ QByteArray::fromRawData(data->val.str, qstrnlen(data->val.str, data->unitSize));
+ const QUrl url = QUrl::fromEncoded(urlData);
+ // Encoded url %-encodes all of the XML special characters except '&',
+ // so we need to do that manually
+ xmlOutput.append(url.toEncoded().replace('&', "&amp;"));
xmlOutput.append("\"/>\n");
break;
+ }
default:
fprintf(stderr, "Unknown dtd type\n");
}
@@ -371,8 +344,8 @@ int main(int argc, char **argv)
sdp_list_t *totalResults = nullptr;
sdp_list_t* serviceFilter;
- for (uint i = 0; i < uuids.size(); ++i) {
- serviceFilter = sdp_list_append(nullptr, &uuids[i]);
+ for (uuid_t &uuid : uuids) { // can't be const, d/t sdp_list_append signature
+ serviceFilter = sdp_list_append(nullptr, &uuid);
result = sdp_service_search_attr_req(session, serviceFilter,
SDP_ATTR_REQ_RANGE,
attributes, &sdpResults);
diff --git a/src/tools/sdpscanner/qt_attribution.json b/src/tools/sdpscanner/qt_attribution.json
index cf0e5136..9524a336 100644
--- a/src/tools/sdpscanner/qt_attribution.json
+++ b/src/tools/sdpscanner/qt_attribution.json
@@ -10,7 +10,7 @@ QtBluetooth and user code linking to it is not considered a derivative work, and
have to be released under GPL too.",
"Description": "SDP Search via BlueZ",
"Homepage": "http://www.bluez.org/",
- "LicenseId": "GPL-2.0",
+ "LicenseId": "GPL-2.0-only",
"License": "GNU General Public License v2.0 only (This does not force user code to be GPL'ed. For more info see details.)",
"Copyright": "Copyright (C) 2000-2016 BlueZ Project."
}
diff --git a/src/tools/sdpscanner/sdpscanner.pro b/src/tools/sdpscanner/sdpscanner.pro
deleted file mode 100644
index 78610ebd..00000000
--- a/src/tools/sdpscanner/sdpscanner.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-TEMPLATE = app
-TARGET = sdpscanner
-
-QT = core
-
-SOURCES = main.cpp
-
-QT_FOR_CONFIG += bluetooth-private
-QMAKE_USE += bluez
-
-load(qt_tool)
-
-linux-*: {
- # bluetooth.h is not standards compliant
- CONFIG -= strict_c++
-}
diff --git a/sync.profile b/sync.profile
deleted file mode 100644
index 25363c70..00000000
--- a/sync.profile
+++ /dev/null
@@ -1,27 +0,0 @@
-%modules = ( # path to module name map
- "QtBluetooth" => "$basedir/src/bluetooth",
- "QtNfc" => "$basedir/src/nfc",
-);
-%moduleheaders = ( # restrict the module headers to those found in relative path
-);
-%deprecatedheaders = (
- "QtBluetooth" => {
- "qbluetoothglobal.h" => "QtBluetooth/qtbluetoothglobal.h"
- },
- "QtNfc" => {
- "qnfcglobal.h" => "QtNfc/qtnfcglobal.h"
- }
-);
-
-@ignore_for_include_check = (
-
- # BlueZ & OBEX auto-generated headers
- "adapter1_bluez5_p.h", "adapter_p.h", "agent_p.h", "device1_bluez5_p.h",
- "device_p.h", "manager_p.h", "obex_agent_p.h", "obex_client1_bluez5_p.h",
- "obex_client_p.h", "obex_manager_p.h", "obex_objectpush1_bluez5_p.h",
- "obex_transfer1_bluez5_p.h", "obex_transfer_p.h", "objectmanager_p.h",
- "profile1_p.h", "properties_p.h", "service_p.h", "gattchar1_p.h",
- "gattdesc1_p.h", "gattservice1_p.h", "profilemanager1_p.h", "battery1_p.h",
- # NFC auto-generated headers
- # Note: "adapter_p.h", "agent_p.h" and "manager_p.h" are duplicated here
- "dbusobjectmanager_p.h", "dbusproperties_p.h", "tag_p.h");
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 00000000..ddf3dbf6
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(QT_BUILD_STANDALONE_TESTS)
+ # Add qt_find_package calls for extra dependencies that need to be found when building
+ # the standalone tests here.
+endif()
+
+if(TARGET Qt::Bluetooth)
+ if(TARGET Qt::Quick)
+ add_subdirectory(bttestui)
+ endif()
+
+ add_subdirectory(bluetoothtestdevice)
+endif()
+
+qt_build_tests()
diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt
new file mode 100644
index 00000000..3b32a869
--- /dev/null
+++ b/tests/auto/CMakeLists.txt
@@ -0,0 +1,32 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(TARGET Qt::Bluetooth)
+ add_subdirectory(qbluetoothaddress)
+ add_subdirectory(qbluetoothdevicediscoveryagent)
+ add_subdirectory(qbluetoothdeviceinfo)
+ add_subdirectory(qbluetoothlocaldevice)
+ add_subdirectory(qbluetoothhostinfo)
+ add_subdirectory(qbluetoothservicediscoveryagent)
+ add_subdirectory(qbluetoothserviceinfo)
+ add_subdirectory(qbluetoothsocket)
+ add_subdirectory(qbluetoothuuid)
+ add_subdirectory(qbluetoothserver)
+ add_subdirectory(qlowenergycharacteristic)
+ add_subdirectory(qlowenergydescriptor)
+ add_subdirectory(qlowenergycontroller)
+ add_subdirectory(qlowenergycontroller-gattserver)
+ add_subdirectory(qlowenergyservice)
+endif()
+if(TARGET Qt::Nfc)
+ add_subdirectory(qndefmessage)
+ add_subdirectory(qndefrecord)
+ add_subdirectory(qnearfieldmanager)
+ add_subdirectory(qnearfieldtagtype1)
+ add_subdirectory(qnearfieldtagtype2)
+ add_subdirectory(qndefnfcsmartposterrecord)
+ add_subdirectory(qndeffilter)
+endif()
+if(TARGET Qt::Bluetooth AND TARGET Qt::Nfc)
+ add_subdirectory(cmake)
+endif()
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
deleted file mode 100644
index f1112240..00000000
--- a/tests/auto/auto.pro
+++ /dev/null
@@ -1,35 +0,0 @@
-TEMPLATE = subdirs
-
-SUBDIRS += \
- cmake
-
-qtHaveModule(bluetooth) {
- SUBDIRS += \
- qbluetoothaddress \
- qbluetoothdevicediscoveryagent \
- qbluetoothdeviceinfo \
- qbluetoothlocaldevice \
- qbluetoothhostinfo \
- qbluetoothservicediscoveryagent \
- qbluetoothserviceinfo \
- qbluetoothsocket \
- qbluetoothtransfermanager \
- qbluetoothtransferrequest \
- qbluetoothuuid \
- qbluetoothserver \
- qlowenergycharacteristic \
- qlowenergydescriptor \
- qlowenergycontroller \
- qlowenergycontroller-gattserver \
- qlowenergyservice
-}
-
-qtHaveModule(nfc) {
- SUBDIRS += \
- qndefmessage \
- qndefrecord \
- qnearfieldmanager \
- qnearfieldtagtype1 \
- qnearfieldtagtype2 \
- qndefnfcsmartposterrecord
-}
diff --git a/tests/auto/bic/data/QtBluetooth.5.14.0.linux-gcc-amd64.txt b/tests/auto/bic/data/QtBluetooth.5.14.0.linux-gcc-amd64.txt
new file mode 100644
index 00000000..d69a6b77
--- /dev/null
+++ b/tests/auto/bic/data/QtBluetooth.5.14.0.linux-gcc-amd64.txt
@@ -0,0 +1,5462 @@
+Class std::__failure_type
+ size=1 align=1
+ base size=0 base align=1
+std::__failure_type (0x0x7faa71123720) 0 empty
+
+Class std::__do_is_destructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_destructible_impl (0x0x7faa7117eea0) 0 empty
+
+Class std::__do_is_nt_destructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_nt_destructible_impl (0x0x7faa711a7120) 0 empty
+
+Class std::__do_is_default_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_default_constructible_impl (0x0x7faa711a7360) 0 empty
+
+Class std::__do_is_static_castable_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_static_castable_impl (0x0x7faa711a75a0) 0 empty
+
+Class std::__do_is_direct_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_direct_constructible_impl (0x0x7faa711a7720) 0 empty
+
+Class std::__do_is_nary_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_nary_constructible_impl (0x0x7faa711a7ae0) 0 empty
+
+Class std::__do_is_implicitly_default_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_implicitly_default_constructible_impl (0x0x7faa711e1c00) 0 empty
+
+Class std::__do_common_type_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_common_type_impl (0x0x7faa71268300) 0 empty
+
+Class std::__do_member_type_wrapper
+ size=1 align=1
+ base size=0 base align=1
+std::__do_member_type_wrapper (0x0x7faa712683c0) 0 empty
+
+Class std::__invoke_memfun_ref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memfun_ref (0x0x7faa71268780) 0 empty
+
+Class std::__invoke_memfun_deref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memfun_deref (0x0x7faa712687e0) 0 empty
+
+Class std::__invoke_memobj_ref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memobj_ref (0x0x7faa71268840) 0 empty
+
+Class std::__invoke_memobj_deref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memobj_deref (0x0x7faa712688a0) 0 empty
+
+Class std::__invoke_other
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_other (0x0x7faa71268900) 0 empty
+
+Class std::__result_of_memfun_ref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memfun_ref_impl (0x0x7faa712689c0) 0 empty
+
+Class std::__result_of_memfun_deref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memfun_deref_impl (0x0x7faa71268a80) 0 empty
+
+Class std::__result_of_memobj_ref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memobj_ref_impl (0x0x7faa71268b40) 0 empty
+
+Class std::__result_of_memobj_deref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memobj_deref_impl (0x0x7faa71268c00) 0 empty
+
+Class std::__result_of_other_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_other_impl (0x0x7faa71268f60) 0 empty
+
+Class std::__swappable_details::__do_is_swappable_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__swappable_details::__do_is_swappable_impl (0x0x7faa70ea2300) 0 empty
+
+Class std::__swappable_details::__do_is_nothrow_swappable_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__swappable_details::__do_is_nothrow_swappable_impl (0x0x7faa70ea2360) 0 empty
+
+Class std::__nonesuch
+ size=1 align=1
+ base size=0 base align=1
+std::__nonesuch (0x0x7faa70ea2900) 0 empty
+
+Class std::piecewise_construct_t
+ size=1 align=1
+ base size=0 base align=1
+std::piecewise_construct_t (0x0x7faa70ea2f60) 0 empty
+
+Class std::__nonesuch_no_braces
+ size=1 align=1
+ base size=1 base align=1
+std::__nonesuch_no_braces (0x0x7faa70ea5618) 0 empty
+ std::__nonesuch (0x0x7faa70ee7480) 0 empty
+
+Class std::__true_type
+ size=1 align=1
+ base size=0 base align=1
+std::__true_type (0x0x7faa70f36de0) 0 empty
+
+Class std::__false_type
+ size=1 align=1
+ base size=0 base align=1
+std::__false_type (0x0x7faa70f36e40) 0 empty
+
+Class std::input_iterator_tag
+ size=1 align=1
+ base size=0 base align=1
+std::input_iterator_tag (0x0x7faa70f96b40) 0 empty
+
+Class std::output_iterator_tag
+ size=1 align=1
+ base size=0 base align=1
+std::output_iterator_tag (0x0x7faa70f96ba0) 0 empty
+
+Class std::forward_iterator_tag
+ size=1 align=1
+ base size=1 base align=1
+std::forward_iterator_tag (0x0x7faa70ea5af8) 0 empty
+ std::input_iterator_tag (0x0x7faa70f96c00) 0 empty
+
+Class std::bidirectional_iterator_tag
+ size=1 align=1
+ base size=1 base align=1
+std::bidirectional_iterator_tag (0x0x7faa70ea5b60) 0 empty
+ std::forward_iterator_tag (0x0x7faa70ea5bc8) 0 empty
+ std::input_iterator_tag (0x0x7faa70f96c60) 0 empty
+
+Class std::random_access_iterator_tag
+ size=1 align=1
+ base size=1 base align=1
+std::random_access_iterator_tag (0x0x7faa70ea5c30) 0 empty
+ std::bidirectional_iterator_tag (0x0x7faa70ea5c98) 0 empty
+ std::forward_iterator_tag (0x0x7faa70ea5d00) 0 empty
+ std::input_iterator_tag (0x0x7faa70f96cc0) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_less_iter
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_less_iter (0x0x7faa710467e0) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_less_val
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_less_val (0x0x7faa71046900) 0 empty
+
+Class __gnu_cxx::__ops::_Val_less_iter
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Val_less_iter (0x0x7faa71046c00) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_equal_to_iter
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_equal_to_iter (0x0x7faa71046f00) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_equal_to_val
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_equal_to_val (0x0x7faa71077060) 0 empty
+
+Class __locale_struct
+ size=232 align=8
+ base size=232 base align=8
+__locale_struct (0x0x7faa70d01360) 0
+
+Class timeval
+ size=16 align=8
+ base size=16 base align=8
+timeval (0x0x7faa70d01660) 0
+
+Class timespec
+ size=16 align=8
+ base size=16 base align=8
+timespec (0x0x7faa70d016c0) 0
+
+Class __pthread_rwlock_arch_t
+ size=56 align=8
+ base size=56 base align=8
+__pthread_rwlock_arch_t (0x0x7faa70d01780) 0
+
+Class __pthread_internal_list
+ size=16 align=8
+ base size=16 base align=8
+__pthread_internal_list (0x0x7faa70d017e0) 0
+
+Class __pthread_mutex_s
+ size=40 align=8
+ base size=40 base align=8
+__pthread_mutex_s (0x0x7faa70d01840) 0
+
+Class __pthread_cond_s
+ size=48 align=8
+ base size=48 base align=8
+__pthread_cond_s (0x0x7faa70d018a0) 0
+
+Class pthread_attr_t
+ size=56 align=8
+ base size=56 base align=8
+pthread_attr_t (0x0x7faa70d01b40) 0
+
+Class random_data
+ size=48 align=8
+ base size=48 base align=8
+random_data (0x0x7faa70d01de0) 0
+
+Class drand48_data
+ size=24 align=8
+ base size=24 base align=8
+drand48_data (0x0x7faa70d01e40) 0
+
+Vtable for std::exception
+std::exception::_ZTVSt9exception: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt9exception)
+16 (int (*)(...))std::exception::~exception
+24 (int (*)(...))std::exception::~exception
+32 (int (*)(...))std::exception::what
+
+Class std::exception
+ size=8 align=8
+ base size=8 base align=8
+std::exception (0x0x7faa70d5cc00) 0 nearly-empty
+ vptr=((& std::exception::_ZTVSt9exception) + 16)
+
+Vtable for std::bad_exception
+std::bad_exception::_ZTVSt13bad_exception: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt13bad_exception)
+16 (int (*)(...))std::bad_exception::~bad_exception
+24 (int (*)(...))std::bad_exception::~bad_exception
+32 (int (*)(...))std::bad_exception::what
+
+Class std::bad_exception
+ size=8 align=8
+ base size=8 base align=8
+std::bad_exception (0x0x7faa71012068) 0 nearly-empty
+ vptr=((& std::bad_exception::_ZTVSt13bad_exception) + 16)
+ std::exception (0x0x7faa70d5cde0) 0 nearly-empty
+ primary-for std::bad_exception (0x0x7faa71012068)
+
+Vtable for std::type_info
+std::type_info::_ZTVSt9type_info: 8 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt9type_info)
+16 (int (*)(...))std::type_info::~type_info
+24 (int (*)(...))std::type_info::~type_info
+32 (int (*)(...))std::type_info::__is_pointer_p
+40 (int (*)(...))std::type_info::__is_function_p
+48 (int (*)(...))std::type_info::__do_catch
+56 (int (*)(...))std::type_info::__do_upcast
+
+Class std::type_info
+ size=16 align=8
+ base size=16 base align=8
+std::type_info (0x0x7faa70dfd000) 0
+ vptr=((& std::type_info::_ZTVSt9type_info) + 16)
+
+Vtable for std::bad_cast
+std::bad_cast::_ZTVSt8bad_cast: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt8bad_cast)
+16 (int (*)(...))std::bad_cast::~bad_cast
+24 (int (*)(...))std::bad_cast::~bad_cast
+32 (int (*)(...))std::bad_cast::what
+
+Class std::bad_cast
+ size=8 align=8
+ base size=8 base align=8
+std::bad_cast (0x0x7faa710120d0) 0 nearly-empty
+ vptr=((& std::bad_cast::_ZTVSt8bad_cast) + 16)
+ std::exception (0x0x7faa70dfd3c0) 0 nearly-empty
+ primary-for std::bad_cast (0x0x7faa710120d0)
+
+Vtable for std::bad_typeid
+std::bad_typeid::_ZTVSt10bad_typeid: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt10bad_typeid)
+16 (int (*)(...))std::bad_typeid::~bad_typeid
+24 (int (*)(...))std::bad_typeid::~bad_typeid
+32 (int (*)(...))std::bad_typeid::what
+
+Class std::bad_typeid
+ size=8 align=8
+ base size=8 base align=8
+std::bad_typeid (0x0x7faa71012138) 0 nearly-empty
+ vptr=((& std::bad_typeid::_ZTVSt10bad_typeid) + 16)
+ std::exception (0x0x7faa70dfd5a0) 0 nearly-empty
+ primary-for std::bad_typeid (0x0x7faa71012138)
+
+Class std::__exception_ptr::exception_ptr
+ size=8 align=8
+ base size=8 base align=8
+std::__exception_ptr::exception_ptr (0x0x7faa70dfd780) 0
+
+Vtable for std::nested_exception
+std::nested_exception::_ZTVSt16nested_exception: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt16nested_exception)
+16 (int (*)(...))std::nested_exception::~nested_exception
+24 (int (*)(...))std::nested_exception::~nested_exception
+
+Class std::nested_exception
+ size=16 align=8
+ base size=16 base align=8
+std::nested_exception (0x0x7faa70dfdd20) 0
+ vptr=((& std::nested_exception::_ZTVSt16nested_exception) + 16)
+
+Vtable for std::bad_alloc
+std::bad_alloc::_ZTVSt9bad_alloc: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt9bad_alloc)
+16 (int (*)(...))std::bad_alloc::~bad_alloc
+24 (int (*)(...))std::bad_alloc::~bad_alloc
+32 (int (*)(...))std::bad_alloc::what
+
+Class std::bad_alloc
+ size=8 align=8
+ base size=8 base align=8
+std::bad_alloc (0x0x7faa710121a0) 0 nearly-empty
+ vptr=((& std::bad_alloc::_ZTVSt9bad_alloc) + 16)
+ std::exception (0x0x7faa70e34420) 0 nearly-empty
+ primary-for std::bad_alloc (0x0x7faa710121a0)
+
+Vtable for std::bad_array_new_length
+std::bad_array_new_length::_ZTVSt20bad_array_new_length: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt20bad_array_new_length)
+16 (int (*)(...))std::bad_array_new_length::~bad_array_new_length
+24 (int (*)(...))std::bad_array_new_length::~bad_array_new_length
+32 (int (*)(...))std::bad_array_new_length::what
+
+Class std::bad_array_new_length
+ size=8 align=8
+ base size=8 base align=8
+std::bad_array_new_length (0x0x7faa71012208) 0 nearly-empty
+ vptr=((& std::bad_array_new_length::_ZTVSt20bad_array_new_length) + 16)
+ std::bad_alloc (0x0x7faa71012270) 0 nearly-empty
+ primary-for std::bad_array_new_length (0x0x7faa71012208)
+ std::exception (0x0x7faa70e34600) 0 nearly-empty
+ primary-for std::bad_alloc (0x0x7faa71012270)
+
+Class std::nothrow_t
+ size=1 align=1
+ base size=0 base align=1
+std::nothrow_t (0x0x7faa70e347e0) 0 empty
+
+Class std::__allocator_traits_base
+ size=1 align=1
+ base size=0 base align=1
+std::__allocator_traits_base (0x0x7faa70e349c0) 0 empty
+
+Class std::__numeric_limits_base
+ size=1 align=1
+ base size=0 base align=1
+std::__numeric_limits_base (0x0x7faa70aafea0) 0 empty
+
+Class QSysInfo
+ size=1 align=1
+ base size=0 base align=1
+QSysInfo (0x0x7faa70746420) 0 empty
+
+Class QMessageLogContext
+ size=32 align=8
+ base size=32 base align=8
+QMessageLogContext (0x0x7faa70746540) 0
+
+Class QMessageLogger
+ size=32 align=8
+ base size=32 base align=8
+QMessageLogger (0x0x7faa70746720) 0
+
+Class QFlag
+ size=4 align=4
+ base size=4 base align=4
+QFlag (0x0x7faa70746de0) 0
+
+Class QIncompatibleFlag
+ size=4 align=4
+ base size=4 base align=4
+QIncompatibleFlag (0x0x7faa707c35a0) 0
+
+Class std::__atomic_flag_base
+ size=1 align=1
+ base size=1 base align=1
+std::__atomic_flag_base (0x0x7faa7085aa80) 0
+
+Class std::atomic_flag
+ size=1 align=1
+ base size=1 base align=1
+std::atomic_flag (0x0x7faa7080b0d0) 0
+ std::__atomic_flag_base (0x0x7faa7085aae0) 0
+
+Class QAtomicInt
+ size=4 align=4
+ base size=4 base align=4
+QAtomicInt (0x0x7faa7080b820) 0
+ QAtomicInteger<int> (0x0x7faa7080b888) 0
+ QBasicAtomicInteger<int> (0x0x7faa70393d20) 0
+
+Class QInternal
+ size=1 align=1
+ base size=0 base align=1
+QInternal (0x0x7faa6ffe78a0) 0 empty
+
+Class QtPrivate::QSlotObjectBase
+ size=16 align=8
+ base size=16 base align=8
+QtPrivate::QSlotObjectBase (0x0x7faa70015e40) 0
+
+Class QGenericArgument
+ size=16 align=8
+ base size=16 base align=8
+QGenericArgument (0x0x7faa700635a0) 0
+
+Class QGenericReturnArgument
+ size=16 align=8
+ base size=16 base align=8
+QGenericReturnArgument (0x0x7faa700174e0) 0
+ QGenericArgument (0x0x7faa70063840) 0
+
+Class QMetaObject::SuperData
+ size=8 align=8
+ base size=8 base align=8
+QMetaObject::SuperData (0x0x7faa70063cc0) 0
+
+Class QMetaObject
+ size=48 align=8
+ base size=48 base align=8
+QMetaObject (0x0x7faa70063c60) 0
+
+Class QMetaObject::Connection
+ size=8 align=8
+ base size=8 base align=8
+QMetaObject::Connection (0x0x7faa6fcb75a0) 0
+
+Class QLatin1Char
+ size=1 align=1
+ base size=1 base align=1
+QLatin1Char (0x0x7faa6fd380c0) 0
+
+Class QChar
+ size=2 align=2
+ base size=2 base align=2
+QChar (0x0x7faa6fd387e0) 0
+
+Class QtPrivate::RefCount
+ size=4 align=4
+ base size=4 base align=4
+QtPrivate::RefCount (0x0x7faa6fe08600) 0
+
+Class QArrayData
+ size=24 align=8
+ base size=24 base align=8
+QArrayData (0x0x7faa6fe08960) 0
+
+Class QtPrivate::QContainerImplHelper
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::QContainerImplHelper (0x0x7faa6fe66c60) 0 empty
+
+Class lconv
+ size=96 align=8
+ base size=96 base align=8
+lconv (0x0x7faa6fb5c4e0) 0
+
+Vtable for __cxxabiv1::__forced_unwind
+__cxxabiv1::__forced_unwind::_ZTVN10__cxxabiv115__forced_unwindE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN10__cxxabiv115__forced_unwindE)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class __cxxabiv1::__forced_unwind
+ size=8 align=8
+ base size=8 base align=8
+__cxxabiv1::__forced_unwind (0x0x7faa6fb5c5a0) 0 nearly-empty
+ vptr=((& __cxxabiv1::__forced_unwind::_ZTVN10__cxxabiv115__forced_unwindE) + 16)
+
+Class sched_param
+ size=4 align=4
+ base size=4 base align=4
+sched_param (0x0x7faa6fc116c0) 0
+
+Class timex
+ size=208 align=8
+ base size=208 base align=8
+timex (0x0x7faa6fc11780) 0
+
+Class tm
+ size=56 align=8
+ base size=56 base align=8
+tm (0x0x7faa6fc117e0) 0
+
+Class itimerspec
+ size=32 align=8
+ base size=32 base align=8
+itimerspec (0x0x7faa6fc11840) 0
+
+Class _pthread_cleanup_buffer
+ size=32 align=8
+ base size=32 base align=8
+_pthread_cleanup_buffer (0x0x7faa6fc118a0) 0
+
+Class __pthread_cleanup_frame
+ size=24 align=8
+ base size=24 base align=8
+__pthread_cleanup_frame (0x0x7faa6fc119c0) 0
+
+Class __pthread_cleanup_class
+ size=24 align=8
+ base size=24 base align=8
+__pthread_cleanup_class (0x0x7faa6fc11a20) 0
+
+Class _IO_marker
+ size=24 align=8
+ base size=24 base align=8
+_IO_marker (0x0x7faa6f9519c0) 0
+
+Class _IO_FILE
+ size=216 align=8
+ base size=216 base align=8
+_IO_FILE (0x0x7faa6f951a20) 0
+
+Class std::_Hash_impl
+ size=1 align=1
+ base size=0 base align=1
+std::_Hash_impl (0x0x7faa6f70ea80) 0 empty
+
+Class std::_Fnv_hash_impl
+ size=1 align=1
+ base size=0 base align=1
+std::_Fnv_hash_impl (0x0x7faa6f70ec00) 0 empty
+
+Class std::locale
+ size=8 align=8
+ base size=8 base align=8
+std::locale (0x0x7faa6f880d80) 0
+
+Vtable for std::locale::facet
+std::locale::facet::_ZTVNSt6locale5facetE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt6locale5facetE)
+16 (int (*)(...))std::locale::facet::~facet
+24 (int (*)(...))std::locale::facet::~facet
+
+Class std::locale::facet
+ size=16 align=8
+ base size=12 base align=8
+std::locale::facet (0x0x7faa6f4d0180) 0
+ vptr=((& std::locale::facet::_ZTVNSt6locale5facetE) + 16)
+
+Class std::locale::id
+ size=8 align=8
+ base size=8 base align=8
+std::locale::id (0x0x7faa6f4d0420) 0
+
+Class std::locale::_Impl
+ size=40 align=8
+ base size=40 base align=8
+std::locale::_Impl (0x0x7faa6f4d0600) 0
+
+Class std::__cow_string
+ size=8 align=8
+ base size=8 base align=8
+std::__cow_string (0x0x7faa6f519600) 0
+
+Vtable for std::logic_error
+std::logic_error::_ZTVSt11logic_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt11logic_error)
+16 (int (*)(...))std::logic_error::~logic_error
+24 (int (*)(...))std::logic_error::~logic_error
+32 (int (*)(...))std::logic_error::what
+
+Class std::logic_error
+ size=16 align=8
+ base size=16 base align=8
+std::logic_error (0x0x7faa6f4f2478) 0
+ vptr=((& std::logic_error::_ZTVSt11logic_error) + 16)
+ std::exception (0x0x7faa6f5196c0) 0 nearly-empty
+ primary-for std::logic_error (0x0x7faa6f4f2478)
+
+Vtable for std::domain_error
+std::domain_error::_ZTVSt12domain_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12domain_error)
+16 (int (*)(...))std::domain_error::~domain_error
+24 (int (*)(...))std::domain_error::~domain_error
+32 (int (*)(...))std::logic_error::what
+
+Class std::domain_error
+ size=16 align=8
+ base size=16 base align=8
+std::domain_error (0x0x7faa6f4f24e0) 0
+ vptr=((& std::domain_error::_ZTVSt12domain_error) + 16)
+ std::logic_error (0x0x7faa6f4f2548) 0
+ primary-for std::domain_error (0x0x7faa6f4f24e0)
+ std::exception (0x0x7faa6f519720) 0 nearly-empty
+ primary-for std::logic_error (0x0x7faa6f4f2548)
+
+Vtable for std::invalid_argument
+std::invalid_argument::_ZTVSt16invalid_argument: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt16invalid_argument)
+16 (int (*)(...))std::invalid_argument::~invalid_argument
+24 (int (*)(...))std::invalid_argument::~invalid_argument
+32 (int (*)(...))std::logic_error::what
+
+Class std::invalid_argument
+ size=16 align=8
+ base size=16 base align=8
+std::invalid_argument (0x0x7faa6f4f25b0) 0
+ vptr=((& std::invalid_argument::_ZTVSt16invalid_argument) + 16)
+ std::logic_error (0x0x7faa6f4f2618) 0
+ primary-for std::invalid_argument (0x0x7faa6f4f25b0)
+ std::exception (0x0x7faa6f519780) 0 nearly-empty
+ primary-for std::logic_error (0x0x7faa6f4f2618)
+
+Vtable for std::length_error
+std::length_error::_ZTVSt12length_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12length_error)
+16 (int (*)(...))std::length_error::~length_error
+24 (int (*)(...))std::length_error::~length_error
+32 (int (*)(...))std::logic_error::what
+
+Class std::length_error
+ size=16 align=8
+ base size=16 base align=8
+std::length_error (0x0x7faa6f4f2680) 0
+ vptr=((& std::length_error::_ZTVSt12length_error) + 16)
+ std::logic_error (0x0x7faa6f4f26e8) 0
+ primary-for std::length_error (0x0x7faa6f4f2680)
+ std::exception (0x0x7faa6f5197e0) 0 nearly-empty
+ primary-for std::logic_error (0x0x7faa6f4f26e8)
+
+Vtable for std::out_of_range
+std::out_of_range::_ZTVSt12out_of_range: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12out_of_range)
+16 (int (*)(...))std::out_of_range::~out_of_range
+24 (int (*)(...))std::out_of_range::~out_of_range
+32 (int (*)(...))std::logic_error::what
+
+Class std::out_of_range
+ size=16 align=8
+ base size=16 base align=8
+std::out_of_range (0x0x7faa6f4f2750) 0
+ vptr=((& std::out_of_range::_ZTVSt12out_of_range) + 16)
+ std::logic_error (0x0x7faa6f4f27b8) 0
+ primary-for std::out_of_range (0x0x7faa6f4f2750)
+ std::exception (0x0x7faa6f519840) 0 nearly-empty
+ primary-for std::logic_error (0x0x7faa6f4f27b8)
+
+Vtable for std::runtime_error
+std::runtime_error::_ZTVSt13runtime_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt13runtime_error)
+16 (int (*)(...))std::runtime_error::~runtime_error
+24 (int (*)(...))std::runtime_error::~runtime_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::runtime_error
+ size=16 align=8
+ base size=16 base align=8
+std::runtime_error (0x0x7faa6f4f2820) 0
+ vptr=((& std::runtime_error::_ZTVSt13runtime_error) + 16)
+ std::exception (0x0x7faa6f5198a0) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7faa6f4f2820)
+
+Vtable for std::range_error
+std::range_error::_ZTVSt11range_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt11range_error)
+16 (int (*)(...))std::range_error::~range_error
+24 (int (*)(...))std::range_error::~range_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::range_error
+ size=16 align=8
+ base size=16 base align=8
+std::range_error (0x0x7faa6f4f2888) 0
+ vptr=((& std::range_error::_ZTVSt11range_error) + 16)
+ std::runtime_error (0x0x7faa6f4f28f0) 0
+ primary-for std::range_error (0x0x7faa6f4f2888)
+ std::exception (0x0x7faa6f519900) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7faa6f4f28f0)
+
+Vtable for std::overflow_error
+std::overflow_error::_ZTVSt14overflow_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt14overflow_error)
+16 (int (*)(...))std::overflow_error::~overflow_error
+24 (int (*)(...))std::overflow_error::~overflow_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::overflow_error
+ size=16 align=8
+ base size=16 base align=8
+std::overflow_error (0x0x7faa6f4f2958) 0
+ vptr=((& std::overflow_error::_ZTVSt14overflow_error) + 16)
+ std::runtime_error (0x0x7faa6f4f29c0) 0
+ primary-for std::overflow_error (0x0x7faa6f4f2958)
+ std::exception (0x0x7faa6f519960) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7faa6f4f29c0)
+
+Vtable for std::underflow_error
+std::underflow_error::_ZTVSt15underflow_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt15underflow_error)
+16 (int (*)(...))std::underflow_error::~underflow_error
+24 (int (*)(...))std::underflow_error::~underflow_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::underflow_error
+ size=16 align=8
+ base size=16 base align=8
+std::underflow_error (0x0x7faa6f4f2a28) 0
+ vptr=((& std::underflow_error::_ZTVSt15underflow_error) + 16)
+ std::runtime_error (0x0x7faa6f4f2a90) 0
+ primary-for std::underflow_error (0x0x7faa6f4f2a28)
+ std::exception (0x0x7faa6f5199c0) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7faa6f4f2a90)
+
+Vtable for std::_V2::error_category
+std::_V2::error_category::_ZTVNSt3_V214error_categoryE: 10 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt3_V214error_categoryE)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+40 (int (*)(...))std::_V2::error_category::_M_message
+48 (int (*)(...))__cxa_pure_virtual
+56 (int (*)(...))std::_V2::error_category::default_error_condition
+64 (int (*)(...))std::_V2::error_category::equivalent
+72 (int (*)(...))std::_V2::error_category::equivalent
+
+Class std::_V2::error_category
+ size=8 align=8
+ base size=8 base align=8
+std::_V2::error_category (0x0x7faa6f519b40) 0 nearly-empty
+ vptr=((& std::_V2::error_category::_ZTVNSt3_V214error_categoryE) + 16)
+
+Class std::error_code
+ size=16 align=8
+ base size=16 base align=8
+std::error_code (0x0x7faa6f519ea0) 0
+
+Class std::error_condition
+ size=16 align=8
+ base size=16 base align=8
+std::error_condition (0x0x7faa6f577720) 0
+
+Vtable for std::system_error
+std::system_error::_ZTVSt12system_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12system_error)
+16 (int (*)(...))std::system_error::~system_error
+24 (int (*)(...))std::system_error::~system_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::system_error
+ size=32 align=8
+ base size=32 base align=8
+std::system_error (0x0x7faa6f4f2ea0) 0
+ vptr=((& std::system_error::_ZTVSt12system_error) + 16)
+ std::runtime_error (0x0x7faa6f4f2f08) 0
+ primary-for std::system_error (0x0x7faa6f4f2ea0)
+ std::exception (0x0x7faa6f5a2300) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7faa6f4f2f08)
+
+Vtable for std::ios_base::failure
+std::ios_base::failure::_ZTVNSt8ios_base7failureB5cxx11E: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt8ios_base7failureB5cxx11E)
+16 (int (*)(...))std::ios_base::failure::~failure
+24 (int (*)(...))std::ios_base::failure::~failure
+32 (int (*)(...))std::ios_base::failure::what
+
+Class std::ios_base::failure
+ size=32 align=8
+ base size=32 base align=8
+std::ios_base::failure (0x0x7faa6f5cb1a0) 0
+ vptr=((& std::ios_base::failure::_ZTVNSt8ios_base7failureB5cxx11E) + 16)
+ std::system_error (0x0x7faa6f5cb208) 0
+ primary-for std::ios_base::failure (0x0x7faa6f5cb1a0)
+ std::runtime_error (0x0x7faa6f5cb270) 0
+ primary-for std::system_error (0x0x7faa6f5cb208)
+ std::exception (0x0x7faa6f5d48a0) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7faa6f5cb270)
+
+Class std::ios_base::_Callback_list
+ size=24 align=8
+ base size=24 base align=8
+std::ios_base::_Callback_list (0x0x7faa6f5d4900) 0
+
+Class std::ios_base::_Words
+ size=16 align=8
+ base size=16 base align=8
+std::ios_base::_Words (0x0x7faa6f5d4960) 0
+
+Class std::ios_base::Init
+ size=1 align=1
+ base size=0 base align=1
+std::ios_base::Init (0x0x7faa6f5d49c0) 0 empty
+
+Vtable for std::ios_base
+std::ios_base::_ZTVSt8ios_base: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt8ios_base)
+16 (int (*)(...))std::ios_base::~ios_base
+24 (int (*)(...))std::ios_base::~ios_base
+
+Class std::ios_base
+ size=216 align=8
+ base size=216 base align=8
+std::ios_base (0x0x7faa6f5d4840) 0
+ vptr=((& std::ios_base::_ZTVSt8ios_base) + 16)
+
+Class std::ctype_base
+ size=1 align=1
+ base size=0 base align=1
+std::ctype_base (0x0x7faa6f2c4300) 0 empty
+
+Class std::__num_base
+ size=1 align=1
+ base size=0 base align=1
+std::__num_base (0x0x7faa6f38f4e0) 0 empty
+
+VTT for std::basic_ostream<char>
+std::basic_ostream<char>::_ZTTSo: 2 entries
+0 ((& std::basic_ostream<char>::_ZTVSo) + 24)
+8 ((& std::basic_ostream<char>::_ZTVSo) + 64)
+
+VTT for std::basic_ostream<wchar_t>
+std::basic_ostream<wchar_t>::_ZTTSt13basic_ostreamIwSt11char_traitsIwEE: 2 entries
+0 ((& std::basic_ostream<wchar_t>::_ZTVSt13basic_ostreamIwSt11char_traitsIwEE) + 24)
+8 ((& std::basic_ostream<wchar_t>::_ZTVSt13basic_ostreamIwSt11char_traitsIwEE) + 64)
+
+VTT for std::basic_istream<char>
+std::basic_istream<char>::_ZTTSi: 2 entries
+0 ((& std::basic_istream<char>::_ZTVSi) + 24)
+8 ((& std::basic_istream<char>::_ZTVSi) + 64)
+
+VTT for std::basic_istream<wchar_t>
+std::basic_istream<wchar_t>::_ZTTSt13basic_istreamIwSt11char_traitsIwEE: 2 entries
+0 ((& std::basic_istream<wchar_t>::_ZTVSt13basic_istreamIwSt11char_traitsIwEE) + 24)
+8 ((& std::basic_istream<wchar_t>::_ZTVSt13basic_istreamIwSt11char_traitsIwEE) + 64)
+
+Construction vtable for std::basic_istream<char> (0x0x7faa6ef25958 instance) in std::basic_iostream<char>
+std::basic_iostream<char>::_ZTCSd0_Si: 10 entries
+0 24
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISi)
+24 0
+32 0
+40 18446744073709551592
+48 (int (*)(...))-24
+56 (int (*)(...))(& _ZTISi)
+64 0
+72 0
+
+Construction vtable for std::basic_ostream<char> (0x0x7faa6ef25a28 instance) in std::basic_iostream<char>
+std::basic_iostream<char>::_ZTCSd16_So: 10 entries
+0 8
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISo)
+24 0
+32 0
+40 18446744073709551608
+48 (int (*)(...))-8
+56 (int (*)(...))(& _ZTISo)
+64 0
+72 0
+
+VTT for std::basic_iostream<char>
+std::basic_iostream<char>::_ZTTSd: 7 entries
+0 ((& std::basic_iostream<char>::_ZTVSd) + 24)
+8 ((& std::basic_iostream<char>::_ZTCSd0_Si) + 24)
+16 ((& std::basic_iostream<char>::_ZTCSd0_Si) + 64)
+24 ((& std::basic_iostream<char>::_ZTCSd16_So) + 24)
+32 ((& std::basic_iostream<char>::_ZTCSd16_So) + 64)
+40 ((& std::basic_iostream<char>::_ZTVSd) + 104)
+48 ((& std::basic_iostream<char>::_ZTVSd) + 64)
+
+Construction vtable for std::basic_istream<wchar_t> (0x0x7faa6ef666e8 instance) in std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E: 10 entries
+0 24
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISt13basic_istreamIwSt11char_traitsIwEE)
+24 0
+32 0
+40 18446744073709551592
+48 (int (*)(...))-24
+56 (int (*)(...))(& _ZTISt13basic_istreamIwSt11char_traitsIwEE)
+64 0
+72 0
+
+Construction vtable for std::basic_ostream<wchar_t> (0x0x7faa6ef667b8 instance) in std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E: 10 entries
+0 8
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISt13basic_ostreamIwSt11char_traitsIwEE)
+24 0
+32 0
+40 18446744073709551608
+48 (int (*)(...))-8
+56 (int (*)(...))(& _ZTISt13basic_ostreamIwSt11char_traitsIwEE)
+64 0
+72 0
+
+VTT for std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTTSt14basic_iostreamIwSt11char_traitsIwEE: 7 entries
+0 ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 24)
+8 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E) + 24)
+16 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E) + 64)
+24 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E) + 24)
+32 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E) + 64)
+40 ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 104)
+48 ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 64)
+
+Class QByteArrayDataPtr
+ size=8 align=8
+ base size=8 base align=8
+QByteArrayDataPtr (0x0x7faa6ef6ae40) 0
+
+Class QByteArray
+ size=8 align=8
+ base size=8 base align=8
+QByteArray (0x0x7faa6ef6aea0) 0
+
+Class QByteRef
+ size=16 align=8
+ base size=12 base align=8
+QByteRef (0x0x7faa6ecd52a0) 0
+
+Class QStringDataPtr
+ size=8 align=8
+ base size=8 base align=8
+QStringDataPtr (0x0x7faa6ed71120) 0
+
+Class QStringView
+ size=16 align=8
+ base size=16 base align=8
+QStringView (0x0x7faa6ed715a0) 0
+
+Class QLatin1String
+ size=16 align=8
+ base size=16 base align=8
+QLatin1String (0x0x7faa6ee5c660) 0
+
+Class QString::Null
+ size=1 align=1
+ base size=0 base align=1
+QString::Null (0x0x7faa6eb07600) 0 empty
+
+Class QString
+ size=8 align=8
+ base size=8 base align=8
+QString (0x0x7faa6eb074e0) 0
+
+Class QCharRef
+ size=16 align=8
+ base size=12 base align=8
+QCharRef (0x0x7faa6e9e4480) 0
+
+Class QStringRef
+ size=16 align=8
+ base size=16 base align=8
+QStringRef (0x0x7faa6e765060) 0
+
+Class QtPrivate::ArgBase
+ size=1 align=1
+ base size=1 base align=1
+QtPrivate::ArgBase (0x0x7faa6e4c6e40) 0
+
+Class QtPrivate::QStringViewArg
+ size=24 align=8
+ base size=24 base align=8
+QtPrivate::QStringViewArg (0x0x7faa6e7f7618) 0
+ QtPrivate::ArgBase (0x0x7faa6e4c6ea0) 0
+
+Class QtPrivate::QLatin1StringArg
+ size=24 align=8
+ base size=24 base align=8
+QtPrivate::QLatin1StringArg (0x0x7faa6e7f7680) 0
+ QtPrivate::ArgBase (0x0x7faa6e5010c0) 0
+
+Class std::__erased_type
+ size=1 align=1
+ base size=0 base align=1
+std::__erased_type (0x0x7faa6e5c5000) 0 empty
+
+Class std::allocator_arg_t
+ size=1 align=1
+ base size=0 base align=1
+std::allocator_arg_t (0x0x7faa6e5c5060) 0 empty
+
+Class std::__uses_alloc_base
+ size=1 align=1
+ base size=0 base align=1
+std::__uses_alloc_base (0x0x7faa6e5c51e0) 0 empty
+
+Class std::__uses_alloc0::_Sink
+ size=1 align=1
+ base size=0 base align=1
+std::__uses_alloc0::_Sink (0x0x7faa6e5c52a0) 0 empty
+
+Class std::__uses_alloc0
+ size=1 align=1
+ base size=1 base align=1
+std::__uses_alloc0 (0x0x7faa6e7f7a28) 0
+ std::__uses_alloc_base (0x0x7faa6e5c5240) 0 empty
+
+Class std::_Swallow_assign
+ size=1 align=1
+ base size=0 base align=1
+std::_Swallow_assign (0x0x7faa6e32f600) 0 empty
+
+Vtable for std::bad_function_call
+std::bad_function_call::_ZTVSt17bad_function_call: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt17bad_function_call)
+16 (int (*)(...))std::bad_function_call::~bad_function_call
+24 (int (*)(...))std::bad_function_call::~bad_function_call
+32 (int (*)(...))std::bad_function_call::what
+
+Class std::bad_function_call
+ size=8 align=8
+ base size=8 base align=8
+std::bad_function_call (0x0x7faa6e2c3c98) 0 nearly-empty
+ vptr=((& std::bad_function_call::_ZTVSt17bad_function_call) + 16)
+ std::exception (0x0x7faa6e372f00) 0 nearly-empty
+ primary-for std::bad_function_call (0x0x7faa6e2c3c98)
+
+Class std::_Nocopy_types
+ size=16 align=8
+ base size=16 base align=8
+std::_Nocopy_types (0x0x7faa6e3a5000) 0
+
+Class std::_Any_data
+ size=16 align=8
+ base size=16 base align=8
+std::_Any_data (0x0x7faa6e3a5060) 0
+
+Class std::_Function_base
+ size=24 align=8
+ base size=24 base align=8
+std::_Function_base (0x0x7faa6e3a5360) 0
+
+Class QtPrivate::QHashCombine
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::QHashCombine (0x0x7faa6e1987e0) 0 empty
+
+Class QtPrivate::QHashCombineCommutative
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::QHashCombineCommutative (0x0x7faa6e1988a0) 0 empty
+
+Class std::_Bit_reference
+ size=16 align=8
+ base size=16 base align=8
+std::_Bit_reference (0x0x7faa6deca000) 0
+
+Class std::_Bit_iterator_base
+ size=16 align=8
+ base size=12 base align=8
+std::_Bit_iterator_base (0x0x7faa6e1eb820) 0
+ std::iterator<std::random_access_iterator_tag, bool> (0x0x7faa6deca720) 0 empty
+
+Class std::_Bit_iterator
+ size=16 align=8
+ base size=12 base align=8
+std::_Bit_iterator (0x0x7faa6e1eb958) 0
+ std::_Bit_iterator_base (0x0x7faa6e1eb9c0) 0
+ std::iterator<std::random_access_iterator_tag, bool> (0x0x7faa6decad80) 0 empty
+
+Class std::_Bit_const_iterator
+ size=16 align=8
+ base size=12 base align=8
+std::_Bit_const_iterator (0x0x7faa6e1eba28) 0
+ std::_Bit_iterator_base (0x0x7faa6e1eba90) 0
+ std::iterator<std::random_access_iterator_tag, bool> (0x0x7faa6df025a0) 0 empty
+
+Class std::__detail::_List_node_base
+ size=16 align=8
+ base size=16 base align=8
+std::__detail::_List_node_base (0x0x7faa6dd4c120) 0
+
+Class QListData::NotArrayCompatibleLayout
+ size=1 align=1
+ base size=0 base align=1
+QListData::NotArrayCompatibleLayout (0x0x7faa6ddfbea0) 0 empty
+
+Class QListData::NotIndirectLayout
+ size=1 align=1
+ base size=0 base align=1
+QListData::NotIndirectLayout (0x0x7faa6ddfbf00) 0 empty
+
+Class QListData::ArrayCompatibleLayout
+ size=1 align=1
+ base size=1 base align=1
+QListData::ArrayCompatibleLayout (0x0x7faa6e0265b0) 0 empty
+ QListData::NotIndirectLayout (0x0x7faa6ddfbf60) 0 empty
+
+Class QListData::InlineWithPaddingLayout
+ size=1 align=1
+ base size=1 base align=1
+QListData::InlineWithPaddingLayout (0x0x7faa6dd668c0) 0 empty
+ QListData::NotArrayCompatibleLayout (0x0x7faa6de12000) 0 empty
+ QListData::NotIndirectLayout (0x0x7faa6de12060) 0 empty
+
+Class QListData::IndirectLayout
+ size=1 align=1
+ base size=1 base align=1
+QListData::IndirectLayout (0x0x7faa6e026618) 0 empty
+ QListData::NotArrayCompatibleLayout (0x0x7faa6de120c0) 0 empty
+
+Class QListData::Data
+ size=24 align=8
+ base size=24 base align=8
+QListData::Data (0x0x7faa6de12120) 0
+
+Class QListData
+ size=8 align=8
+ base size=8 base align=8
+QListData (0x0x7faa6ddfbe40) 0
+
+Class QRegExp
+ size=8 align=8
+ base size=8 base align=8
+QRegExp (0x0x7faa6db0d2a0) 0
+
+Class QStringMatcher::Data
+ size=272 align=8
+ base size=272 base align=8
+QStringMatcher::Data (0x0x7faa6dbe97e0) 0
+
+Class QStringMatcher
+ size=1048 align=8
+ base size=1048 base align=8
+QStringMatcher (0x0x7faa6dbe9780) 0
+
+Class QStringList
+ size=8 align=8
+ base size=8 base align=8
+QStringList (0x0x7faa6dbee2d8) 0
+ QList<QString> (0x0x7faa6dbee340) 0
+ QListSpecialMethods<QString> (0x0x7faa6dbe9a20) 0 empty
+
+Class QScopedPointerPodDeleter
+ size=1 align=1
+ base size=0 base align=1
+QScopedPointerPodDeleter (0x0x7faa6d8b9960) 0 empty
+
+Class std::_Rb_tree_node_base
+ size=32 align=8
+ base size=32 base align=8
+std::_Rb_tree_node_base (0x0x7faa6d94dba0) 0
+
+Class std::_Rb_tree_header
+ size=40 align=8
+ base size=40 base align=8
+std::_Rb_tree_header (0x0x7faa6d94df00) 0
+
+Class QtPrivate::AbstractDebugStreamFunction
+ size=16 align=8
+ base size=16 base align=8
+QtPrivate::AbstractDebugStreamFunction (0x0x7faa6d6ab540) 0
+
+Class QtPrivate::AbstractComparatorFunction
+ size=24 align=8
+ base size=24 base align=8
+QtPrivate::AbstractComparatorFunction (0x0x7faa6d6ab8a0) 0
+
+Class QtPrivate::AbstractConverterFunction
+ size=8 align=8
+ base size=8 base align=8
+QtPrivate::AbstractConverterFunction (0x0x7faa6d6abde0) 0
+
+Class QMetaType
+ size=80 align=8
+ base size=80 base align=8
+QMetaType (0x0x7faa6d6d2360) 0
+
+Class QtMetaTypePrivate::VariantData
+ size=24 align=8
+ base size=20 base align=8
+QtMetaTypePrivate::VariantData (0x0x7faa6d73b540) 0
+
+Class QtMetaTypePrivate::VectorBoolElements
+ size=1 align=1
+ base size=0 base align=1
+QtMetaTypePrivate::VectorBoolElements (0x0x7faa6d73bc00) 0 empty
+
+Class QtMetaTypePrivate::QSequentialIterableImpl
+ size=104 align=8
+ base size=104 base align=8
+QtMetaTypePrivate::QSequentialIterableImpl (0x0x7faa6d390a80) 0
+
+Class QtMetaTypePrivate::QAssociativeIterableImpl
+ size=112 align=8
+ base size=112 base align=8
+QtMetaTypePrivate::QAssociativeIterableImpl (0x0x7faa6d44d180) 0
+
+Class QtMetaTypePrivate::QPairVariantInterfaceImpl
+ size=40 align=8
+ base size=40 base align=8
+QtMetaTypePrivate::QPairVariantInterfaceImpl (0x0x7faa6d4a26c0) 0
+
+Class std::chrono::_V2::system_clock
+ size=1 align=1
+ base size=0 base align=1
+std::chrono::_V2::system_clock (0x0x7faa6d337c60) 0 empty
+
+Class std::chrono::_V2::steady_clock
+ size=1 align=1
+ base size=0 base align=1
+std::chrono::_V2::steady_clock (0x0x7faa6d06d720) 0 empty
+
+Vtable for QObjectData
+QObjectData::_ZTV11QObjectData: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QObjectData)
+16 (int (*)(...))__cxa_pure_virtual
+24 (int (*)(...))__cxa_pure_virtual
+
+Class QObjectData
+ size=48 align=8
+ base size=48 base align=8
+QObjectData (0x0x7faa6d06d780) 0
+ vptr=((& QObjectData::_ZTV11QObjectData) + 16)
+
+Class QObject::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QObject::QPrivateSignal (0x0x7faa6d06d960) 0 empty
+
+Vtable for QObject
+QObject::_ZTV7QObject: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI7QObject)
+16 (int (*)(...))QObject::metaObject
+24 (int (*)(...))QObject::qt_metacast
+32 (int (*)(...))QObject::qt_metacall
+40 (int (*)(...))QObject::~QObject
+48 (int (*)(...))QObject::~QObject
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QObject
+ size=16 align=8
+ base size=16 base align=8
+QObject (0x0x7faa6d06d900) 0
+ vptr=((& QObject::_ZTV7QObject) + 16)
+
+Vtable for QObjectUserData
+QObjectUserData::_ZTV15QObjectUserData: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QObjectUserData)
+16 (int (*)(...))QObjectUserData::~QObjectUserData
+24 (int (*)(...))QObjectUserData::~QObjectUserData
+
+Class QObjectUserData
+ size=8 align=8
+ base size=8 base align=8
+QObjectUserData (0x0x7faa6d150780) 0 nearly-empty
+ vptr=((& QObjectUserData::_ZTV15QObjectUserData) + 16)
+
+Class QSignalBlocker
+ size=16 align=8
+ base size=10 base align=8
+QSignalBlocker (0x0x7faa6d150900) 0
+
+Class QAbstractAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractAnimation::QPrivateSignal (0x0x7faa6d1721e0) 0 empty
+
+Vtable for QAbstractAnimation
+QAbstractAnimation::_ZTV18QAbstractAnimation: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QAbstractAnimation)
+16 (int (*)(...))QAbstractAnimation::metaObject
+24 (int (*)(...))QAbstractAnimation::qt_metacast
+32 (int (*)(...))QAbstractAnimation::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAbstractAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QAbstractAnimation
+ size=16 align=8
+ base size=16 base align=8
+QAbstractAnimation (0x0x7faa6d152478) 0
+ vptr=((& QAbstractAnimation::_ZTV18QAbstractAnimation) + 16)
+ QObject (0x0x7faa6d172180) 0
+ primary-for QAbstractAnimation (0x0x7faa6d152478)
+
+Class QAnimationDriver::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAnimationDriver::QPrivateSignal (0x0x7faa6d1725a0) 0 empty
+
+Vtable for QAnimationDriver
+QAnimationDriver::_ZTV16QAnimationDriver: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QAnimationDriver)
+16 (int (*)(...))QAnimationDriver::metaObject
+24 (int (*)(...))QAnimationDriver::qt_metacast
+32 (int (*)(...))QAnimationDriver::qt_metacall
+40 (int (*)(...))QAnimationDriver::~QAnimationDriver
+48 (int (*)(...))QAnimationDriver::~QAnimationDriver
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAnimationDriver::advance
+120 (int (*)(...))QAnimationDriver::elapsed
+128 (int (*)(...))QAnimationDriver::start
+136 (int (*)(...))QAnimationDriver::stop
+
+Class QAnimationDriver
+ size=16 align=8
+ base size=16 base align=8
+QAnimationDriver (0x0x7faa6d1524e0) 0
+ vptr=((& QAnimationDriver::_ZTV16QAnimationDriver) + 16)
+ QObject (0x0x7faa6d172540) 0
+ primary-for QAnimationDriver (0x0x7faa6d1524e0)
+
+Class QEventLoop::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QEventLoop::QPrivateSignal (0x0x7faa6d1727e0) 0 empty
+
+Vtable for QEventLoop
+QEventLoop::_ZTV10QEventLoop: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QEventLoop)
+16 (int (*)(...))QEventLoop::metaObject
+24 (int (*)(...))QEventLoop::qt_metacast
+32 (int (*)(...))QEventLoop::qt_metacall
+40 (int (*)(...))QEventLoop::~QEventLoop
+48 (int (*)(...))QEventLoop::~QEventLoop
+56 (int (*)(...))QEventLoop::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QEventLoop
+ size=16 align=8
+ base size=16 base align=8
+QEventLoop (0x0x7faa6d152548) 0
+ vptr=((& QEventLoop::_ZTV10QEventLoop) + 16)
+ QObject (0x0x7faa6d172780) 0
+ primary-for QEventLoop (0x0x7faa6d152548)
+
+Class QEventLoopLocker
+ size=8 align=8
+ base size=8 base align=8
+QEventLoopLocker (0x0x7faa6cdcf0c0) 0
+
+Class QAbstractEventDispatcher::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractEventDispatcher::QPrivateSignal (0x0x7faa6cdcf180) 0 empty
+
+Class QAbstractEventDispatcher::TimerInfo
+ size=12 align=4
+ base size=12 base align=4
+QAbstractEventDispatcher::TimerInfo (0x0x7faa6cdcf1e0) 0
+
+Vtable for QAbstractEventDispatcher
+QAbstractEventDispatcher::_ZTV24QAbstractEventDispatcher: 28 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI24QAbstractEventDispatcher)
+16 (int (*)(...))QAbstractEventDispatcher::metaObject
+24 (int (*)(...))QAbstractEventDispatcher::qt_metacast
+32 (int (*)(...))QAbstractEventDispatcher::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))__cxa_pure_virtual
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))__cxa_pure_virtual
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))__cxa_pure_virtual
+176 (int (*)(...))__cxa_pure_virtual
+184 (int (*)(...))__cxa_pure_virtual
+192 (int (*)(...))__cxa_pure_virtual
+200 (int (*)(...))__cxa_pure_virtual
+208 (int (*)(...))QAbstractEventDispatcher::startingUp
+216 (int (*)(...))QAbstractEventDispatcher::closingDown
+
+Class QAbstractEventDispatcher
+ size=16 align=8
+ base size=16 base align=8
+QAbstractEventDispatcher (0x0x7faa6d152680) 0
+ vptr=((& QAbstractEventDispatcher::_ZTV24QAbstractEventDispatcher) + 16)
+ QObject (0x0x7faa6cdcf120) 0
+ primary-for QAbstractEventDispatcher (0x0x7faa6d152680)
+
+Class QMapNodeBase
+ size=24 align=8
+ base size=24 base align=8
+QMapNodeBase (0x0x7faa6ce261e0) 0
+
+Class QMapDataBase
+ size=40 align=8
+ base size=40 base align=8
+QMapDataBase (0x0x7faa6ce26e40) 0
+
+Class QHashData::Node
+ size=16 align=8
+ base size=16 base align=8
+QHashData::Node (0x0x7faa6cf1a7e0) 0
+
+Class QHashData
+ size=48 align=8
+ base size=44 base align=8
+QHashData (0x0x7faa6cf1a780) 0
+
+Class QHashDummyValue
+ size=1 align=1
+ base size=0 base align=1
+QHashDummyValue (0x0x7faa6cf1aa80) 0 empty
+
+Class QVariant::PrivateShared
+ size=16 align=8
+ base size=12 base align=8
+QVariant::PrivateShared (0x0x7faa6cc4a1e0) 0
+
+Class QVariant::Private::Data
+ size=8 align=8
+ base size=8 base align=8
+QVariant::Private::Data (0x0x7faa6cc4a2a0) 0
+
+Class QVariant::Private
+ size=16 align=8
+ base size=12 base align=8
+QVariant::Private (0x0x7faa6cc4a240) 0
+
+Class QVariant::Handler
+ size=72 align=8
+ base size=72 base align=8
+QVariant::Handler (0x0x7faa6cc4a300) 0
+
+Class QVariant
+ size=16 align=8
+ base size=16 base align=8
+QVariant (0x0x7faa6cc4a180) 0
+
+Class QVariantComparisonHelper
+ size=8 align=8
+ base size=8 base align=8
+QVariantComparisonHelper (0x0x7faa6c9ac5a0) 0
+
+Class QSequentialIterable::const_iterator
+ size=112 align=8
+ base size=112 base align=8
+QSequentialIterable::const_iterator (0x0x7faa6c9f1c00) 0
+
+Class QSequentialIterable
+ size=104 align=8
+ base size=104 base align=8
+QSequentialIterable (0x0x7faa6c9f1ba0) 0
+
+Class QAssociativeIterable::const_iterator
+ size=120 align=8
+ base size=120 base align=8
+QAssociativeIterable::const_iterator (0x0x7faa6c9f1d20) 0
+
+Class QAssociativeIterable
+ size=112 align=8
+ base size=112 base align=8
+QAssociativeIterable (0x0x7faa6c9f1cc0) 0
+
+Class QModelIndex
+ size=24 align=8
+ base size=24 base align=8
+QModelIndex (0x0x7faa6cabbea0) 0
+
+Class QPersistentModelIndex
+ size=8 align=8
+ base size=8 base align=8
+QPersistentModelIndex (0x0x7faa6cb2dae0) 0
+
+Class QAbstractItemModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractItemModel::QPrivateSignal (0x0x7faa6c7fd900) 0 empty
+
+Vtable for QAbstractItemModel
+QAbstractItemModel::_ZTV18QAbstractItemModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QAbstractItemModel)
+16 (int (*)(...))QAbstractItemModel::metaObject
+24 (int (*)(...))QAbstractItemModel::qt_metacast
+32 (int (*)(...))QAbstractItemModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractItemModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))QAbstractItemModel::hasChildren
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))QAbstractItemModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractItemModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractItemModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractItemModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractItemModel (0x0x7faa6c806820) 0
+ vptr=((& QAbstractItemModel::_ZTV18QAbstractItemModel) + 16)
+ QObject (0x0x7faa6c7fd8a0) 0
+ primary-for QAbstractItemModel (0x0x7faa6c806820)
+
+Class QAbstractTableModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractTableModel::QPrivateSignal (0x0x7faa6c875cc0) 0 empty
+
+Vtable for QAbstractTableModel
+QAbstractTableModel::_ZTV19QAbstractTableModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QAbstractTableModel)
+16 (int (*)(...))QAbstractTableModel::metaObject
+24 (int (*)(...))QAbstractTableModel::qt_metacast
+32 (int (*)(...))QAbstractTableModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractTableModel::index
+120 (int (*)(...))QAbstractTableModel::parent
+128 (int (*)(...))QAbstractTableModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))QAbstractTableModel::hasChildren
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))QAbstractItemModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractTableModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractTableModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractTableModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractTableModel (0x0x7faa6c806e38) 0
+ vptr=((& QAbstractTableModel::_ZTV19QAbstractTableModel) + 16)
+ QAbstractItemModel (0x0x7faa6c806ea0) 0
+ primary-for QAbstractTableModel (0x0x7faa6c806e38)
+ QObject (0x0x7faa6c875c60) 0
+ primary-for QAbstractItemModel (0x0x7faa6c806ea0)
+
+Class QAbstractListModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractListModel::QPrivateSignal (0x0x7faa6c875e40) 0 empty
+
+Vtable for QAbstractListModel
+QAbstractListModel::_ZTV18QAbstractListModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QAbstractListModel)
+16 (int (*)(...))QAbstractListModel::metaObject
+24 (int (*)(...))QAbstractListModel::qt_metacast
+32 (int (*)(...))QAbstractListModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractListModel::index
+120 (int (*)(...))QAbstractListModel::parent
+128 (int (*)(...))QAbstractListModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))QAbstractListModel::columnCount
+152 (int (*)(...))QAbstractListModel::hasChildren
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))QAbstractItemModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractListModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractListModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractListModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractListModel (0x0x7faa6c806f08) 0
+ vptr=((& QAbstractListModel::_ZTV18QAbstractListModel) + 16)
+ QAbstractItemModel (0x0x7faa6c806f70) 0
+ primary-for QAbstractListModel (0x0x7faa6c806f08)
+ QObject (0x0x7faa6c875de0) 0
+ primary-for QAbstractItemModel (0x0x7faa6c806f70)
+
+Vtable for QAbstractNativeEventFilter
+QAbstractNativeEventFilter::_ZTV26QAbstractNativeEventFilter: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI26QAbstractNativeEventFilter)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractNativeEventFilter
+ size=16 align=8
+ base size=16 base align=8
+QAbstractNativeEventFilter (0x0x7faa6c8fc5a0) 0
+ vptr=((& QAbstractNativeEventFilter::_ZTV26QAbstractNativeEventFilter) + 16)
+
+Class QAbstractProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractProxyModel::QPrivateSignal (0x0x7faa6c8fc660) 0 empty
+
+Vtable for QAbstractProxyModel
+QAbstractProxyModel::_ZTV19QAbstractProxyModel: 53 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QAbstractProxyModel)
+16 (int (*)(...))QAbstractProxyModel::metaObject
+24 (int (*)(...))QAbstractProxyModel::qt_metacast
+32 (int (*)(...))QAbstractProxyModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractProxyModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))QAbstractProxyModel::hasChildren
+160 (int (*)(...))QAbstractProxyModel::data
+168 (int (*)(...))QAbstractProxyModel::setData
+176 (int (*)(...))QAbstractProxyModel::headerData
+184 (int (*)(...))QAbstractProxyModel::setHeaderData
+192 (int (*)(...))QAbstractProxyModel::itemData
+200 (int (*)(...))QAbstractProxyModel::setItemData
+208 (int (*)(...))QAbstractProxyModel::mimeTypes
+216 (int (*)(...))QAbstractProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QAbstractProxyModel::dropMimeData
+240 (int (*)(...))QAbstractProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractProxyModel::fetchMore
+312 (int (*)(...))QAbstractProxyModel::canFetchMore
+320 (int (*)(...))QAbstractProxyModel::flags
+328 (int (*)(...))QAbstractProxyModel::sort
+336 (int (*)(...))QAbstractProxyModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QAbstractProxyModel::setSourceModel
+392 (int (*)(...))__cxa_pure_virtual
+400 (int (*)(...))__cxa_pure_virtual
+408 (int (*)(...))QAbstractProxyModel::mapSelectionToSource
+416 (int (*)(...))QAbstractProxyModel::mapSelectionFromSource
+
+Class QAbstractProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractProxyModel (0x0x7faa6c90d068) 0
+ vptr=((& QAbstractProxyModel::_ZTV19QAbstractProxyModel) + 16)
+ QAbstractItemModel (0x0x7faa6c90d0d0) 0
+ primary-for QAbstractProxyModel (0x0x7faa6c90d068)
+ QObject (0x0x7faa6c8fc600) 0
+ primary-for QAbstractItemModel (0x0x7faa6c90d0d0)
+
+Class QAbstractState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractState::QPrivateSignal (0x0x7faa6c8fc8a0) 0 empty
+
+Vtable for QAbstractState
+QAbstractState::_ZTV14QAbstractState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI14QAbstractState)
+16 (int (*)(...))QAbstractState::metaObject
+24 (int (*)(...))QAbstractState::qt_metacast
+32 (int (*)(...))QAbstractState::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAbstractState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractState
+ size=16 align=8
+ base size=16 base align=8
+QAbstractState (0x0x7faa6c90d138) 0
+ vptr=((& QAbstractState::_ZTV14QAbstractState) + 16)
+ QObject (0x0x7faa6c8fc840) 0
+ primary-for QAbstractState (0x0x7faa6c90d138)
+
+Class QAbstractTransition::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractTransition::QPrivateSignal (0x0x7faa6c8fcae0) 0 empty
+
+Vtable for QAbstractTransition
+QAbstractTransition::_ZTV19QAbstractTransition: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QAbstractTransition)
+16 (int (*)(...))QAbstractTransition::metaObject
+24 (int (*)(...))QAbstractTransition::qt_metacast
+32 (int (*)(...))QAbstractTransition::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAbstractTransition::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractTransition
+ size=16 align=8
+ base size=16 base align=8
+QAbstractTransition (0x0x7faa6c90d1a0) 0
+ vptr=((& QAbstractTransition::_ZTV19QAbstractTransition) + 16)
+ QObject (0x0x7faa6c8fca80) 0
+ primary-for QAbstractTransition (0x0x7faa6c90d1a0)
+
+Class QAnimationGroup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAnimationGroup::QPrivateSignal (0x0x7faa6c8fcde0) 0 empty
+
+Vtable for QAnimationGroup
+QAnimationGroup::_ZTV15QAnimationGroup: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QAnimationGroup)
+16 (int (*)(...))QAnimationGroup::metaObject
+24 (int (*)(...))QAnimationGroup::qt_metacast
+32 (int (*)(...))QAnimationGroup::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAnimationGroup::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QAnimationGroup
+ size=16 align=8
+ base size=16 base align=8
+QAnimationGroup (0x0x7faa6c90d208) 0
+ vptr=((& QAnimationGroup::_ZTV15QAnimationGroup) + 16)
+ QAbstractAnimation (0x0x7faa6c90d270) 0
+ primary-for QAnimationGroup (0x0x7faa6c90d208)
+ QObject (0x0x7faa6c8fcd80) 0
+ primary-for QAbstractAnimation (0x0x7faa6c90d270)
+
+Class QBasicTimer
+ size=4 align=4
+ base size=4 base align=4
+QBasicTimer (0x0x7faa6c5d0120) 0
+
+Class QBitArray
+ size=8 align=8
+ base size=8 base align=8
+QBitArray (0x0x7faa6c64fa80) 0
+
+Class QBitRef
+ size=16 align=8
+ base size=12 base align=8
+QBitRef (0x0x7faa6c6a1f00) 0
+
+Class QIODevice::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QIODevice::QPrivateSignal (0x0x7faa6c7161e0) 0 empty
+
+Vtable for QIODevice
+QIODevice::_ZTV9QIODevice: 30 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QIODevice)
+16 (int (*)(...))QIODevice::metaObject
+24 (int (*)(...))QIODevice::qt_metacast
+32 (int (*)(...))QIODevice::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QIODevice::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QIODevice::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QIODevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))__cxa_pure_virtual
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))__cxa_pure_virtual
+
+Class QIODevice
+ size=16 align=8
+ base size=16 base align=8
+QIODevice (0x0x7faa6c70c820) 0
+ vptr=((& QIODevice::_ZTV9QIODevice) + 16)
+ QObject (0x0x7faa6c716180) 0
+ primary-for QIODevice (0x0x7faa6c70c820)
+
+Class QBuffer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QBuffer::QPrivateSignal (0x0x7faa6c716b40) 0 empty
+
+Vtable for QBuffer
+QBuffer::_ZTV7QBuffer: 30 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI7QBuffer)
+16 (int (*)(...))QBuffer::metaObject
+24 (int (*)(...))QBuffer::qt_metacast
+32 (int (*)(...))QBuffer::qt_metacall
+40 (int (*)(...))QBuffer::~QBuffer
+48 (int (*)(...))QBuffer::~QBuffer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QBuffer::connectNotify
+104 (int (*)(...))QBuffer::disconnectNotify
+112 (int (*)(...))QIODevice::isSequential
+120 (int (*)(...))QBuffer::open
+128 (int (*)(...))QBuffer::close
+136 (int (*)(...))QBuffer::pos
+144 (int (*)(...))QBuffer::size
+152 (int (*)(...))QBuffer::seek
+160 (int (*)(...))QBuffer::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QBuffer::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QBuffer::readData
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QBuffer::writeData
+
+Class QBuffer
+ size=16 align=8
+ base size=16 base align=8
+QBuffer (0x0x7faa6c70c958) 0
+ vptr=((& QBuffer::_ZTV7QBuffer) + 16)
+ QIODevice (0x0x7faa6c70c9c0) 0
+ primary-for QBuffer (0x0x7faa6c70c958)
+ QObject (0x0x7faa6c716ae0) 0
+ primary-for QIODevice (0x0x7faa6c70c9c0)
+
+Class QByteArrayMatcher::Data
+ size=272 align=8
+ base size=272 base align=8
+QByteArrayMatcher::Data (0x0x7faa6c716de0) 0
+
+Class QByteArrayMatcher
+ size=1040 align=8
+ base size=1040 base align=8
+QByteArrayMatcher (0x0x7faa6c716d80) 0
+
+Class QStaticByteArrayMatcherBase::Skiptable
+ size=256 align=1
+ base size=256 base align=1
+QStaticByteArrayMatcherBase::Skiptable (0x0x7faa6c716f60) 0
+
+Class QStaticByteArrayMatcherBase
+ size=256 align=16
+ base size=256 base align=16
+QStaticByteArrayMatcherBase (0x0x7faa6c716f00) 0
+
+Class QSharedData
+ size=4 align=4
+ base size=4 base align=4
+QSharedData (0x0x7faa6c77ce40) 0
+
+Class QLocale
+ size=8 align=8
+ base size=8 base align=8
+QLocale (0x0x7faa6c3dad20) 0
+
+Class QCalendar::YearMonthDay
+ size=12 align=4
+ base size=12 base align=4
+QCalendar::YearMonthDay (0x0x7faa6c567240) 0
+
+Class QCalendar
+ size=8 align=8
+ base size=8 base align=8
+QCalendar (0x0x7faa6c5671e0) 0
+
+Class QDate
+ size=8 align=8
+ base size=8 base align=8
+QDate (0x0x7faa6c567a20) 0
+
+Class QTime
+ size=4 align=4
+ base size=4 base align=4
+QTime (0x0x7faa6c1ed300) 0
+
+Class QDateTime::ShortData
+ size=8 align=8
+ base size=8 base align=8
+QDateTime::ShortData (0x0x7faa6c23df60) 0
+
+Class QDateTime::Data
+ size=8 align=8
+ base size=8 base align=8
+QDateTime::Data (0x0x7faa6c258000) 0
+
+Class QDateTime
+ size=8 align=8
+ base size=8 base align=8
+QDateTime (0x0x7faa6c23df00) 0
+
+Vtable for QTextStream
+QTextStream::_ZTV11QTextStream: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QTextStream)
+16 (int (*)(...))QTextStream::~QTextStream
+24 (int (*)(...))QTextStream::~QTextStream
+
+Class QTextStream
+ size=16 align=8
+ base size=16 base align=8
+QTextStream (0x0x7faa6c32e6c0) 0
+ vptr=((& QTextStream::_ZTV11QTextStream) + 16)
+
+Class QTextStreamManipulator
+ size=40 align=8
+ base size=38 base align=8
+QTextStreamManipulator (0x0x7faa6c32ef60) 0
+
+Class QContiguousCacheData
+ size=24 align=4
+ base size=24 base align=4
+QContiguousCacheData (0x0x7faa6bffdc00) 0
+
+Vtable for __gnu_cxx::__concurrence_lock_error
+__gnu_cxx::__concurrence_lock_error::_ZTVN9__gnu_cxx24__concurrence_lock_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx24__concurrence_lock_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_lock_error::~__concurrence_lock_error
+24 (int (*)(...))__gnu_cxx::__concurrence_lock_error::~__concurrence_lock_error
+32 (int (*)(...))__gnu_cxx::__concurrence_lock_error::what
+
+Class __gnu_cxx::__concurrence_lock_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_lock_error (0x0x7faa6c32d9c0) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_lock_error::_ZTVN9__gnu_cxx24__concurrence_lock_errorE) + 16)
+ std::exception (0x0x7faa6c04ca80) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_lock_error (0x0x7faa6c32d9c0)
+
+Vtable for __gnu_cxx::__concurrence_unlock_error
+__gnu_cxx::__concurrence_unlock_error::_ZTVN9__gnu_cxx26__concurrence_unlock_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx26__concurrence_unlock_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_unlock_error::~__concurrence_unlock_error
+24 (int (*)(...))__gnu_cxx::__concurrence_unlock_error::~__concurrence_unlock_error
+32 (int (*)(...))__gnu_cxx::__concurrence_unlock_error::what
+
+Class __gnu_cxx::__concurrence_unlock_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_unlock_error (0x0x7faa6c32da28) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_unlock_error::_ZTVN9__gnu_cxx26__concurrence_unlock_errorE) + 16)
+ std::exception (0x0x7faa6c04cba0) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_unlock_error (0x0x7faa6c32da28)
+
+Vtable for __gnu_cxx::__concurrence_broadcast_error
+__gnu_cxx::__concurrence_broadcast_error::_ZTVN9__gnu_cxx29__concurrence_broadcast_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx29__concurrence_broadcast_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::~__concurrence_broadcast_error
+24 (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::~__concurrence_broadcast_error
+32 (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::what
+
+Class __gnu_cxx::__concurrence_broadcast_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_broadcast_error (0x0x7faa6c32da90) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_broadcast_error::_ZTVN9__gnu_cxx29__concurrence_broadcast_errorE) + 16)
+ std::exception (0x0x7faa6c04ccc0) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_broadcast_error (0x0x7faa6c32da90)
+
+Vtable for __gnu_cxx::__concurrence_wait_error
+__gnu_cxx::__concurrence_wait_error::_ZTVN9__gnu_cxx24__concurrence_wait_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx24__concurrence_wait_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_wait_error::~__concurrence_wait_error
+24 (int (*)(...))__gnu_cxx::__concurrence_wait_error::~__concurrence_wait_error
+32 (int (*)(...))__gnu_cxx::__concurrence_wait_error::what
+
+Class __gnu_cxx::__concurrence_wait_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_wait_error (0x0x7faa6c32db60) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_wait_error::_ZTVN9__gnu_cxx24__concurrence_wait_errorE) + 16)
+ std::exception (0x0x7faa6c04cde0) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_wait_error (0x0x7faa6c32db60)
+
+Class __gnu_cxx::__mutex
+ size=40 align=8
+ base size=40 base align=8
+__gnu_cxx::__mutex (0x0x7faa6c076e40) 0
+
+Class __gnu_cxx::__recursive_mutex
+ size=40 align=8
+ base size=40 base align=8
+__gnu_cxx::__recursive_mutex (0x0x7faa6c09a180) 0
+
+Class __gnu_cxx::__scoped_lock
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__scoped_lock (0x0x7faa6c09a480) 0
+
+Class __gnu_cxx::__cond
+ size=48 align=8
+ base size=48 base align=8
+__gnu_cxx::__cond (0x0x7faa6c09a7e0) 0
+
+Vtable for std::bad_weak_ptr
+std::bad_weak_ptr::_ZTVSt12bad_weak_ptr: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12bad_weak_ptr)
+16 (int (*)(...))std::bad_weak_ptr::~bad_weak_ptr
+24 (int (*)(...))std::bad_weak_ptr::~bad_weak_ptr
+32 (int (*)(...))std::bad_weak_ptr::what
+
+Class std::bad_weak_ptr
+ size=8 align=8
+ base size=8 base align=8
+std::bad_weak_ptr (0x0x7faa6c32dbc8) 0 nearly-empty
+ vptr=((& std::bad_weak_ptr::_ZTVSt12bad_weak_ptr) + 16)
+ std::exception (0x0x7faa6c1119c0) 0 nearly-empty
+ primary-for std::bad_weak_ptr (0x0x7faa6c32dbc8)
+
+Class std::_Sp_make_shared_tag
+ size=1 align=1
+ base size=0 base align=1
+std::_Sp_make_shared_tag (0x0x7faa6c17e960) 0 empty
+
+Class std::__sp_array_delete
+ size=1 align=1
+ base size=0 base align=1
+std::__sp_array_delete (0x0x7faa6c17ed80) 0 empty
+
+Class std::_Sp_locker
+ size=2 align=1
+ base size=2 base align=1
+std::_Sp_locker (0x0x7faa6beb5c00) 0
+
+Class QtSharedPointer::NormalDeleter
+ size=1 align=1
+ base size=0 base align=1
+QtSharedPointer::NormalDeleter (0x0x7faa6bf17120) 0 empty
+
+Class QtSharedPointer::ExternalRefCountData
+ size=16 align=8
+ base size=16 base align=8
+QtSharedPointer::ExternalRefCountData (0x0x7faa6bf172a0) 0
+
+Class QtPrivate::EnableInternalData
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::EnableInternalData (0x0x7faa6bf77ba0) 0 empty
+
+Class QDebug::Stream
+ size=80 align=8
+ base size=76 base align=8
+QDebug::Stream (0x0x7faa6bbcf2a0) 0
+
+Class QDebug
+ size=8 align=8
+ base size=8 base align=8
+QDebug (0x0x7faa6bbcf240) 0
+
+Class QDebugStateSaver
+ size=8 align=8
+ base size=8 base align=8
+QDebugStateSaver (0x0x7faa6bd3eba0) 0
+
+Class QNoDebug
+ size=1 align=1
+ base size=0 base align=1
+QNoDebug (0x0x7faa6bd3ec60) 0 empty
+
+Class QCborError
+ size=4 align=4
+ base size=4 base align=4
+QCborError (0x0x7faa6b9beea0) 0
+
+Class QRegularExpression
+ size=8 align=8
+ base size=8 base align=8
+QRegularExpression (0x0x7faa6b9f0660) 0
+
+Class QRegularExpressionMatch
+ size=8 align=8
+ base size=8 base align=8
+QRegularExpressionMatch (0x0x7faa6ba9e540) 0
+
+Class QRegularExpressionMatchIterator
+ size=8 align=8
+ base size=8 base align=8
+QRegularExpressionMatchIterator (0x0x7faa6bb06300) 0
+
+Class QUrl
+ size=8 align=8
+ base size=8 base align=8
+QUrl (0x0x7faa6bb59d20) 0
+
+Class QUuid
+ size=16 align=4
+ base size=16 base align=4
+QUuid (0x0x7faa6b89fcc0) 0
+
+Class QCborParserError
+ size=16 align=8
+ base size=12 base align=8
+QCborParserError (0x0x7faa6b933840) 0
+
+Class QCborValue
+ size=24 align=8
+ base size=20 base align=8
+QCborValue (0x0x7faa6b933900) 0
+
+Class QCborValueRef
+ size=16 align=8
+ base size=16 base align=8
+QCborValueRef (0x0x7faa6b3b24e0) 0
+
+Class QCborArray::Iterator
+ size=16 align=8
+ base size=16 base align=8
+QCborArray::Iterator (0x0x7faa6b423f00) 0
+
+Class QCborArray::ConstIterator
+ size=16 align=8
+ base size=16 base align=8
+QCborArray::ConstIterator (0x0x7faa6b423f60) 0
+
+Class QCborArray
+ size=8 align=8
+ base size=8 base align=8
+QCborArray (0x0x7faa6b423ea0) 0
+
+Class QCborMap::Iterator
+ size=16 align=8
+ base size=16 base align=8
+QCborMap::Iterator (0x0x7faa6b1aab40) 0
+
+Class QCborMap::ConstIterator
+ size=16 align=8
+ base size=16 base align=8
+QCborMap::ConstIterator (0x0x7faa6b1aaba0) 0
+
+Class QCborMap
+ size=8 align=8
+ base size=8 base align=8
+QCborMap (0x0x7faa6b1aaae0) 0
+
+Class qfloat16::Wrap
+ size=2 align=2
+ base size=2 base align=2
+qfloat16::Wrap (0x0x7faa6afc8360) 0
+
+Class qfloat16
+ size=2 align=2
+ base size=2 base align=2
+qfloat16 (0x0x7faa6afc8300) 0
+
+Class QCborStreamWriter
+ size=8 align=8
+ base size=8 base align=8
+QCborStreamWriter (0x0x7faa6b0b5000) 0
+
+Class QCborStreamReader
+ size=24 align=8
+ base size=20 base align=8
+QCborStreamReader (0x0x7faa6b0b5d20) 0
+
+Class QCollatorSortKey
+ size=8 align=8
+ base size=8 base align=8
+QCollatorSortKey (0x0x7faa6b14ae40) 0
+
+Class QCollator
+ size=8 align=8
+ base size=8 base align=8
+QCollator (0x0x7faa6b175060) 0
+
+Class QCommandLineOption
+ size=8 align=8
+ base size=8 base align=8
+QCommandLineOption (0x0x7faa6ae64660) 0
+
+Vtable for QEvent
+QEvent::_ZTV6QEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI6QEvent)
+16 (int (*)(...))QEvent::~QEvent
+24 (int (*)(...))QEvent::~QEvent
+
+Class QEvent
+ size=24 align=8
+ base size=20 base align=8
+QEvent (0x0x7faa6af26ba0) 0
+ vptr=((& QEvent::_ZTV6QEvent) + 16)
+
+Vtable for QTimerEvent
+QTimerEvent::_ZTV11QTimerEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QTimerEvent)
+16 (int (*)(...))QTimerEvent::~QTimerEvent
+24 (int (*)(...))QTimerEvent::~QTimerEvent
+
+Class QTimerEvent
+ size=24 align=8
+ base size=24 base align=8
+QTimerEvent (0x0x7faa6af25618) 0
+ vptr=((& QTimerEvent::_ZTV11QTimerEvent) + 16)
+ QEvent (0x0x7faa6af26f60) 0
+ primary-for QTimerEvent (0x0x7faa6af25618)
+
+Vtable for QChildEvent
+QChildEvent::_ZTV11QChildEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QChildEvent)
+16 (int (*)(...))QChildEvent::~QChildEvent
+24 (int (*)(...))QChildEvent::~QChildEvent
+
+Class QChildEvent
+ size=32 align=8
+ base size=32 base align=8
+QChildEvent (0x0x7faa6af25680) 0
+ vptr=((& QChildEvent::_ZTV11QChildEvent) + 16)
+ QEvent (0x0x7faa6af70060) 0
+ primary-for QChildEvent (0x0x7faa6af25680)
+
+Vtable for QDynamicPropertyChangeEvent
+QDynamicPropertyChangeEvent::_ZTV27QDynamicPropertyChangeEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI27QDynamicPropertyChangeEvent)
+16 (int (*)(...))QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent
+24 (int (*)(...))QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent
+
+Class QDynamicPropertyChangeEvent
+ size=32 align=8
+ base size=32 base align=8
+QDynamicPropertyChangeEvent (0x0x7faa6af25bc8) 0
+ vptr=((& QDynamicPropertyChangeEvent::_ZTV27QDynamicPropertyChangeEvent) + 16)
+ QEvent (0x0x7faa6af706c0) 0
+ primary-for QDynamicPropertyChangeEvent (0x0x7faa6af25bc8)
+
+Vtable for QDeferredDeleteEvent
+QDeferredDeleteEvent::_ZTV20QDeferredDeleteEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QDeferredDeleteEvent)
+16 (int (*)(...))QDeferredDeleteEvent::~QDeferredDeleteEvent
+24 (int (*)(...))QDeferredDeleteEvent::~QDeferredDeleteEvent
+
+Class QDeferredDeleteEvent
+ size=24 align=8
+ base size=24 base align=8
+QDeferredDeleteEvent (0x0x7faa6af25c30) 0
+ vptr=((& QDeferredDeleteEvent::_ZTV20QDeferredDeleteEvent) + 16)
+ QEvent (0x0x7faa6af70780) 0
+ primary-for QDeferredDeleteEvent (0x0x7faa6af25c30)
+
+Class QCoreApplication::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QCoreApplication::QPrivateSignal (0x0x7faa6af708a0) 0 empty
+
+Vtable for QCoreApplication
+QCoreApplication::_ZTV16QCoreApplication: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QCoreApplication)
+16 (int (*)(...))QCoreApplication::metaObject
+24 (int (*)(...))QCoreApplication::qt_metacast
+32 (int (*)(...))QCoreApplication::qt_metacall
+40 (int (*)(...))QCoreApplication::~QCoreApplication
+48 (int (*)(...))QCoreApplication::~QCoreApplication
+56 (int (*)(...))QCoreApplication::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QCoreApplication::notify
+120 (int (*)(...))QCoreApplication::compressEvent
+
+Class QCoreApplication
+ size=16 align=8
+ base size=16 base align=8
+QCoreApplication (0x0x7faa6af25c98) 0
+ vptr=((& QCoreApplication::_ZTV16QCoreApplication) + 16)
+ QObject (0x0x7faa6af70840) 0
+ primary-for QCoreApplication (0x0x7faa6af25c98)
+
+Class QCommandLineParser
+ size=8 align=8
+ base size=8 base align=8
+QCommandLineParser (0x0x7faa6af70ae0) 0
+
+Class QConcatenateTablesProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QConcatenateTablesProxyModel::QPrivateSignal (0x0x7faa6af70c60) 0 empty
+
+Vtable for QConcatenateTablesProxyModel
+QConcatenateTablesProxyModel::_ZTV28QConcatenateTablesProxyModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI28QConcatenateTablesProxyModel)
+16 (int (*)(...))QConcatenateTablesProxyModel::metaObject
+24 (int (*)(...))QConcatenateTablesProxyModel::qt_metacast
+32 (int (*)(...))QConcatenateTablesProxyModel::qt_metacall
+40 (int (*)(...))QConcatenateTablesProxyModel::~QConcatenateTablesProxyModel
+48 (int (*)(...))QConcatenateTablesProxyModel::~QConcatenateTablesProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QConcatenateTablesProxyModel::index
+120 (int (*)(...))QConcatenateTablesProxyModel::parent
+128 (int (*)(...))QAbstractItemModel::sibling
+136 (int (*)(...))QConcatenateTablesProxyModel::rowCount
+144 (int (*)(...))QConcatenateTablesProxyModel::columnCount
+152 (int (*)(...))QAbstractItemModel::hasChildren
+160 (int (*)(...))QConcatenateTablesProxyModel::data
+168 (int (*)(...))QConcatenateTablesProxyModel::setData
+176 (int (*)(...))QConcatenateTablesProxyModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QConcatenateTablesProxyModel::itemData
+200 (int (*)(...))QConcatenateTablesProxyModel::setItemData
+208 (int (*)(...))QConcatenateTablesProxyModel::mimeTypes
+216 (int (*)(...))QConcatenateTablesProxyModel::mimeData
+224 (int (*)(...))QConcatenateTablesProxyModel::canDropMimeData
+232 (int (*)(...))QConcatenateTablesProxyModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QConcatenateTablesProxyModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QConcatenateTablesProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QConcatenateTablesProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QConcatenateTablesProxyModel (0x0x7faa6af25d00) 0
+ vptr=((& QConcatenateTablesProxyModel::_ZTV28QConcatenateTablesProxyModel) + 16)
+ QAbstractItemModel (0x0x7faa6af25d68) 0
+ primary-for QConcatenateTablesProxyModel (0x0x7faa6af25d00)
+ QObject (0x0x7faa6af70c00) 0
+ primary-for QAbstractItemModel (0x0x7faa6af25d68)
+
+Class QCryptographicHash
+ size=8 align=8
+ base size=8 base align=8
+QCryptographicHash (0x0x7faa6af70e40) 0
+
+Class QDataStream
+ size=32 align=8
+ base size=32 base align=8
+QDataStream (0x0x7faa6af70f60) 0
+
+Class QtPrivate::StreamStateSaver
+ size=16 align=8
+ base size=12 base align=8
+QtPrivate::StreamStateSaver (0x0x7faa6abf3120) 0
+
+Class QElapsedTimer
+ size=16 align=8
+ base size=16 base align=8
+QElapsedTimer (0x0x7faa6ac2f840) 0
+
+Class QDeadlineTimer
+ size=16 align=8
+ base size=16 base align=8
+QDeadlineTimer (0x0x7faa6ac2ff60) 0
+
+Class QFileDevice::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFileDevice::QPrivateSignal (0x0x7faa6ad81c60) 0 empty
+
+Vtable for QFileDevice
+QFileDevice::_ZTV11QFileDevice: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QFileDevice)
+16 (int (*)(...))QFileDevice::metaObject
+24 (int (*)(...))QFileDevice::qt_metacast
+32 (int (*)(...))QFileDevice::qt_metacall
+40 (int (*)(...))QFileDevice::~QFileDevice
+48 (int (*)(...))QFileDevice::~QFileDevice
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QFileDevice::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFileDevice::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QFileDevice::writeData
+240 (int (*)(...))QFileDevice::fileName
+248 (int (*)(...))QFileDevice::resize
+256 (int (*)(...))QFileDevice::permissions
+264 (int (*)(...))QFileDevice::setPermissions
+
+Class QFileDevice
+ size=16 align=8
+ base size=16 base align=8
+QFileDevice (0x0x7faa6ad79f70) 0
+ vptr=((& QFileDevice::_ZTV11QFileDevice) + 16)
+ QIODevice (0x0x7faa6a998000) 0
+ primary-for QFileDevice (0x0x7faa6ad79f70)
+ QObject (0x0x7faa6ad81c00) 0
+ primary-for QIODevice (0x0x7faa6a998000)
+
+Class QFile::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFile::QPrivateSignal (0x0x7faa6a9cc5a0) 0 empty
+
+Vtable for QFile
+QFile::_ZTV5QFile: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI5QFile)
+16 (int (*)(...))QFile::metaObject
+24 (int (*)(...))QFile::qt_metacast
+32 (int (*)(...))QFile::qt_metacall
+40 (int (*)(...))QFile::~QFile
+48 (int (*)(...))QFile::~QFile
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QFile::open
+128 (int (*)(...))QFileDevice::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFile::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QFileDevice::writeData
+240 (int (*)(...))QFile::fileName
+248 (int (*)(...))QFile::resize
+256 (int (*)(...))QFile::permissions
+264 (int (*)(...))QFile::setPermissions
+
+Class QFile
+ size=16 align=8
+ base size=16 base align=8
+QFile (0x0x7faa6a998138) 0
+ vptr=((& QFile::_ZTV5QFile) + 16)
+ QFileDevice (0x0x7faa6a9981a0) 0
+ primary-for QFile (0x0x7faa6a998138)
+ QIODevice (0x0x7faa6a998208) 0
+ primary-for QFileDevice (0x0x7faa6a9981a0)
+ QObject (0x0x7faa6a9cc540) 0
+ primary-for QIODevice (0x0x7faa6a998208)
+
+Class QFileInfo
+ size=8 align=8
+ base size=8 base align=8
+QFileInfo (0x0x7faa6a9ccc00) 0
+
+Class QDir
+ size=8 align=8
+ base size=8 base align=8
+QDir (0x0x7faa6aac3ae0) 0
+
+Class QDirIterator
+ size=8 align=8
+ base size=8 base align=8
+QDirIterator (0x0x7faa6a7deae0) 0
+
+Class QEasingCurve
+ size=8 align=8
+ base size=8 base align=8
+QEasingCurve (0x0x7faa6a8352a0) 0
+
+Class QEventTransition::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QEventTransition::QPrivateSignal (0x0x7faa6a9333c0) 0 empty
+
+Vtable for QEventTransition
+QEventTransition::_ZTV16QEventTransition: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QEventTransition)
+16 (int (*)(...))QEventTransition::metaObject
+24 (int (*)(...))QEventTransition::qt_metacast
+32 (int (*)(...))QEventTransition::qt_metacall
+40 (int (*)(...))QEventTransition::~QEventTransition
+48 (int (*)(...))QEventTransition::~QEventTransition
+56 (int (*)(...))QEventTransition::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QEventTransition::eventTest
+120 (int (*)(...))QEventTransition::onTransition
+
+Class QEventTransition
+ size=16 align=8
+ base size=16 base align=8
+QEventTransition (0x0x7faa6a8e8ea0) 0
+ vptr=((& QEventTransition::_ZTV16QEventTransition) + 16)
+ QAbstractTransition (0x0x7faa6a8e8f08) 0
+ primary-for QEventTransition (0x0x7faa6a8e8ea0)
+ QObject (0x0x7faa6a933360) 0
+ primary-for QAbstractTransition (0x0x7faa6a8e8f08)
+
+Vtable for QException
+QException::_ZTV10QException: 7 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QException)
+16 (int (*)(...))QException::~QException
+24 (int (*)(...))QException::~QException
+32 (int (*)(...))std::exception::what
+40 (int (*)(...))QException::raise
+48 (int (*)(...))QException::clone
+
+Class QException
+ size=8 align=8
+ base size=8 base align=8
+QException (0x0x7faa6a8e8f70) 0 nearly-empty
+ vptr=((& QException::_ZTV10QException) + 16)
+ std::exception (0x0x7faa6a9335a0) 0 nearly-empty
+ primary-for QException (0x0x7faa6a8e8f70)
+
+Vtable for QUnhandledException
+QUnhandledException::_ZTV19QUnhandledException: 7 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QUnhandledException)
+16 (int (*)(...))QUnhandledException::~QUnhandledException
+24 (int (*)(...))QUnhandledException::~QUnhandledException
+32 (int (*)(...))std::exception::what
+40 (int (*)(...))QUnhandledException::raise
+48 (int (*)(...))QUnhandledException::clone
+
+Class QUnhandledException
+ size=8 align=8
+ base size=8 base align=8
+QUnhandledException (0x0x7faa6a95a000) 0 nearly-empty
+ vptr=((& QUnhandledException::_ZTV19QUnhandledException) + 16)
+ QException (0x0x7faa6a95a068) 0 nearly-empty
+ primary-for QUnhandledException (0x0x7faa6a95a000)
+ std::exception (0x0x7faa6a933600) 0 nearly-empty
+ primary-for QException (0x0x7faa6a95a068)
+
+Class QtPrivate::ExceptionHolder
+ size=8 align=8
+ base size=8 base align=8
+QtPrivate::ExceptionHolder (0x0x7faa6a933660) 0
+
+Class QtPrivate::ExceptionStore
+ size=8 align=8
+ base size=8 base align=8
+QtPrivate::ExceptionStore (0x0x7faa6a933720) 0
+
+Vtable for QFactoryInterface
+QFactoryInterface::_ZTV17QFactoryInterface: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QFactoryInterface)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class QFactoryInterface
+ size=8 align=8
+ base size=8 base align=8
+QFactoryInterface (0x0x7faa6a933780) 0 nearly-empty
+ vptr=((& QFactoryInterface::_ZTV17QFactoryInterface) + 16)
+
+Class QFileSelector::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFileSelector::QPrivateSignal (0x0x7faa6a9339c0) 0 empty
+
+Vtable for QFileSelector
+QFileSelector::_ZTV13QFileSelector: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QFileSelector)
+16 (int (*)(...))QFileSelector::metaObject
+24 (int (*)(...))QFileSelector::qt_metacast
+32 (int (*)(...))QFileSelector::qt_metacall
+40 (int (*)(...))QFileSelector::~QFileSelector
+48 (int (*)(...))QFileSelector::~QFileSelector
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QFileSelector
+ size=16 align=8
+ base size=16 base align=8
+QFileSelector (0x0x7faa6a95a0d0) 0
+ vptr=((& QFileSelector::_ZTV13QFileSelector) + 16)
+ QObject (0x0x7faa6a933960) 0
+ primary-for QFileSelector (0x0x7faa6a95a0d0)
+
+Class QFileSystemWatcher::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFileSystemWatcher::QPrivateSignal (0x0x7faa6a933c00) 0 empty
+
+Vtable for QFileSystemWatcher
+QFileSystemWatcher::_ZTV18QFileSystemWatcher: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QFileSystemWatcher)
+16 (int (*)(...))QFileSystemWatcher::metaObject
+24 (int (*)(...))QFileSystemWatcher::qt_metacast
+32 (int (*)(...))QFileSystemWatcher::qt_metacall
+40 (int (*)(...))QFileSystemWatcher::~QFileSystemWatcher
+48 (int (*)(...))QFileSystemWatcher::~QFileSystemWatcher
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QFileSystemWatcher
+ size=16 align=8
+ base size=16 base align=8
+QFileSystemWatcher (0x0x7faa6a95a138) 0
+ vptr=((& QFileSystemWatcher::_ZTV18QFileSystemWatcher) + 16)
+ QObject (0x0x7faa6a933ba0) 0
+ primary-for QFileSystemWatcher (0x0x7faa6a95a138)
+
+Class QFinalState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFinalState::QPrivateSignal (0x0x7faa6a933e40) 0 empty
+
+Vtable for QFinalState
+QFinalState::_ZTV11QFinalState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QFinalState)
+16 (int (*)(...))QFinalState::metaObject
+24 (int (*)(...))QFinalState::qt_metacast
+32 (int (*)(...))QFinalState::qt_metacall
+40 (int (*)(...))QFinalState::~QFinalState
+48 (int (*)(...))QFinalState::~QFinalState
+56 (int (*)(...))QFinalState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFinalState::onEntry
+120 (int (*)(...))QFinalState::onExit
+
+Class QFinalState
+ size=16 align=8
+ base size=16 base align=8
+QFinalState (0x0x7faa6a95a1a0) 0
+ vptr=((& QFinalState::_ZTV11QFinalState) + 16)
+ QAbstractState (0x0x7faa6a95a208) 0
+ primary-for QFinalState (0x0x7faa6a95a1a0)
+ QObject (0x0x7faa6a933de0) 0
+ primary-for QAbstractState (0x0x7faa6a95a208)
+
+Vtable for QRunnable
+QRunnable::_ZTV9QRunnable: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QRunnable)
+16 (int (*)(...))__cxa_pure_virtual
+24 0
+32 0
+
+Class QRunnable
+ size=16 align=8
+ base size=12 base align=8
+QRunnable (0x0x7faa6a556060) 0
+ vptr=((& QRunnable::_ZTV9QRunnable) + 16)
+
+Class QBasicMutex
+ size=8 align=8
+ base size=8 base align=8
+QBasicMutex (0x0x7faa6a556300) 0
+
+Class QMutex
+ size=8 align=8
+ base size=8 base align=8
+QMutex (0x0x7faa6a95a2d8) 0
+ QBasicMutex (0x0x7faa6a556f60) 0
+
+Class QRecursiveMutex
+ size=8 align=8
+ base size=8 base align=8
+QRecursiveMutex (0x0x7faa6a95a340) 0
+ QMutex (0x0x7faa6a95a3a8) 0
+ QBasicMutex (0x0x7faa6a5df1e0) 0
+
+Class QMutexLocker
+ size=8 align=8
+ base size=8 base align=8
+QMutexLocker (0x0x7faa6a5df240) 0
+
+Class QtPrivate::ResultItem
+ size=16 align=8
+ base size=16 base align=8
+QtPrivate::ResultItem (0x0x7faa6a5df840) 0
+
+Class QtPrivate::ResultIteratorBase
+ size=16 align=8
+ base size=12 base align=8
+QtPrivate::ResultIteratorBase (0x0x7faa6a5dfe40) 0
+
+Vtable for QtPrivate::ResultStoreBase
+QtPrivate::ResultStoreBase::_ZTVN9QtPrivate15ResultStoreBaseE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9QtPrivate15ResultStoreBaseE)
+16 (int (*)(...))QtPrivate::ResultStoreBase::~ResultStoreBase
+24 (int (*)(...))QtPrivate::ResultStoreBase::~ResultStoreBase
+
+Class QtPrivate::ResultStoreBase
+ size=48 align=8
+ base size=44 base align=8
+QtPrivate::ResultStoreBase (0x0x7faa6a62f060) 0
+ vptr=((& QtPrivate::ResultStoreBase::_ZTVN9QtPrivate15ResultStoreBaseE) + 16)
+
+Class std::__mutex_base
+ size=40 align=8
+ base size=40 base align=8
+std::__mutex_base (0x0x7faa6a67c840) 0
+
+Class std::mutex
+ size=40 align=8
+ base size=40 base align=8
+std::mutex (0x0x7faa6a671c98) 0
+ std::__mutex_base (0x0x7faa6a67c8a0) 0
+
+Class std::defer_lock_t
+ size=1 align=1
+ base size=0 base align=1
+std::defer_lock_t (0x0x7faa6a67ca80) 0 empty
+
+Class std::try_to_lock_t
+ size=1 align=1
+ base size=0 base align=1
+std::try_to_lock_t (0x0x7faa6a67cae0) 0 empty
+
+Class std::adopt_lock_t
+ size=1 align=1
+ base size=0 base align=1
+std::adopt_lock_t (0x0x7faa6a67cb40) 0 empty
+
+Class std::__recursive_mutex_base
+ size=40 align=8
+ base size=40 base align=8
+std::__recursive_mutex_base (0x0x7faa6a6af5a0) 0
+
+Class std::recursive_mutex
+ size=40 align=8
+ base size=40 base align=8
+std::recursive_mutex (0x0x7faa6a671d00) 0
+ std::__recursive_mutex_base (0x0x7faa6a6af600) 0
+
+Class std::timed_mutex
+ size=40 align=8
+ base size=40 base align=8
+std::timed_mutex (0x0x7faa6a68eaf0) 0
+ std::__mutex_base (0x0x7faa6a6af9c0) 0
+ std::__timed_mutex_impl<std::timed_mutex> (0x0x7faa6a6afa20) 0 empty
+
+Class std::recursive_timed_mutex
+ size=40 align=8
+ base size=40 base align=8
+std::recursive_timed_mutex (0x0x7faa6a68ee70) 0
+ std::__recursive_mutex_base (0x0x7faa6a6afd80) 0
+ std::__timed_mutex_impl<std::recursive_timed_mutex> (0x0x7faa6a6afde0) 0 empty
+
+Class std::once_flag
+ size=4 align=4
+ base size=4 base align=4
+std::once_flag (0x0x7faa6a6ef540) 0
+
+Vtable for QFutureInterfaceBase
+QFutureInterfaceBase::_ZTV20QFutureInterfaceBase: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QFutureInterfaceBase)
+16 (int (*)(...))QFutureInterfaceBase::~QFutureInterfaceBase
+24 (int (*)(...))QFutureInterfaceBase::~QFutureInterfaceBase
+
+Class QFutureInterfaceBase
+ size=16 align=8
+ base size=16 base align=8
+QFutureInterfaceBase (0x0x7faa6a6ef780) 0
+ vptr=((& QFutureInterfaceBase::_ZTV20QFutureInterfaceBase) + 16)
+
+Class QFutureWatcherBase::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFutureWatcherBase::QPrivateSignal (0x0x7faa6a39fae0) 0 empty
+
+Vtable for QFutureWatcherBase
+QFutureWatcherBase::_ZTV18QFutureWatcherBase: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QFutureWatcherBase)
+16 (int (*)(...))QFutureWatcherBase::metaObject
+24 (int (*)(...))QFutureWatcherBase::qt_metacast
+32 (int (*)(...))QFutureWatcherBase::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QFutureWatcherBase::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QFutureWatcherBase::connectNotify
+104 (int (*)(...))QFutureWatcherBase::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QFutureWatcherBase
+ size=16 align=8
+ base size=16 base align=8
+QFutureWatcherBase (0x0x7faa6a72baf8) 0
+ vptr=((& QFutureWatcherBase::_ZTV18QFutureWatcherBase) + 16)
+ QObject (0x0x7faa6a39fa80) 0
+ primary-for QFutureWatcherBase (0x0x7faa6a72baf8)
+
+Class QHistoryState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QHistoryState::QPrivateSignal (0x0x7faa6a3c6e40) 0 empty
+
+Vtable for QHistoryState
+QHistoryState::_ZTV13QHistoryState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QHistoryState)
+16 (int (*)(...))QHistoryState::metaObject
+24 (int (*)(...))QHistoryState::qt_metacast
+32 (int (*)(...))QHistoryState::qt_metacall
+40 (int (*)(...))QHistoryState::~QHistoryState
+48 (int (*)(...))QHistoryState::~QHistoryState
+56 (int (*)(...))QHistoryState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QHistoryState::onEntry
+120 (int (*)(...))QHistoryState::onExit
+
+Class QHistoryState
+ size=16 align=8
+ base size=16 base align=8
+QHistoryState (0x0x7faa6a3e3340) 0
+ vptr=((& QHistoryState::_ZTV13QHistoryState) + 16)
+ QAbstractState (0x0x7faa6a3e33a8) 0
+ primary-for QHistoryState (0x0x7faa6a3e3340)
+ QObject (0x0x7faa6a3c6de0) 0
+ primary-for QAbstractState (0x0x7faa6a3e33a8)
+
+Class QIdentityProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QIdentityProxyModel::QPrivateSignal (0x0x7faa6a3f8180) 0 empty
+
+Vtable for QIdentityProxyModel
+QIdentityProxyModel::_ZTV19QIdentityProxyModel: 53 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QIdentityProxyModel)
+16 (int (*)(...))QIdentityProxyModel::metaObject
+24 (int (*)(...))QIdentityProxyModel::qt_metacast
+32 (int (*)(...))QIdentityProxyModel::qt_metacall
+40 (int (*)(...))QIdentityProxyModel::~QIdentityProxyModel
+48 (int (*)(...))QIdentityProxyModel::~QIdentityProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QIdentityProxyModel::index
+120 (int (*)(...))QIdentityProxyModel::parent
+128 (int (*)(...))QIdentityProxyModel::sibling
+136 (int (*)(...))QIdentityProxyModel::rowCount
+144 (int (*)(...))QIdentityProxyModel::columnCount
+152 (int (*)(...))QAbstractProxyModel::hasChildren
+160 (int (*)(...))QAbstractProxyModel::data
+168 (int (*)(...))QAbstractProxyModel::setData
+176 (int (*)(...))QIdentityProxyModel::headerData
+184 (int (*)(...))QAbstractProxyModel::setHeaderData
+192 (int (*)(...))QAbstractProxyModel::itemData
+200 (int (*)(...))QAbstractProxyModel::setItemData
+208 (int (*)(...))QAbstractProxyModel::mimeTypes
+216 (int (*)(...))QAbstractProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QIdentityProxyModel::dropMimeData
+240 (int (*)(...))QAbstractProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QIdentityProxyModel::insertRows
+264 (int (*)(...))QIdentityProxyModel::insertColumns
+272 (int (*)(...))QIdentityProxyModel::removeRows
+280 (int (*)(...))QIdentityProxyModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractProxyModel::fetchMore
+312 (int (*)(...))QAbstractProxyModel::canFetchMore
+320 (int (*)(...))QAbstractProxyModel::flags
+328 (int (*)(...))QAbstractProxyModel::sort
+336 (int (*)(...))QAbstractProxyModel::buddy
+344 (int (*)(...))QIdentityProxyModel::match
+352 (int (*)(...))QAbstractProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QIdentityProxyModel::setSourceModel
+392 (int (*)(...))QIdentityProxyModel::mapToSource
+400 (int (*)(...))QIdentityProxyModel::mapFromSource
+408 (int (*)(...))QIdentityProxyModel::mapSelectionToSource
+416 (int (*)(...))QIdentityProxyModel::mapSelectionFromSource
+
+Class QIdentityProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QIdentityProxyModel (0x0x7faa6a3e3410) 0
+ vptr=((& QIdentityProxyModel::_ZTV19QIdentityProxyModel) + 16)
+ QAbstractProxyModel (0x0x7faa6a3e3478) 0
+ primary-for QIdentityProxyModel (0x0x7faa6a3e3410)
+ QAbstractItemModel (0x0x7faa6a3e34e0) 0
+ primary-for QAbstractProxyModel (0x0x7faa6a3e3478)
+ QObject (0x0x7faa6a3f8120) 0
+ primary-for QAbstractItemModel (0x0x7faa6a3e34e0)
+
+Class QItemSelectionRange
+ size=16 align=8
+ base size=16 base align=8
+QItemSelectionRange (0x0x7faa6a3f8360) 0
+
+Class QItemSelectionModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QItemSelectionModel::QPrivateSignal (0x0x7faa6a4b2c60) 0 empty
+
+Vtable for QItemSelectionModel
+QItemSelectionModel::_ZTV19QItemSelectionModel: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QItemSelectionModel)
+16 (int (*)(...))QItemSelectionModel::metaObject
+24 (int (*)(...))QItemSelectionModel::qt_metacast
+32 (int (*)(...))QItemSelectionModel::qt_metacall
+40 (int (*)(...))QItemSelectionModel::~QItemSelectionModel
+48 (int (*)(...))QItemSelectionModel::~QItemSelectionModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QItemSelectionModel::setCurrentIndex
+120 (int (*)(...))QItemSelectionModel::select
+128 (int (*)(...))QItemSelectionModel::select
+136 (int (*)(...))QItemSelectionModel::clear
+144 (int (*)(...))QItemSelectionModel::reset
+152 (int (*)(...))QItemSelectionModel::clearCurrentIndex
+
+Class QItemSelectionModel
+ size=16 align=8
+ base size=16 base align=8
+QItemSelectionModel (0x0x7faa6a4afe38) 0
+ vptr=((& QItemSelectionModel::_ZTV19QItemSelectionModel) + 16)
+ QObject (0x0x7faa6a4b2c00) 0
+ primary-for QItemSelectionModel (0x0x7faa6a4afe38)
+
+Class QItemSelection
+ size=8 align=8
+ base size=8 base align=8
+QItemSelection (0x0x7faa6a536000) 0
+ QList<QItemSelectionRange> (0x0x7faa6a536068) 0
+ QListSpecialMethods<QItemSelectionRange> (0x0x7faa6a4f1780) 0 empty
+
+Class QJsonValue
+ size=24 align=8
+ base size=20 base align=8
+QJsonValue (0x0x7faa6a1840c0) 0
+
+Class QJsonValueRef
+ size=16 align=8
+ base size=12 base align=8
+QJsonValueRef (0x0x7faa6a2b1d20) 0
+
+Class QJsonValuePtr
+ size=24 align=8
+ base size=24 base align=8
+QJsonValuePtr (0x0x7faa6a2f1cc0) 0
+
+Class QJsonValueRefPtr
+ size=16 align=8
+ base size=16 base align=8
+QJsonValueRefPtr (0x0x7faa6a2f1f60) 0
+
+Class QJsonArray::iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonArray::iterator (0x0x7faa69f6c300) 0
+
+Class QJsonArray::const_iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonArray::const_iterator (0x0x7faa69f6c360) 0
+
+Class QJsonArray
+ size=16 align=8
+ base size=16 base align=8
+QJsonArray (0x0x7faa69f6c2a0) 0
+
+Class QJsonParseError
+ size=8 align=4
+ base size=8 base align=4
+QJsonParseError (0x0x7faa6a09b240) 0
+
+Class QJsonDocument
+ size=8 align=8
+ base size=8 base align=8
+QJsonDocument (0x0x7faa6a09b2a0) 0
+
+Class QJsonObject::iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonObject::iterator (0x0x7faa6a0eda80) 0
+
+Class QJsonObject::const_iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonObject::const_iterator (0x0x7faa6a0edae0) 0
+
+Class QJsonObject
+ size=16 align=8
+ base size=16 base align=8
+QJsonObject (0x0x7faa6a0eda20) 0
+
+Class QLibrary::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QLibrary::QPrivateSignal (0x0x7faa69e08f00) 0 empty
+
+Vtable for QLibrary
+QLibrary::_ZTV8QLibrary: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI8QLibrary)
+16 (int (*)(...))QLibrary::metaObject
+24 (int (*)(...))QLibrary::qt_metacast
+32 (int (*)(...))QLibrary::qt_metacall
+40 (int (*)(...))QLibrary::~QLibrary
+48 (int (*)(...))QLibrary::~QLibrary
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QLibrary
+ size=32 align=8
+ base size=25 base align=8
+QLibrary (0x0x7faa69e0dc98) 0
+ vptr=((& QLibrary::_ZTV8QLibrary) + 16)
+ QObject (0x0x7faa69e08ea0) 0
+ primary-for QLibrary (0x0x7faa69e0dc98)
+
+Class QVersionNumber::SegmentStorage
+ size=8 align=8
+ base size=8 base align=8
+QVersionNumber::SegmentStorage (0x0x7faa69e38d80) 0
+
+Class QVersionNumber
+ size=8 align=8
+ base size=8 base align=8
+QVersionNumber (0x0x7faa69e388a0) 0
+
+Class QLibraryInfo
+ size=1 align=1
+ base size=0 base align=1
+QLibraryInfo (0x0x7faa69f09540) 0 empty
+
+Class QPoint
+ size=8 align=4
+ base size=8 base align=4
+QPoint (0x0x7faa69f095a0) 0
+
+Class QPointF
+ size=16 align=8
+ base size=16 base align=8
+QPointF (0x0x7faa69b82420) 0
+
+Class QLine
+ size=16 align=4
+ base size=16 base align=4
+QLine (0x0x7faa69bf3600) 0
+
+Class QLineF
+ size=32 align=8
+ base size=32 base align=8
+QLineF (0x0x7faa69c5f9c0) 0
+
+Class QLinkedListData
+ size=32 align=8
+ base size=25 base align=8
+QLinkedListData (0x0x7faa69cdcc60) 0
+
+Class QLockFile
+ size=8 align=8
+ base size=8 base align=8
+QLockFile (0x0x7faa6999f1e0) 0
+
+Class QLoggingCategory::AtomicBools
+ size=4 align=1
+ base size=4 base align=1
+QLoggingCategory::AtomicBools (0x0x7faa6999f420) 0
+
+Class QLoggingCategory
+ size=24 align=8
+ base size=24 base align=8
+QLoggingCategory (0x0x7faa6999f3c0) 0
+
+Class QMargins
+ size=16 align=4
+ base size=16 base align=4
+QMargins (0x0x7faa6999f840) 0
+
+Class QMarginsF
+ size=32 align=8
+ base size=32 base align=8
+QMarginsF (0x0x7faa69a61780) 0
+
+Class QMessageAuthenticationCode
+ size=8 align=8
+ base size=8 base align=8
+QMessageAuthenticationCode (0x0x7faa698a9f60) 0
+
+Class QMetaMethod
+ size=16 align=8
+ base size=12 base align=8
+QMetaMethod (0x0x7faa698d2000) 0
+
+Class QMetaEnum
+ size=16 align=8
+ base size=12 base align=8
+QMetaEnum (0x0x7faa69932840) 0
+
+Class QMetaProperty
+ size=32 align=8
+ base size=32 base align=8
+QMetaProperty (0x0x7faa694f4a20) 0
+
+Class QMetaClassInfo
+ size=16 align=8
+ base size=12 base align=8
+QMetaClassInfo (0x0x7faa694f4b40) 0
+
+Class QMimeData::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QMimeData::QPrivateSignal (0x0x7faa6954f120) 0 empty
+
+Vtable for QMimeData
+QMimeData::_ZTV9QMimeData: 17 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QMimeData)
+16 (int (*)(...))QMimeData::metaObject
+24 (int (*)(...))QMimeData::qt_metacast
+32 (int (*)(...))QMimeData::qt_metacall
+40 (int (*)(...))QMimeData::~QMimeData
+48 (int (*)(...))QMimeData::~QMimeData
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QMimeData::hasFormat
+120 (int (*)(...))QMimeData::formats
+128 (int (*)(...))QMimeData::retrieveData
+
+Class QMimeData
+ size=16 align=8
+ base size=16 base align=8
+QMimeData (0x0x7faa695458f0) 0
+ vptr=((& QMimeData::_ZTV9QMimeData) + 16)
+ QObject (0x0x7faa6954f0c0) 0
+ primary-for QMimeData (0x0x7faa695458f0)
+
+Class QMimeType
+ size=8 align=8
+ base size=8 base align=8
+QMimeType (0x0x7faa6954f300) 0
+
+Class QMimeDatabase
+ size=8 align=8
+ base size=8 base align=8
+QMimeDatabase (0x0x7faa69623240) 0
+
+Class QObjectCleanupHandler::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QObjectCleanupHandler::QPrivateSignal (0x0x7faa69623300) 0 empty
+
+Vtable for QObjectCleanupHandler
+QObjectCleanupHandler::_ZTV21QObjectCleanupHandler: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QObjectCleanupHandler)
+16 (int (*)(...))QObjectCleanupHandler::metaObject
+24 (int (*)(...))QObjectCleanupHandler::qt_metacast
+32 (int (*)(...))QObjectCleanupHandler::qt_metacall
+40 (int (*)(...))QObjectCleanupHandler::~QObjectCleanupHandler
+48 (int (*)(...))QObjectCleanupHandler::~QObjectCleanupHandler
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QObjectCleanupHandler
+ size=24 align=8
+ base size=24 base align=8
+QObjectCleanupHandler (0x0x7faa6961c478) 0
+ vptr=((& QObjectCleanupHandler::_ZTV21QObjectCleanupHandler) + 16)
+ QObject (0x0x7faa696232a0) 0
+ primary-for QObjectCleanupHandler (0x0x7faa6961c478)
+
+Class QOperatingSystemVersion
+ size=16 align=4
+ base size=16 base align=4
+QOperatingSystemVersion (0x0x7faa69623420) 0
+
+Class QParallelAnimationGroup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QParallelAnimationGroup::QPrivateSignal (0x0x7faa6968dba0) 0 empty
+
+Vtable for QParallelAnimationGroup
+QParallelAnimationGroup::_ZTV23QParallelAnimationGroup: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI23QParallelAnimationGroup)
+16 (int (*)(...))QParallelAnimationGroup::metaObject
+24 (int (*)(...))QParallelAnimationGroup::qt_metacast
+32 (int (*)(...))QParallelAnimationGroup::qt_metacall
+40 (int (*)(...))QParallelAnimationGroup::~QParallelAnimationGroup
+48 (int (*)(...))QParallelAnimationGroup::~QParallelAnimationGroup
+56 (int (*)(...))QParallelAnimationGroup::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QParallelAnimationGroup::duration
+120 (int (*)(...))QParallelAnimationGroup::updateCurrentTime
+128 (int (*)(...))QParallelAnimationGroup::updateState
+136 (int (*)(...))QParallelAnimationGroup::updateDirection
+
+Class QParallelAnimationGroup
+ size=16 align=8
+ base size=16 base align=8
+QParallelAnimationGroup (0x0x7faa6968ed00) 0
+ vptr=((& QParallelAnimationGroup::_ZTV23QParallelAnimationGroup) + 16)
+ QAnimationGroup (0x0x7faa6968ed68) 0
+ primary-for QParallelAnimationGroup (0x0x7faa6968ed00)
+ QAbstractAnimation (0x0x7faa6968edd0) 0
+ primary-for QAnimationGroup (0x0x7faa6968ed68)
+ QObject (0x0x7faa6968db40) 0
+ primary-for QAbstractAnimation (0x0x7faa6968edd0)
+
+Class QPauseAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QPauseAnimation::QPrivateSignal (0x0x7faa6968dde0) 0 empty
+
+Vtable for QPauseAnimation
+QPauseAnimation::_ZTV15QPauseAnimation: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QPauseAnimation)
+16 (int (*)(...))QPauseAnimation::metaObject
+24 (int (*)(...))QPauseAnimation::qt_metacast
+32 (int (*)(...))QPauseAnimation::qt_metacall
+40 (int (*)(...))QPauseAnimation::~QPauseAnimation
+48 (int (*)(...))QPauseAnimation::~QPauseAnimation
+56 (int (*)(...))QPauseAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QPauseAnimation::duration
+120 (int (*)(...))QPauseAnimation::updateCurrentTime
+128 (int (*)(...))QAbstractAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QPauseAnimation
+ size=16 align=8
+ base size=16 base align=8
+QPauseAnimation (0x0x7faa6968ee38) 0
+ vptr=((& QPauseAnimation::_ZTV15QPauseAnimation) + 16)
+ QAbstractAnimation (0x0x7faa6968eea0) 0
+ primary-for QPauseAnimation (0x0x7faa6968ee38)
+ QObject (0x0x7faa6968dd80) 0
+ primary-for QAbstractAnimation (0x0x7faa6968eea0)
+
+Class QStaticPlugin
+ size=16 align=8
+ base size=16 base align=8
+QStaticPlugin (0x0x7faa696be960) 0
+
+Class QPluginLoader::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QPluginLoader::QPrivateSignal (0x0x7faa69309ae0) 0 empty
+
+Vtable for QPluginLoader
+QPluginLoader::_ZTV13QPluginLoader: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QPluginLoader)
+16 (int (*)(...))QPluginLoader::metaObject
+24 (int (*)(...))QPluginLoader::qt_metacast
+32 (int (*)(...))QPluginLoader::qt_metacall
+40 (int (*)(...))QPluginLoader::~QPluginLoader
+48 (int (*)(...))QPluginLoader::~QPluginLoader
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QPluginLoader
+ size=32 align=8
+ base size=25 base align=8
+QPluginLoader (0x0x7faa69317208) 0
+ vptr=((& QPluginLoader::_ZTV13QPluginLoader) + 16)
+ QObject (0x0x7faa69309a80) 0
+ primary-for QPluginLoader (0x0x7faa69317208)
+
+Class QProcessEnvironment
+ size=8 align=8
+ base size=8 base align=8
+QProcessEnvironment (0x0x7faa69309c00) 0
+
+Class QProcess::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QProcess::QPrivateSignal (0x0x7faa693f00c0) 0 empty
+
+Vtable for QProcess
+QProcess::_ZTV8QProcess: 31 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI8QProcess)
+16 (int (*)(...))QProcess::metaObject
+24 (int (*)(...))QProcess::qt_metacast
+32 (int (*)(...))QProcess::qt_metacall
+40 (int (*)(...))QProcess::~QProcess
+48 (int (*)(...))QProcess::~QProcess
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QProcess::isSequential
+120 (int (*)(...))QProcess::open
+128 (int (*)(...))QProcess::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QProcess::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QProcess::bytesAvailable
+184 (int (*)(...))QProcess::bytesToWrite
+192 (int (*)(...))QProcess::canReadLine
+200 (int (*)(...))QProcess::waitForReadyRead
+208 (int (*)(...))QProcess::waitForBytesWritten
+216 (int (*)(...))QProcess::readData
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QProcess::writeData
+240 (int (*)(...))QProcess::setupChildProcess
+
+Class QProcess
+ size=16 align=8
+ base size=16 base align=8
+QProcess (0x0x7faa693e6680) 0
+ vptr=((& QProcess::_ZTV8QProcess) + 16)
+ QIODevice (0x0x7faa693e66e8) 0
+ primary-for QProcess (0x0x7faa693e6680)
+ QObject (0x0x7faa693f0060) 0
+ primary-for QIODevice (0x0x7faa693e66e8)
+
+Class QVariantAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QVariantAnimation::QPrivateSignal (0x0x7faa693f0780) 0 empty
+
+Vtable for QVariantAnimation
+QVariantAnimation::_ZTV17QVariantAnimation: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QVariantAnimation)
+16 (int (*)(...))QVariantAnimation::metaObject
+24 (int (*)(...))QVariantAnimation::qt_metacast
+32 (int (*)(...))QVariantAnimation::qt_metacall
+40 (int (*)(...))QVariantAnimation::~QVariantAnimation
+48 (int (*)(...))QVariantAnimation::~QVariantAnimation
+56 (int (*)(...))QVariantAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QVariantAnimation::duration
+120 (int (*)(...))QVariantAnimation::updateCurrentTime
+128 (int (*)(...))QVariantAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+144 (int (*)(...))QVariantAnimation::updateCurrentValue
+152 (int (*)(...))QVariantAnimation::interpolated
+
+Class QVariantAnimation
+ size=16 align=8
+ base size=16 base align=8
+QVariantAnimation (0x0x7faa693e6750) 0
+ vptr=((& QVariantAnimation::_ZTV17QVariantAnimation) + 16)
+ QAbstractAnimation (0x0x7faa693e67b8) 0
+ primary-for QVariantAnimation (0x0x7faa693e6750)
+ QObject (0x0x7faa693f0720) 0
+ primary-for QAbstractAnimation (0x0x7faa693e67b8)
+
+Class QPropertyAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QPropertyAnimation::QPrivateSignal (0x0x7faa693f0a20) 0 empty
+
+Vtable for QPropertyAnimation
+QPropertyAnimation::_ZTV18QPropertyAnimation: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QPropertyAnimation)
+16 (int (*)(...))QPropertyAnimation::metaObject
+24 (int (*)(...))QPropertyAnimation::qt_metacast
+32 (int (*)(...))QPropertyAnimation::qt_metacall
+40 (int (*)(...))QPropertyAnimation::~QPropertyAnimation
+48 (int (*)(...))QPropertyAnimation::~QPropertyAnimation
+56 (int (*)(...))QPropertyAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QVariantAnimation::duration
+120 (int (*)(...))QVariantAnimation::updateCurrentTime
+128 (int (*)(...))QPropertyAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+144 (int (*)(...))QPropertyAnimation::updateCurrentValue
+152 (int (*)(...))QVariantAnimation::interpolated
+
+Class QPropertyAnimation
+ size=16 align=8
+ base size=16 base align=8
+QPropertyAnimation (0x0x7faa693e6888) 0
+ vptr=((& QPropertyAnimation::_ZTV18QPropertyAnimation) + 16)
+ QVariantAnimation (0x0x7faa693e68f0) 0
+ primary-for QPropertyAnimation (0x0x7faa693e6888)
+ QAbstractAnimation (0x0x7faa693e6958) 0
+ primary-for QVariantAnimation (0x0x7faa693e68f0)
+ QObject (0x0x7faa693f09c0) 0
+ primary-for QAbstractAnimation (0x0x7faa693e6958)
+
+Class std::random_device
+ size=5000 align=8
+ base size=5000 base align=8
+std::random_device (0x0x7faa694be180) 0
+
+Class std::bernoulli_distribution::param_type
+ size=8 align=8
+ base size=8 base align=8
+std::bernoulli_distribution::param_type (0x0x7faa6919bea0) 0
+
+Class std::bernoulli_distribution
+ size=8 align=8
+ base size=8 base align=8
+std::bernoulli_distribution (0x0x7faa6919be40) 0
+
+Class std::seed_seq
+ size=24 align=8
+ base size=24 base align=8
+std::seed_seq (0x0x7faa68f8ac00) 0
+
+Class QRandomGenerator::Storage
+ size=2504 align=8
+ base size=2504 base align=8
+QRandomGenerator::Storage (0x0x7faa68dc88a0) 0
+
+Class QRandomGenerator
+ size=2512 align=8
+ base size=2512 base align=8
+QRandomGenerator (0x0x7faa68dc8840) 0
+
+Class QRandomGenerator64
+ size=2512 align=8
+ base size=2512 base align=8
+QRandomGenerator64 (0x0x7faa68e4d618) 0
+ QRandomGenerator (0x0x7faa68e6c3c0) 0
+
+Class QReadWriteLock
+ size=8 align=8
+ base size=8 base align=8
+QReadWriteLock (0x0x7faa68e6cf60) 0
+
+Class QReadLocker
+ size=8 align=8
+ base size=8 base align=8
+QReadLocker (0x0x7faa68e8f240) 0
+
+Class QWriteLocker
+ size=8 align=8
+ base size=8 base align=8
+QWriteLocker (0x0x7faa68e8f720) 0
+
+Class QSize
+ size=8 align=4
+ base size=8 base align=4
+QSize (0x0x7faa68e8fc00) 0
+
+Class QSizeF
+ size=16 align=8
+ base size=16 base align=8
+QSizeF (0x0x7faa68b64ae0) 0
+
+Class QRect
+ size=16 align=4
+ base size=16 base align=4
+QRect (0x0x7faa68bdeb40) 0
+
+Class QRectF
+ size=32 align=8
+ base size=32 base align=8
+QRectF (0x0x7faa68c8fba0) 0
+
+Class QResource
+ size=8 align=8
+ base size=8 base align=8
+QResource (0x0x7faa68950cc0) 0
+
+Class QSaveFile::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSaveFile::QPrivateSignal (0x0x7faa68950f60) 0 empty
+
+Vtable for QSaveFile
+QSaveFile::_ZTV9QSaveFile: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QSaveFile)
+16 (int (*)(...))QSaveFile::metaObject
+24 (int (*)(...))QSaveFile::qt_metacast
+32 (int (*)(...))QSaveFile::qt_metacall
+40 (int (*)(...))QSaveFile::~QSaveFile
+48 (int (*)(...))QSaveFile::~QSaveFile
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QSaveFile::open
+128 (int (*)(...))QSaveFile::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFileDevice::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QSaveFile::writeData
+240 (int (*)(...))QSaveFile::fileName
+248 (int (*)(...))QFileDevice::resize
+256 (int (*)(...))QFileDevice::permissions
+264 (int (*)(...))QFileDevice::setPermissions
+
+Class QSaveFile
+ size=16 align=8
+ base size=16 base align=8
+QSaveFile (0x0x7faa6899b000) 0
+ vptr=((& QSaveFile::_ZTV9QSaveFile) + 16)
+ QFileDevice (0x0x7faa6899b068) 0
+ primary-for QSaveFile (0x0x7faa6899b000)
+ QIODevice (0x0x7faa6899b0d0) 0
+ primary-for QFileDevice (0x0x7faa6899b068)
+ QObject (0x0x7faa68950f00) 0
+ primary-for QIODevice (0x0x7faa6899b0d0)
+
+Class QSemaphore
+ size=8 align=8
+ base size=8 base align=8
+QSemaphore (0x0x7faa689a75a0) 0
+
+Class QSemaphoreReleaser
+ size=16 align=8
+ base size=12 base align=8
+QSemaphoreReleaser (0x0x7faa689a7720) 0
+
+Class QSequentialAnimationGroup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSequentialAnimationGroup::QPrivateSignal (0x0x7faa68a7c360) 0 empty
+
+Vtable for QSequentialAnimationGroup
+QSequentialAnimationGroup::_ZTV25QSequentialAnimationGroup: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI25QSequentialAnimationGroup)
+16 (int (*)(...))QSequentialAnimationGroup::metaObject
+24 (int (*)(...))QSequentialAnimationGroup::qt_metacast
+32 (int (*)(...))QSequentialAnimationGroup::qt_metacall
+40 (int (*)(...))QSequentialAnimationGroup::~QSequentialAnimationGroup
+48 (int (*)(...))QSequentialAnimationGroup::~QSequentialAnimationGroup
+56 (int (*)(...))QSequentialAnimationGroup::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QSequentialAnimationGroup::duration
+120 (int (*)(...))QSequentialAnimationGroup::updateCurrentTime
+128 (int (*)(...))QSequentialAnimationGroup::updateState
+136 (int (*)(...))QSequentialAnimationGroup::updateDirection
+
+Class QSequentialAnimationGroup
+ size=16 align=8
+ base size=16 base align=8
+QSequentialAnimationGroup (0x0x7faa68a7a888) 0
+ vptr=((& QSequentialAnimationGroup::_ZTV25QSequentialAnimationGroup) + 16)
+ QAnimationGroup (0x0x7faa68a7a8f0) 0
+ primary-for QSequentialAnimationGroup (0x0x7faa68a7a888)
+ QAbstractAnimation (0x0x7faa68a7a958) 0
+ primary-for QAnimationGroup (0x0x7faa68a7a8f0)
+ QObject (0x0x7faa68a7c300) 0
+ primary-for QAbstractAnimation (0x0x7faa68a7a958)
+
+Class QSettings::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSettings::QPrivateSignal (0x0x7faa68a7c5a0) 0 empty
+
+Vtable for QSettings
+QSettings::_ZTV9QSettings: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QSettings)
+16 (int (*)(...))QSettings::metaObject
+24 (int (*)(...))QSettings::qt_metacast
+32 (int (*)(...))QSettings::qt_metacall
+40 (int (*)(...))QSettings::~QSettings
+48 (int (*)(...))QSettings::~QSettings
+56 (int (*)(...))QSettings::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSettings
+ size=16 align=8
+ base size=16 base align=8
+QSettings (0x0x7faa68a7a9c0) 0
+ vptr=((& QSettings::_ZTV9QSettings) + 16)
+ QObject (0x0x7faa68a7c540) 0
+ primary-for QSettings (0x0x7faa68a7a9c0)
+
+Class QSharedMemory::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSharedMemory::QPrivateSignal (0x0x7faa68a7ca20) 0 empty
+
+Vtable for QSharedMemory
+QSharedMemory::_ZTV13QSharedMemory: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QSharedMemory)
+16 (int (*)(...))QSharedMemory::metaObject
+24 (int (*)(...))QSharedMemory::qt_metacast
+32 (int (*)(...))QSharedMemory::qt_metacall
+40 (int (*)(...))QSharedMemory::~QSharedMemory
+48 (int (*)(...))QSharedMemory::~QSharedMemory
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSharedMemory
+ size=16 align=8
+ base size=16 base align=8
+QSharedMemory (0x0x7faa68a7aa28) 0
+ vptr=((& QSharedMemory::_ZTV13QSharedMemory) + 16)
+ QObject (0x0x7faa68a7c9c0) 0
+ primary-for QSharedMemory (0x0x7faa68a7aa28)
+
+Class QSignalMapper::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSignalMapper::QPrivateSignal (0x0x7faa68a7cc60) 0 empty
+
+Vtable for QSignalMapper
+QSignalMapper::_ZTV13QSignalMapper: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QSignalMapper)
+16 (int (*)(...))QSignalMapper::metaObject
+24 (int (*)(...))QSignalMapper::qt_metacast
+32 (int (*)(...))QSignalMapper::qt_metacall
+40 (int (*)(...))QSignalMapper::~QSignalMapper
+48 (int (*)(...))QSignalMapper::~QSignalMapper
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSignalMapper
+ size=16 align=8
+ base size=16 base align=8
+QSignalMapper (0x0x7faa68a7aa90) 0
+ vptr=((& QSignalMapper::_ZTV13QSignalMapper) + 16)
+ QObject (0x0x7faa68a7cc00) 0
+ primary-for QSignalMapper (0x0x7faa68a7aa90)
+
+Class QSignalTransition::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSignalTransition::QPrivateSignal (0x0x7faa68a7cea0) 0 empty
+
+Vtable for QSignalTransition
+QSignalTransition::_ZTV17QSignalTransition: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QSignalTransition)
+16 (int (*)(...))QSignalTransition::metaObject
+24 (int (*)(...))QSignalTransition::qt_metacast
+32 (int (*)(...))QSignalTransition::qt_metacall
+40 (int (*)(...))QSignalTransition::~QSignalTransition
+48 (int (*)(...))QSignalTransition::~QSignalTransition
+56 (int (*)(...))QSignalTransition::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QSignalTransition::eventTest
+120 (int (*)(...))QSignalTransition::onTransition
+
+Class QSignalTransition
+ size=16 align=8
+ base size=16 base align=8
+QSignalTransition (0x0x7faa68a7aaf8) 0
+ vptr=((& QSignalTransition::_ZTV17QSignalTransition) + 16)
+ QAbstractTransition (0x0x7faa68a7ab60) 0
+ primary-for QSignalTransition (0x0x7faa68a7aaf8)
+ QObject (0x0x7faa68a7ce40) 0
+ primary-for QAbstractTransition (0x0x7faa68a7ab60)
+
+Class QSocketNotifier::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSocketNotifier::QPrivateSignal (0x0x7faa68664180) 0 empty
+
+Vtable for QSocketNotifier
+QSocketNotifier::_ZTV15QSocketNotifier: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QSocketNotifier)
+16 (int (*)(...))QSocketNotifier::metaObject
+24 (int (*)(...))QSocketNotifier::qt_metacast
+32 (int (*)(...))QSocketNotifier::qt_metacall
+40 (int (*)(...))QSocketNotifier::~QSocketNotifier
+48 (int (*)(...))QSocketNotifier::~QSocketNotifier
+56 (int (*)(...))QSocketNotifier::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSocketNotifier
+ size=16 align=8
+ base size=16 base align=8
+QSocketNotifier (0x0x7faa68a7abc8) 0
+ vptr=((& QSocketNotifier::_ZTV15QSocketNotifier) + 16)
+ QObject (0x0x7faa68664120) 0
+ primary-for QSocketNotifier (0x0x7faa68a7abc8)
+
+Class QSortFilterProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSortFilterProxyModel::QPrivateSignal (0x0x7faa686643c0) 0 empty
+
+Vtable for QSortFilterProxyModel
+QSortFilterProxyModel::_ZTV21QSortFilterProxyModel: 56 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QSortFilterProxyModel)
+16 (int (*)(...))QSortFilterProxyModel::metaObject
+24 (int (*)(...))QSortFilterProxyModel::qt_metacast
+32 (int (*)(...))QSortFilterProxyModel::qt_metacall
+40 (int (*)(...))QSortFilterProxyModel::~QSortFilterProxyModel
+48 (int (*)(...))QSortFilterProxyModel::~QSortFilterProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QSortFilterProxyModel::index
+120 (int (*)(...))QSortFilterProxyModel::parent
+128 (int (*)(...))QSortFilterProxyModel::sibling
+136 (int (*)(...))QSortFilterProxyModel::rowCount
+144 (int (*)(...))QSortFilterProxyModel::columnCount
+152 (int (*)(...))QSortFilterProxyModel::hasChildren
+160 (int (*)(...))QSortFilterProxyModel::data
+168 (int (*)(...))QSortFilterProxyModel::setData
+176 (int (*)(...))QSortFilterProxyModel::headerData
+184 (int (*)(...))QSortFilterProxyModel::setHeaderData
+192 (int (*)(...))QAbstractProxyModel::itemData
+200 (int (*)(...))QAbstractProxyModel::setItemData
+208 (int (*)(...))QSortFilterProxyModel::mimeTypes
+216 (int (*)(...))QSortFilterProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QSortFilterProxyModel::dropMimeData
+240 (int (*)(...))QSortFilterProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QSortFilterProxyModel::insertRows
+264 (int (*)(...))QSortFilterProxyModel::insertColumns
+272 (int (*)(...))QSortFilterProxyModel::removeRows
+280 (int (*)(...))QSortFilterProxyModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QSortFilterProxyModel::fetchMore
+312 (int (*)(...))QSortFilterProxyModel::canFetchMore
+320 (int (*)(...))QSortFilterProxyModel::flags
+328 (int (*)(...))QSortFilterProxyModel::sort
+336 (int (*)(...))QSortFilterProxyModel::buddy
+344 (int (*)(...))QSortFilterProxyModel::match
+352 (int (*)(...))QSortFilterProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QSortFilterProxyModel::setSourceModel
+392 (int (*)(...))QSortFilterProxyModel::mapToSource
+400 (int (*)(...))QSortFilterProxyModel::mapFromSource
+408 (int (*)(...))QSortFilterProxyModel::mapSelectionToSource
+416 (int (*)(...))QSortFilterProxyModel::mapSelectionFromSource
+424 (int (*)(...))QSortFilterProxyModel::filterAcceptsRow
+432 (int (*)(...))QSortFilterProxyModel::filterAcceptsColumn
+440 (int (*)(...))QSortFilterProxyModel::lessThan
+
+Class QSortFilterProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QSortFilterProxyModel (0x0x7faa68a7ac30) 0
+ vptr=((& QSortFilterProxyModel::_ZTV21QSortFilterProxyModel) + 16)
+ QAbstractProxyModel (0x0x7faa68a7ac98) 0
+ primary-for QSortFilterProxyModel (0x0x7faa68a7ac30)
+ QAbstractItemModel (0x0x7faa68a7ad00) 0
+ primary-for QAbstractProxyModel (0x0x7faa68a7ac98)
+ QObject (0x0x7faa68664360) 0
+ primary-for QAbstractItemModel (0x0x7faa68a7ad00)
+
+Class QStandardPaths
+ size=1 align=1
+ base size=0 base align=1
+QStandardPaths (0x0x7faa686647e0) 0 empty
+
+Class QState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QState::QPrivateSignal (0x0x7faa686cd120) 0 empty
+
+Vtable for QState
+QState::_ZTV6QState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI6QState)
+16 (int (*)(...))QState::metaObject
+24 (int (*)(...))QState::qt_metacast
+32 (int (*)(...))QState::qt_metacall
+40 (int (*)(...))QState::~QState
+48 (int (*)(...))QState::~QState
+56 (int (*)(...))QState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QState::onEntry
+120 (int (*)(...))QState::onExit
+
+Class QState
+ size=16 align=8
+ base size=16 base align=8
+QState (0x0x7faa68a7aea0) 0
+ vptr=((& QState::_ZTV6QState) + 16)
+ QAbstractState (0x0x7faa68a7af08) 0
+ primary-for QState (0x0x7faa68a7aea0)
+ QObject (0x0x7faa686cd0c0) 0
+ primary-for QAbstractState (0x0x7faa68a7af08)
+
+Class QStateMachine::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QStateMachine::QPrivateSignal (0x0x7faa686cd5a0) 0 empty
+
+Vtable for QStateMachine::SignalEvent
+QStateMachine::SignalEvent::_ZTVN13QStateMachine11SignalEventE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN13QStateMachine11SignalEventE)
+16 (int (*)(...))QStateMachine::SignalEvent::~SignalEvent
+24 (int (*)(...))QStateMachine::SignalEvent::~SignalEvent
+
+Class QStateMachine::SignalEvent
+ size=48 align=8
+ base size=48 base align=8
+QStateMachine::SignalEvent (0x0x7faa686eb0d0) 0
+ vptr=((& QStateMachine::SignalEvent::_ZTVN13QStateMachine11SignalEventE) + 16)
+ QEvent (0x0x7faa686cd600) 0
+ primary-for QStateMachine::SignalEvent (0x0x7faa686eb0d0)
+
+Vtable for QStateMachine::WrappedEvent
+QStateMachine::WrappedEvent::_ZTVN13QStateMachine12WrappedEventE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN13QStateMachine12WrappedEventE)
+16 (int (*)(...))QStateMachine::WrappedEvent::~WrappedEvent
+24 (int (*)(...))QStateMachine::WrappedEvent::~WrappedEvent
+
+Class QStateMachine::WrappedEvent
+ size=40 align=8
+ base size=40 base align=8
+QStateMachine::WrappedEvent (0x0x7faa686eb138) 0
+ vptr=((& QStateMachine::WrappedEvent::_ZTVN13QStateMachine12WrappedEventE) + 16)
+ QEvent (0x0x7faa686cd660) 0
+ primary-for QStateMachine::WrappedEvent (0x0x7faa686eb138)
+
+Vtable for QStateMachine
+QStateMachine::_ZTV13QStateMachine: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QStateMachine)
+16 (int (*)(...))QStateMachine::metaObject
+24 (int (*)(...))QStateMachine::qt_metacast
+32 (int (*)(...))QStateMachine::qt_metacall
+40 (int (*)(...))QStateMachine::~QStateMachine
+48 (int (*)(...))QStateMachine::~QStateMachine
+56 (int (*)(...))QStateMachine::event
+64 (int (*)(...))QStateMachine::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QStateMachine::onEntry
+120 (int (*)(...))QStateMachine::onExit
+128 (int (*)(...))QStateMachine::beginSelectTransitions
+136 (int (*)(...))QStateMachine::endSelectTransitions
+144 (int (*)(...))QStateMachine::beginMicrostep
+152 (int (*)(...))QStateMachine::endMicrostep
+
+Class QStateMachine
+ size=16 align=8
+ base size=16 base align=8
+QStateMachine (0x0x7faa68a7af70) 0
+ vptr=((& QStateMachine::_ZTV13QStateMachine) + 16)
+ QState (0x0x7faa686eb000) 0
+ primary-for QStateMachine (0x0x7faa68a7af70)
+ QAbstractState (0x0x7faa686eb068) 0
+ primary-for QState (0x0x7faa686eb000)
+ QObject (0x0x7faa686cd540) 0
+ primary-for QAbstractState (0x0x7faa686eb068)
+
+Class QStorageInfo
+ size=8 align=8
+ base size=8 base align=8
+QStorageInfo (0x0x7faa686cda20) 0
+
+Class QAbstractConcatenable
+ size=1 align=1
+ base size=0 base align=1
+QAbstractConcatenable (0x0x7faa687f27e0) 0 empty
+
+Class QStringListModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QStringListModel::QPrivateSignal (0x0x7faa6847ab40) 0 empty
+
+Vtable for QStringListModel
+QStringListModel::_ZTV16QStringListModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QStringListModel)
+16 (int (*)(...))QStringListModel::metaObject
+24 (int (*)(...))QStringListModel::qt_metacast
+32 (int (*)(...))QStringListModel::qt_metacall
+40 (int (*)(...))QStringListModel::~QStringListModel
+48 (int (*)(...))QStringListModel::~QStringListModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractListModel::index
+120 (int (*)(...))QAbstractListModel::parent
+128 (int (*)(...))QStringListModel::sibling
+136 (int (*)(...))QStringListModel::rowCount
+144 (int (*)(...))QAbstractListModel::columnCount
+152 (int (*)(...))QAbstractListModel::hasChildren
+160 (int (*)(...))QStringListModel::data
+168 (int (*)(...))QStringListModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QStringListModel::itemData
+200 (int (*)(...))QStringListModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractListModel::dropMimeData
+240 (int (*)(...))QStringListModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QStringListModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QStringListModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QStringListModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QStringListModel::flags
+328 (int (*)(...))QStringListModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QStringListModel
+ size=24 align=8
+ base size=24 base align=8
+QStringListModel (0x0x7faa6846ea28) 0
+ vptr=((& QStringListModel::_ZTV16QStringListModel) + 16)
+ QAbstractListModel (0x0x7faa6846ea90) 0
+ primary-for QStringListModel (0x0x7faa6846ea28)
+ QAbstractItemModel (0x0x7faa6846eaf8) 0
+ primary-for QAbstractListModel (0x0x7faa6846ea90)
+ QObject (0x0x7faa6847aae0) 0
+ primary-for QAbstractItemModel (0x0x7faa6846eaf8)
+
+Class QSystemSemaphore
+ size=8 align=8
+ base size=8 base align=8
+QSystemSemaphore (0x0x7faa6847ac60) 0
+
+Class QTemporaryDir
+ size=8 align=8
+ base size=8 base align=8
+QTemporaryDir (0x0x7faa6847ad20) 0
+
+Class QTemporaryFile::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTemporaryFile::QPrivateSignal (0x0x7faa6847ae40) 0 empty
+
+Vtable for QTemporaryFile
+QTemporaryFile::_ZTV14QTemporaryFile: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI14QTemporaryFile)
+16 (int (*)(...))QTemporaryFile::metaObject
+24 (int (*)(...))QTemporaryFile::qt_metacast
+32 (int (*)(...))QTemporaryFile::qt_metacall
+40 (int (*)(...))QTemporaryFile::~QTemporaryFile
+48 (int (*)(...))QTemporaryFile::~QTemporaryFile
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QTemporaryFile::open
+128 (int (*)(...))QFileDevice::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFile::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QFileDevice::writeData
+240 (int (*)(...))QTemporaryFile::fileName
+248 (int (*)(...))QFile::resize
+256 (int (*)(...))QFile::permissions
+264 (int (*)(...))QFile::setPermissions
+
+Class QTemporaryFile
+ size=16 align=8
+ base size=16 base align=8
+QTemporaryFile (0x0x7faa6846eb60) 0
+ vptr=((& QTemporaryFile::_ZTV14QTemporaryFile) + 16)
+ QFile (0x0x7faa6846ebc8) 0
+ primary-for QTemporaryFile (0x0x7faa6846eb60)
+ QFileDevice (0x0x7faa6846ec30) 0
+ primary-for QFile (0x0x7faa6846ebc8)
+ QIODevice (0x0x7faa6846ec98) 0
+ primary-for QFileDevice (0x0x7faa6846ec30)
+ QObject (0x0x7faa6847ade0) 0
+ primary-for QIODevice (0x0x7faa6846ec98)
+
+Class QTextBoundaryFinder
+ size=48 align=8
+ base size=48 base align=8
+QTextBoundaryFinder (0x0x7faa684d51e0) 0
+
+Class QTextCodec::ConverterState
+ size=32 align=8
+ base size=32 base align=8
+QTextCodec::ConverterState (0x0x7faa684d5a20) 0
+
+Vtable for QTextCodec
+QTextCodec::_ZTV10QTextCodec: 9 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QTextCodec)
+16 (int (*)(...))__cxa_pure_virtual
+24 (int (*)(...))QTextCodec::aliases
+32 (int (*)(...))__cxa_pure_virtual
+40 (int (*)(...))__cxa_pure_virtual
+48 (int (*)(...))__cxa_pure_virtual
+56 0
+64 0
+
+Class QTextCodec
+ size=8 align=8
+ base size=8 base align=8
+QTextCodec (0x0x7faa684d59c0) 0 nearly-empty
+ vptr=((& QTextCodec::_ZTV10QTextCodec) + 16)
+
+Class QTextEncoder
+ size=40 align=8
+ base size=40 base align=8
+QTextEncoder (0x0x7faa6853a420) 0
+
+Class QTextDecoder
+ size=40 align=8
+ base size=40 base align=8
+QTextDecoder (0x0x7faa6853a600) 0
+
+Vtable for std::thread::_State
+std::thread::_State::_ZTVNSt6thread6_StateE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt6thread6_StateE)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class std::thread::_State
+ size=8 align=8
+ base size=8 base align=8
+std::thread::_State (0x0x7faa6853a840) 0 nearly-empty
+ vptr=((& std::thread::_State::_ZTVNSt6thread6_StateE) + 16)
+
+Class std::thread::id
+ size=8 align=8
+ base size=8 base align=8
+std::thread::id (0x0x7faa6853a8a0) 0
+
+Class std::thread
+ size=8 align=8
+ base size=8 base align=8
+std::thread (0x0x7faa6853a7e0) 0
+
+Class std::condition_variable
+ size=48 align=8
+ base size=48 base align=8
+std::condition_variable (0x0x7faa683ddc60) 0
+
+Class std::__at_thread_exit_elt
+ size=16 align=8
+ base size=16 base align=8
+std::__at_thread_exit_elt (0x0x7faa6842a060) 0
+
+Class std::_V2::condition_variable_any
+ size=64 align=8
+ base size=64 base align=8
+std::_V2::condition_variable_any (0x0x7faa6842a0c0) 0
+
+Class std::__atomic_futex_unsigned_base
+ size=1 align=1
+ base size=0 base align=1
+std::__atomic_futex_unsigned_base (0x0x7faa681913c0) 0 empty
+
+Vtable for std::future_error
+std::future_error::_ZTVSt12future_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12future_error)
+16 (int (*)(...))std::future_error::~future_error
+24 (int (*)(...))std::future_error::~future_error
+32 (int (*)(...))std::future_error::what
+
+Class std::future_error
+ size=32 align=8
+ base size=32 base align=8
+std::future_error (0x0x7faa681b2068) 0
+ vptr=((& std::future_error::_ZTVSt12future_error) + 16)
+ std::logic_error (0x0x7faa681b20d0) 0
+ primary-for std::future_error (0x0x7faa681b2068)
+ std::exception (0x0x7faa68191ae0) 0 nearly-empty
+ primary-for std::logic_error (0x0x7faa681b20d0)
+
+Class std::__future_base::_Result_base::_Deleter
+ size=1 align=1
+ base size=0 base align=1
+std::__future_base::_Result_base::_Deleter (0x0x7faa681c3240) 0 empty
+
+Vtable for std::__future_base::_Result_base
+std::__future_base::_Result_base::_ZTVNSt13__future_base12_Result_baseE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt13__future_base12_Result_baseE)
+16 (int (*)(...))__cxa_pure_virtual
+24 0
+32 0
+
+Class std::__future_base::_Result_base
+ size=16 align=8
+ base size=16 base align=8
+std::__future_base::_Result_base (0x0x7faa681c31e0) 0
+ vptr=((& std::__future_base::_Result_base::_ZTVNSt13__future_base12_Result_baseE) + 16)
+
+Class std::__future_base::_State_baseV2::__exception_ptr_tag
+ size=1 align=1
+ base size=0 base align=1
+std::__future_base::_State_baseV2::__exception_ptr_tag (0x0x7faa67fa3960) 0 empty
+
+Class std::__future_base::_State_baseV2::_Make_ready
+ size=32 align=8
+ base size=32 base align=8
+std::__future_base::_State_baseV2::_Make_ready (0x0x7faa67f858f0) 0
+ std::__at_thread_exit_elt (0x0x7faa67fa3a20) 0
+
+Vtable for std::__future_base::_State_baseV2
+std::__future_base::_State_baseV2::_ZTVNSt13__future_base13_State_baseV2E: 6 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt13__future_base13_State_baseV2E)
+16 (int (*)(...))std::__future_base::_State_baseV2::~_State_baseV2
+24 (int (*)(...))std::__future_base::_State_baseV2::~_State_baseV2
+32 (int (*)(...))std::__future_base::_State_baseV2::_M_complete_async
+40 (int (*)(...))std::__future_base::_State_baseV2::_M_is_deferred_future
+
+Class std::__future_base::_State_baseV2
+ size=32 align=8
+ base size=28 base align=8
+std::__future_base::_State_baseV2 (0x0x7faa681c33c0) 0
+ vptr=((& std::__future_base::_State_baseV2::_ZTVNSt13__future_base13_State_baseV2E) + 16)
+
+Class std::__future_base
+ size=1 align=1
+ base size=0 base align=1
+std::__future_base (0x0x7faa681c3180) 0 empty
+
+Vtable for std::__future_base::_Async_state_commonV2
+std::__future_base::_Async_state_commonV2::_ZTVNSt13__future_base21_Async_state_commonV2E: 6 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt13__future_base21_Async_state_commonV2E)
+16 (int (*)(...))std::__future_base::_Async_state_commonV2::~_Async_state_commonV2
+24 (int (*)(...))std::__future_base::_Async_state_commonV2::~_Async_state_commonV2
+32 (int (*)(...))std::__future_base::_Async_state_commonV2::_M_complete_async
+40 (int (*)(...))std::__future_base::_State_baseV2::_M_is_deferred_future
+
+Class std::__future_base::_Async_state_commonV2
+ size=48 align=8
+ base size=44 base align=8
+std::__future_base::_Async_state_commonV2 (0x0x7faa67727618) 0
+ vptr=((& std::__future_base::_Async_state_commonV2::_ZTVNSt13__future_base21_Async_state_commonV2E) + 16)
+ std::__future_base::_State_baseV2 (0x0x7faa67749a20) 0
+ primary-for std::__future_base::_Async_state_commonV2 (0x0x7faa67727618)
+
+Class QThread::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QThread::QPrivateSignal (0x0x7faa6777e300) 0 empty
+
+Vtable for QThread
+QThread::_ZTV7QThread: 15 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI7QThread)
+16 (int (*)(...))QThread::metaObject
+24 (int (*)(...))QThread::qt_metacast
+32 (int (*)(...))QThread::qt_metacall
+40 (int (*)(...))QThread::~QThread
+48 (int (*)(...))QThread::~QThread
+56 (int (*)(...))QThread::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QThread::run
+
+Class QThread
+ size=16 align=8
+ base size=16 base align=8
+QThread (0x0x7faa67727958) 0
+ vptr=((& QThread::_ZTV7QThread) + 16)
+ QObject (0x0x7faa6777e2a0) 0
+ primary-for QThread (0x0x7faa67727958)
+
+Class QThreadPool::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QThreadPool::QPrivateSignal (0x0x7faa6777e6c0) 0 empty
+
+Vtable for QThreadPool
+QThreadPool::_ZTV11QThreadPool: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QThreadPool)
+16 (int (*)(...))QThreadPool::metaObject
+24 (int (*)(...))QThreadPool::qt_metacast
+32 (int (*)(...))QThreadPool::qt_metacall
+40 (int (*)(...))QThreadPool::~QThreadPool
+48 (int (*)(...))QThreadPool::~QThreadPool
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QThreadPool
+ size=16 align=8
+ base size=16 base align=8
+QThreadPool (0x0x7faa677279c0) 0
+ vptr=((& QThreadPool::_ZTV11QThreadPool) + 16)
+ QObject (0x0x7faa6777e660) 0
+ primary-for QThreadPool (0x0x7faa677279c0)
+
+Class QThreadStorageData
+ size=4 align=4
+ base size=4 base align=4
+QThreadStorageData (0x0x7faa6777e8a0) 0
+
+Class QTimeLine::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTimeLine::QPrivateSignal (0x0x7faa6777ef60) 0 empty
+
+Vtable for QTimeLine
+QTimeLine::_ZTV9QTimeLine: 15 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QTimeLine)
+16 (int (*)(...))QTimeLine::metaObject
+24 (int (*)(...))QTimeLine::qt_metacast
+32 (int (*)(...))QTimeLine::qt_metacall
+40 (int (*)(...))QTimeLine::~QTimeLine
+48 (int (*)(...))QTimeLine::~QTimeLine
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QTimeLine::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTimeLine::valueForTime
+
+Class QTimeLine
+ size=16 align=8
+ base size=16 base align=8
+QTimeLine (0x0x7faa67727a28) 0
+ vptr=((& QTimeLine::_ZTV9QTimeLine) + 16)
+ QObject (0x0x7faa6777ef00) 0
+ primary-for QTimeLine (0x0x7faa67727a28)
+
+Class QTimer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTimer::QPrivateSignal (0x0x7faa677d01e0) 0 empty
+
+Vtable for QTimer
+QTimer::_ZTV6QTimer: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI6QTimer)
+16 (int (*)(...))QTimer::metaObject
+24 (int (*)(...))QTimer::qt_metacast
+32 (int (*)(...))QTimer::qt_metacall
+40 (int (*)(...))QTimer::~QTimer
+48 (int (*)(...))QTimer::~QTimer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QTimer::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QTimer
+ size=32 align=8
+ base size=29 base align=8
+QTimer (0x0x7faa67727a90) 0
+ vptr=((& QTimer::_ZTV6QTimer) + 16)
+ QObject (0x0x7faa677d0180) 0
+ primary-for QTimer (0x0x7faa67727a90)
+
+Class QTimeZone::OffsetData
+ size=32 align=8
+ base size=28 base align=8
+QTimeZone::OffsetData (0x0x7faa67808b40) 0
+
+Class QTimeZone
+ size=8 align=8
+ base size=8 base align=8
+QTimeZone (0x0x7faa67808ae0) 0
+
+Class QTranslator::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTranslator::QPrivateSignal (0x0x7faa674a6c00) 0 empty
+
+Vtable for QTranslator
+QTranslator::_ZTV11QTranslator: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QTranslator)
+16 (int (*)(...))QTranslator::metaObject
+24 (int (*)(...))QTranslator::qt_metacast
+32 (int (*)(...))QTranslator::qt_metacall
+40 (int (*)(...))QTranslator::~QTranslator
+48 (int (*)(...))QTranslator::~QTranslator
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTranslator::translate
+120 (int (*)(...))QTranslator::isEmpty
+
+Class QTranslator
+ size=16 align=8
+ base size=16 base align=8
+QTranslator (0x0x7faa674bc1a0) 0
+ vptr=((& QTranslator::_ZTV11QTranslator) + 16)
+ QObject (0x0x7faa674a6ba0) 0
+ primary-for QTranslator (0x0x7faa674bc1a0)
+
+Class QTransposeProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTransposeProxyModel::QPrivateSignal (0x0x7faa674a6e40) 0 empty
+
+Vtable for QTransposeProxyModel
+QTransposeProxyModel::_ZTV20QTransposeProxyModel: 53 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QTransposeProxyModel)
+16 (int (*)(...))QTransposeProxyModel::metaObject
+24 (int (*)(...))QTransposeProxyModel::qt_metacast
+32 (int (*)(...))QTransposeProxyModel::qt_metacall
+40 (int (*)(...))QTransposeProxyModel::~QTransposeProxyModel
+48 (int (*)(...))QTransposeProxyModel::~QTransposeProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTransposeProxyModel::index
+120 (int (*)(...))QTransposeProxyModel::parent
+128 (int (*)(...))QAbstractProxyModel::sibling
+136 (int (*)(...))QTransposeProxyModel::rowCount
+144 (int (*)(...))QTransposeProxyModel::columnCount
+152 (int (*)(...))QAbstractProxyModel::hasChildren
+160 (int (*)(...))QAbstractProxyModel::data
+168 (int (*)(...))QAbstractProxyModel::setData
+176 (int (*)(...))QTransposeProxyModel::headerData
+184 (int (*)(...))QTransposeProxyModel::setHeaderData
+192 (int (*)(...))QTransposeProxyModel::itemData
+200 (int (*)(...))QTransposeProxyModel::setItemData
+208 (int (*)(...))QAbstractProxyModel::mimeTypes
+216 (int (*)(...))QAbstractProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QAbstractProxyModel::dropMimeData
+240 (int (*)(...))QAbstractProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QTransposeProxyModel::insertRows
+264 (int (*)(...))QTransposeProxyModel::insertColumns
+272 (int (*)(...))QTransposeProxyModel::removeRows
+280 (int (*)(...))QTransposeProxyModel::removeColumns
+288 (int (*)(...))QTransposeProxyModel::moveRows
+296 (int (*)(...))QTransposeProxyModel::moveColumns
+304 (int (*)(...))QAbstractProxyModel::fetchMore
+312 (int (*)(...))QAbstractProxyModel::canFetchMore
+320 (int (*)(...))QAbstractProxyModel::flags
+328 (int (*)(...))QTransposeProxyModel::sort
+336 (int (*)(...))QAbstractProxyModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QTransposeProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QTransposeProxyModel::setSourceModel
+392 (int (*)(...))QTransposeProxyModel::mapToSource
+400 (int (*)(...))QTransposeProxyModel::mapFromSource
+408 (int (*)(...))QAbstractProxyModel::mapSelectionToSource
+416 (int (*)(...))QAbstractProxyModel::mapSelectionFromSource
+
+Class QTransposeProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QTransposeProxyModel (0x0x7faa674bc208) 0
+ vptr=((& QTransposeProxyModel::_ZTV20QTransposeProxyModel) + 16)
+ QAbstractProxyModel (0x0x7faa674bc270) 0
+ primary-for QTransposeProxyModel (0x0x7faa674bc208)
+ QAbstractItemModel (0x0x7faa674bc2d8) 0
+ primary-for QAbstractProxyModel (0x0x7faa674bc270)
+ QObject (0x0x7faa674a6de0) 0
+ primary-for QAbstractItemModel (0x0x7faa674bc2d8)
+
+Class QUrlQuery
+ size=8 align=8
+ base size=8 base align=8
+QUrlQuery (0x0x7faa674ec060) 0
+
+Class QWaitCondition
+ size=8 align=8
+ base size=8 base align=8
+QWaitCondition (0x0x7faa675c3540) 0
+
+Class QXmlStreamStringRef
+ size=16 align=8
+ base size=16 base align=8
+QXmlStreamStringRef (0x0x7faa675c3660) 0
+
+Class QXmlStreamAttribute
+ size=80 align=8
+ base size=73 base align=8
+QXmlStreamAttribute (0x0x7faa67154a20) 0
+
+Class QXmlStreamAttributes
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamAttributes (0x0x7faa671c75b0) 0
+ QVector<QXmlStreamAttribute> (0x0x7faa671cd180) 0
+
+Class QXmlStreamNamespaceDeclaration
+ size=40 align=8
+ base size=40 base align=8
+QXmlStreamNamespaceDeclaration (0x0x7faa671cd480) 0
+
+Class QXmlStreamNotationDeclaration
+ size=56 align=8
+ base size=56 base align=8
+QXmlStreamNotationDeclaration (0x0x7faa67259420) 0
+
+Class QXmlStreamEntityDeclaration
+ size=88 align=8
+ base size=88 base align=8
+QXmlStreamEntityDeclaration (0x0x7faa672b7420) 0
+
+Vtable for QXmlStreamEntityResolver
+QXmlStreamEntityResolver::_ZTV24QXmlStreamEntityResolver: 6 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI24QXmlStreamEntityResolver)
+16 (int (*)(...))QXmlStreamEntityResolver::~QXmlStreamEntityResolver
+24 (int (*)(...))QXmlStreamEntityResolver::~QXmlStreamEntityResolver
+32 (int (*)(...))QXmlStreamEntityResolver::resolveEntity
+40 (int (*)(...))QXmlStreamEntityResolver::resolveUndeclaredEntity
+
+Class QXmlStreamEntityResolver
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamEntityResolver (0x0x7faa673224e0) 0 nearly-empty
+ vptr=((& QXmlStreamEntityResolver::_ZTV24QXmlStreamEntityResolver) + 16)
+
+Class QXmlStreamReader
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamReader (0x0x7faa67322540) 0
+
+Class QXmlStreamWriter
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamWriter (0x0x7faa66f7f420) 0
+
+Class QBluetoothAddress
+ size=8 align=8
+ base size=8 base align=8
+QBluetoothAddress (0x0x7faa66fe53c0) 0
+
+Class QBluetoothDeviceInfo
+ size=8 align=8
+ base size=8 base align=8
+QBluetoothDeviceInfo (0x0x7faa66fe5720) 0
+
+Class QBluetoothDeviceDiscoveryAgent::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QBluetoothDeviceDiscoveryAgent::QPrivateSignal (0x0x7faa6704f840) 0 empty
+
+Vtable for QBluetoothDeviceDiscoveryAgent
+QBluetoothDeviceDiscoveryAgent::_ZTV30QBluetoothDeviceDiscoveryAgent: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI30QBluetoothDeviceDiscoveryAgent)
+16 (int (*)(...))QBluetoothDeviceDiscoveryAgent::metaObject
+24 (int (*)(...))QBluetoothDeviceDiscoveryAgent::qt_metacast
+32 (int (*)(...))QBluetoothDeviceDiscoveryAgent::qt_metacall
+40 (int (*)(...))QBluetoothDeviceDiscoveryAgent::~QBluetoothDeviceDiscoveryAgent
+48 (int (*)(...))QBluetoothDeviceDiscoveryAgent::~QBluetoothDeviceDiscoveryAgent
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QBluetoothDeviceDiscoveryAgent
+ size=24 align=8
+ base size=24 base align=8
+QBluetoothDeviceDiscoveryAgent (0x0x7faa66f805b0) 0
+ vptr=((& QBluetoothDeviceDiscoveryAgent::_ZTV30QBluetoothDeviceDiscoveryAgent) + 16)
+ QObject (0x0x7faa6704f7e0) 0
+ primary-for QBluetoothDeviceDiscoveryAgent (0x0x7faa66f805b0)
+
+Class QBluetoothHostInfo
+ size=8 align=8
+ base size=8 base align=8
+QBluetoothHostInfo (0x0x7faa670b7360) 0
+
+Class QBluetoothLocalDevice::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QBluetoothLocalDevice::QPrivateSignal (0x0x7faa670b76c0) 0 empty
+
+Vtable for QBluetoothLocalDevice
+QBluetoothLocalDevice::_ZTV21QBluetoothLocalDevice: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QBluetoothLocalDevice)
+16 (int (*)(...))QBluetoothLocalDevice::metaObject
+24 (int (*)(...))QBluetoothLocalDevice::qt_metacast
+32 (int (*)(...))QBluetoothLocalDevice::qt_metacall
+40 (int (*)(...))QBluetoothLocalDevice::~QBluetoothLocalDevice
+48 (int (*)(...))QBluetoothLocalDevice::~QBluetoothLocalDevice
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QBluetoothLocalDevice
+ size=24 align=8
+ base size=24 base align=8
+QBluetoothLocalDevice (0x0x7faa66f806e8) 0
+ vptr=((& QBluetoothLocalDevice::_ZTV21QBluetoothLocalDevice) + 16)
+ QObject (0x0x7faa670b7660) 0
+ primary-for QBluetoothLocalDevice (0x0x7faa66f806e8)
+
+Class quint128
+ size=16 align=1
+ base size=16 base align=1
+quint128 (0x0x7faa670fb0c0) 0
+
+Class QBluetoothUuid
+ size=16 align=4
+ base size=16 base align=4
+QBluetoothUuid (0x0x7faa66f80750) 0
+ QUuid (0x0x7faa670fb120) 0
+
+Class QBluetoothServiceInfo::Sequence
+ size=8 align=8
+ base size=8 base align=8
+QBluetoothServiceInfo::Sequence (0x0x7faa66f807b8) 0
+ QList<QVariant> (0x0x7faa66f80820) 0
+ QListSpecialMethods<QVariant> (0x0x7faa670fb660) 0 empty
+
+Class QBluetoothServiceInfo::Alternative
+ size=8 align=8
+ base size=8 base align=8
+QBluetoothServiceInfo::Alternative (0x0x7faa66f80888) 0
+ QList<QVariant> (0x0x7faa66f808f0) 0
+ QListSpecialMethods<QVariant> (0x0x7faa670fb6c0) 0 empty
+
+Class QBluetoothServiceInfo
+ size=16 align=8
+ base size=16 base align=8
+QBluetoothServiceInfo (0x0x7faa670fb600) 0
+
+Class QAbstractSocket::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractSocket::QPrivateSignal (0x0x7faa66d848a0) 0 empty
+
+Vtable for QAbstractSocket
+QAbstractSocket::_ZTV15QAbstractSocket: 41 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QAbstractSocket)
+16 (int (*)(...))QAbstractSocket::metaObject
+24 (int (*)(...))QAbstractSocket::qt_metacast
+32 (int (*)(...))QAbstractSocket::qt_metacall
+40 (int (*)(...))QAbstractSocket::~QAbstractSocket
+48 (int (*)(...))QAbstractSocket::~QAbstractSocket
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractSocket::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QAbstractSocket::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QAbstractSocket::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QAbstractSocket::bytesAvailable
+184 (int (*)(...))QAbstractSocket::bytesToWrite
+192 (int (*)(...))QAbstractSocket::canReadLine
+200 (int (*)(...))QAbstractSocket::waitForReadyRead
+208 (int (*)(...))QAbstractSocket::waitForBytesWritten
+216 (int (*)(...))QAbstractSocket::readData
+224 (int (*)(...))QAbstractSocket::readLineData
+232 (int (*)(...))QAbstractSocket::writeData
+240 (int (*)(...))QAbstractSocket::resume
+248 (int (*)(...))QAbstractSocket::connectToHost
+256 (int (*)(...))QAbstractSocket::connectToHost
+264 (int (*)(...))QAbstractSocket::disconnectFromHost
+272 (int (*)(...))QAbstractSocket::setReadBufferSize
+280 (int (*)(...))QAbstractSocket::socketDescriptor
+288 (int (*)(...))QAbstractSocket::setSocketDescriptor
+296 (int (*)(...))QAbstractSocket::setSocketOption
+304 (int (*)(...))QAbstractSocket::socketOption
+312 (int (*)(...))QAbstractSocket::waitForConnected
+320 (int (*)(...))QAbstractSocket::waitForDisconnected
+
+Class QAbstractSocket
+ size=16 align=8
+ base size=16 base align=8
+QAbstractSocket (0x0x7faa66f80958) 0
+ vptr=((& QAbstractSocket::_ZTV15QAbstractSocket) + 16)
+ QIODevice (0x0x7faa66f809c0) 0
+ primary-for QAbstractSocket (0x0x7faa66f80958)
+ QObject (0x0x7faa66d84840) 0
+ primary-for QIODevice (0x0x7faa66f809c0)
+
+Class QBluetoothSocket::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QBluetoothSocket::QPrivateSignal (0x0x7faa66e37060) 0 empty
+
+Vtable for QBluetoothSocket
+QBluetoothSocket::_ZTV16QBluetoothSocket: 30 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QBluetoothSocket)
+16 (int (*)(...))QBluetoothSocket::metaObject
+24 (int (*)(...))QBluetoothSocket::qt_metacast
+32 (int (*)(...))QBluetoothSocket::qt_metacall
+40 (int (*)(...))QBluetoothSocket::~QBluetoothSocket
+48 (int (*)(...))QBluetoothSocket::~QBluetoothSocket
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QBluetoothSocket::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QBluetoothSocket::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QIODevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QBluetoothSocket::bytesAvailable
+184 (int (*)(...))QBluetoothSocket::bytesToWrite
+192 (int (*)(...))QBluetoothSocket::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QBluetoothSocket::readData
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QBluetoothSocket::writeData
+
+Class QBluetoothSocket
+ size=24 align=8
+ base size=24 base align=8
+QBluetoothSocket (0x0x7faa66f80bc8) 0
+ vptr=((& QBluetoothSocket::_ZTV16QBluetoothSocket) + 16)
+ QIODevice (0x0x7faa66f80c30) 0
+ primary-for QBluetoothSocket (0x0x7faa66f80bc8)
+ QObject (0x0x7faa66e37000) 0
+ primary-for QIODevice (0x0x7faa66f80c30)
+
+Class QBluetoothServer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QBluetoothServer::QPrivateSignal (0x0x7faa66e37480) 0 empty
+
+Vtable for QBluetoothServer
+QBluetoothServer::_ZTV16QBluetoothServer: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QBluetoothServer)
+16 (int (*)(...))QBluetoothServer::metaObject
+24 (int (*)(...))QBluetoothServer::qt_metacast
+32 (int (*)(...))QBluetoothServer::qt_metacall
+40 (int (*)(...))QBluetoothServer::~QBluetoothServer
+48 (int (*)(...))QBluetoothServer::~QBluetoothServer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QBluetoothServer
+ size=24 align=8
+ base size=24 base align=8
+QBluetoothServer (0x0x7faa66f80c98) 0
+ vptr=((& QBluetoothServer::_ZTV16QBluetoothServer) + 16)
+ QObject (0x0x7faa66e37420) 0
+ primary-for QBluetoothServer (0x0x7faa66f80c98)
+
+Class QBluetoothServiceDiscoveryAgent::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QBluetoothServiceDiscoveryAgent::QPrivateSignal (0x0x7faa66e37780) 0 empty
+
+Vtable for QBluetoothServiceDiscoveryAgent
+QBluetoothServiceDiscoveryAgent::_ZTV31QBluetoothServiceDiscoveryAgent: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI31QBluetoothServiceDiscoveryAgent)
+16 (int (*)(...))QBluetoothServiceDiscoveryAgent::metaObject
+24 (int (*)(...))QBluetoothServiceDiscoveryAgent::qt_metacast
+32 (int (*)(...))QBluetoothServiceDiscoveryAgent::qt_metacall
+40 (int (*)(...))QBluetoothServiceDiscoveryAgent::~QBluetoothServiceDiscoveryAgent
+48 (int (*)(...))QBluetoothServiceDiscoveryAgent::~QBluetoothServiceDiscoveryAgent
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QBluetoothServiceDiscoveryAgent
+ size=24 align=8
+ base size=24 base align=8
+QBluetoothServiceDiscoveryAgent (0x0x7faa66f80d00) 0
+ vptr=((& QBluetoothServiceDiscoveryAgent::_ZTV31QBluetoothServiceDiscoveryAgent) + 16)
+ QObject (0x0x7faa66e37720) 0
+ primary-for QBluetoothServiceDiscoveryAgent (0x0x7faa66f80d00)
+
+Class QBluetoothTransferManager::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QBluetoothTransferManager::QPrivateSignal (0x0x7faa66e37b40) 0 empty
+
+Vtable for QBluetoothTransferManager
+QBluetoothTransferManager::_ZTV25QBluetoothTransferManager: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI25QBluetoothTransferManager)
+16 (int (*)(...))QBluetoothTransferManager::metaObject
+24 (int (*)(...))QBluetoothTransferManager::qt_metacast
+32 (int (*)(...))QBluetoothTransferManager::qt_metacall
+40 (int (*)(...))QBluetoothTransferManager::~QBluetoothTransferManager
+48 (int (*)(...))QBluetoothTransferManager::~QBluetoothTransferManager
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QBluetoothTransferManager
+ size=16 align=8
+ base size=16 base align=8
+QBluetoothTransferManager (0x0x7faa66f80d68) 0
+ vptr=((& QBluetoothTransferManager::_ZTV25QBluetoothTransferManager) + 16)
+ QObject (0x0x7faa66e37ae0) 0
+ primary-for QBluetoothTransferManager (0x0x7faa66f80d68)
+
+Class QBluetoothTransferRequest
+ size=8 align=8
+ base size=8 base align=8
+QBluetoothTransferRequest (0x0x7faa66e37c60) 0
+
+Class QBluetoothTransferReply::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QBluetoothTransferReply::QPrivateSignal (0x0x7faa66e37de0) 0 empty
+
+Vtable for QBluetoothTransferReply
+QBluetoothTransferReply::_ZTV23QBluetoothTransferReply: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI23QBluetoothTransferReply)
+16 (int (*)(...))QBluetoothTransferReply::metaObject
+24 (int (*)(...))QBluetoothTransferReply::qt_metacast
+32 (int (*)(...))QBluetoothTransferReply::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))__cxa_pure_virtual
+136 (int (*)(...))__cxa_pure_virtual
+
+Class QBluetoothTransferReply
+ size=24 align=8
+ base size=24 base align=8
+QBluetoothTransferReply (0x0x7faa66f80dd0) 0
+ vptr=((& QBluetoothTransferReply::_ZTV23QBluetoothTransferReply) + 16)
+ QObject (0x0x7faa66e37d80) 0
+ primary-for QBluetoothTransferReply (0x0x7faa66f80dd0)
+
+Class QLowEnergyAdvertisingData
+ size=8 align=8
+ base size=8 base align=8
+QLowEnergyAdvertisingData (0x0x7faa66ea72a0) 0
+
+Class QLowEnergyDescriptor
+ size=24 align=8
+ base size=24 base align=8
+QLowEnergyDescriptor (0x0x7faa66b764e0) 0
+
+Class QLowEnergyCharacteristic
+ size=24 align=8
+ base size=24 base align=8
+QLowEnergyCharacteristic (0x0x7faa66b76780) 0
+
+Class QLowEnergyService::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QLowEnergyService::QPrivateSignal (0x0x7faa66bf0120) 0 empty
+
+Vtable for QLowEnergyService
+QLowEnergyService::_ZTV17QLowEnergyService: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QLowEnergyService)
+16 (int (*)(...))QLowEnergyService::metaObject
+24 (int (*)(...))QLowEnergyService::qt_metacast
+32 (int (*)(...))QLowEnergyService::qt_metacall
+40 (int (*)(...))QLowEnergyService::~QLowEnergyService
+48 (int (*)(...))QLowEnergyService::~QLowEnergyService
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QLowEnergyService
+ size=32 align=8
+ base size=32 base align=8
+QLowEnergyService (0x0x7faa66bc50d0) 0
+ vptr=((& QLowEnergyService::_ZTV17QLowEnergyService) + 16)
+ QObject (0x0x7faa66bf00c0) 0
+ primary-for QLowEnergyService (0x0x7faa66bc50d0)
+
+Class QLowEnergyController::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QLowEnergyController::QPrivateSignal (0x0x7faa66c4a4e0) 0 empty
+
+Vtable for QLowEnergyController
+QLowEnergyController::_ZTV20QLowEnergyController: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QLowEnergyController)
+16 (int (*)(...))QLowEnergyController::metaObject
+24 (int (*)(...))QLowEnergyController::qt_metacast
+32 (int (*)(...))QLowEnergyController::qt_metacall
+40 (int (*)(...))QLowEnergyController::~QLowEnergyController
+48 (int (*)(...))QLowEnergyController::~QLowEnergyController
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QLowEnergyController
+ size=24 align=8
+ base size=24 base align=8
+QLowEnergyController (0x0x7faa66bc5208) 0
+ vptr=((& QLowEnergyController::_ZTV20QLowEnergyController) + 16)
+ QObject (0x0x7faa66c4a480) 0
+ primary-for QLowEnergyController (0x0x7faa66bc5208)
+
+Class QLowEnergyAdvertisingParameters::AddressInfo
+ size=16 align=8
+ base size=12 base align=8
+QLowEnergyAdvertisingParameters::AddressInfo (0x0x7faa66c941e0) 0
+
+Class QLowEnergyAdvertisingParameters
+ size=8 align=8
+ base size=8 base align=8
+QLowEnergyAdvertisingParameters (0x0x7faa66c94180) 0
+
+Class QLowEnergyCharacteristicData
+ size=8 align=8
+ base size=8 base align=8
+QLowEnergyCharacteristicData (0x0x7faa66965f00) 0
+
+Class QLowEnergyConnectionParameters
+ size=8 align=8
+ base size=8 base align=8
+QLowEnergyConnectionParameters (0x0x7faa66a56060) 0
+
+Class QLowEnergyDescriptorData
+ size=8 align=8
+ base size=8 base align=8
+QLowEnergyDescriptorData (0x0x7faa66b1b420) 0
+
+Class QLowEnergyServiceData
+ size=8 align=8
+ base size=8 base align=8
+QLowEnergyServiceData (0x0x7faa667e3900) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa668fc000) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa668fc360) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa668fc540) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa668fc8a0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa668fca80) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa668fcde0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa6693a000) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa6693a360) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa6693a540) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa6693a8a0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa6693aa80) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa6693ade0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa66570000) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa66570360) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa66570540) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa665708a0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa6659dd80) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa665cc120) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa665cc2a0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa665cc600) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa665cc780) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa665ccae0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa665ccc60) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa665fd000) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa665fd180) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa665fd4e0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa665fd660) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa665fd9c0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa665fdb40) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa665fdea0) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7faa6662d060) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7faa6662d3c0) 0 empty
+
diff --git a/tests/auto/bic/data/QtNfc.5.14.0.linux-gcc-amd64.txt b/tests/auto/bic/data/QtNfc.5.14.0.linux-gcc-amd64.txt
new file mode 100644
index 00000000..ce605a5a
--- /dev/null
+++ b/tests/auto/bic/data/QtNfc.5.14.0.linux-gcc-amd64.txt
@@ -0,0 +1,5228 @@
+Class std::__failure_type
+ size=1 align=1
+ base size=0 base align=1
+std::__failure_type (0x0x7fb80aaea0c0) 0 empty
+
+Class std::__do_is_destructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_destructible_impl (0x0x7fb80ab30840) 0 empty
+
+Class std::__do_is_nt_destructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_nt_destructible_impl (0x0x7fb80ab30a80) 0 empty
+
+Class std::__do_is_default_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_default_constructible_impl (0x0x7fb80ab30cc0) 0 empty
+
+Class std::__do_is_static_castable_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_static_castable_impl (0x0x7fb80ab30f00) 0 empty
+
+Class std::__do_is_direct_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_direct_constructible_impl (0x0x7fb80ab600c0) 0 empty
+
+Class std::__do_is_nary_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_nary_constructible_impl (0x0x7fb80ab60480) 0 empty
+
+Class std::__do_is_implicitly_default_constructible_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_is_implicitly_default_constructible_impl (0x0x7fb80ab9b5a0) 0 empty
+
+Class std::__do_common_type_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__do_common_type_impl (0x0x7fb80abf1c60) 0 empty
+
+Class std::__do_member_type_wrapper
+ size=1 align=1
+ base size=0 base align=1
+std::__do_member_type_wrapper (0x0x7fb80abf1d20) 0 empty
+
+Class std::__invoke_memfun_ref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memfun_ref (0x0x7fb80ac21120) 0 empty
+
+Class std::__invoke_memfun_deref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memfun_deref (0x0x7fb80ac21180) 0 empty
+
+Class std::__invoke_memobj_ref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memobj_ref (0x0x7fb80ac211e0) 0 empty
+
+Class std::__invoke_memobj_deref
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_memobj_deref (0x0x7fb80ac21240) 0 empty
+
+Class std::__invoke_other
+ size=1 align=1
+ base size=0 base align=1
+std::__invoke_other (0x0x7fb80ac212a0) 0 empty
+
+Class std::__result_of_memfun_ref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memfun_ref_impl (0x0x7fb80ac21360) 0 empty
+
+Class std::__result_of_memfun_deref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memfun_deref_impl (0x0x7fb80ac21420) 0 empty
+
+Class std::__result_of_memobj_ref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memobj_ref_impl (0x0x7fb80ac214e0) 0 empty
+
+Class std::__result_of_memobj_deref_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_memobj_deref_impl (0x0x7fb80ac215a0) 0 empty
+
+Class std::__result_of_other_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__result_of_other_impl (0x0x7fb80ac21900) 0 empty
+
+Class std::__swappable_details::__do_is_swappable_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__swappable_details::__do_is_swappable_impl (0x0x7fb80ac21c60) 0 empty
+
+Class std::__swappable_details::__do_is_nothrow_swappable_impl
+ size=1 align=1
+ base size=0 base align=1
+std::__swappable_details::__do_is_nothrow_swappable_impl (0x0x7fb80ac21cc0) 0 empty
+
+Class std::__nonesuch
+ size=1 align=1
+ base size=0 base align=1
+std::__nonesuch (0x0x7fb80a8682a0) 0 empty
+
+Class std::piecewise_construct_t
+ size=1 align=1
+ base size=0 base align=1
+std::piecewise_construct_t (0x0x7fb80a868900) 0 empty
+
+Class std::__nonesuch_no_braces
+ size=1 align=1
+ base size=1 base align=1
+std::__nonesuch_no_braces (0x0x7fb80a85f3a8) 0 empty
+ std::__nonesuch (0x0x7fb80a868de0) 0 empty
+
+Class std::__true_type
+ size=1 align=1
+ base size=0 base align=1
+std::__true_type (0x0x7fb80a8ec780) 0 empty
+
+Class std::__false_type
+ size=1 align=1
+ base size=0 base align=1
+std::__false_type (0x0x7fb80a8ec7e0) 0 empty
+
+Class std::input_iterator_tag
+ size=1 align=1
+ base size=0 base align=1
+std::input_iterator_tag (0x0x7fb80a9464e0) 0 empty
+
+Class std::output_iterator_tag
+ size=1 align=1
+ base size=0 base align=1
+std::output_iterator_tag (0x0x7fb80a946540) 0 empty
+
+Class std::forward_iterator_tag
+ size=1 align=1
+ base size=1 base align=1
+std::forward_iterator_tag (0x0x7fb80a85f888) 0 empty
+ std::input_iterator_tag (0x0x7fb80a9465a0) 0 empty
+
+Class std::bidirectional_iterator_tag
+ size=1 align=1
+ base size=1 base align=1
+std::bidirectional_iterator_tag (0x0x7fb80a85f8f0) 0 empty
+ std::forward_iterator_tag (0x0x7fb80a85f958) 0 empty
+ std::input_iterator_tag (0x0x7fb80a946600) 0 empty
+
+Class std::random_access_iterator_tag
+ size=1 align=1
+ base size=1 base align=1
+std::random_access_iterator_tag (0x0x7fb80a85f9c0) 0 empty
+ std::bidirectional_iterator_tag (0x0x7fb80a85fa28) 0 empty
+ std::forward_iterator_tag (0x0x7fb80a85fa90) 0 empty
+ std::input_iterator_tag (0x0x7fb80a946660) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_less_iter
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_less_iter (0x0x7fb80a9fe180) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_less_val
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_less_val (0x0x7fb80a9fe2a0) 0 empty
+
+Class __gnu_cxx::__ops::_Val_less_iter
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Val_less_iter (0x0x7fb80a9fe5a0) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_equal_to_iter
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_equal_to_iter (0x0x7fb80a9fe8a0) 0 empty
+
+Class __gnu_cxx::__ops::_Iter_equal_to_val
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__ops::_Iter_equal_to_val (0x0x7fb80a9fe9c0) 0 empty
+
+Class __locale_struct
+ size=232 align=8
+ base size=232 base align=8
+__locale_struct (0x0x7fb80a687cc0) 0
+
+Class timeval
+ size=16 align=8
+ base size=16 base align=8
+timeval (0x0x7fb80a6cf000) 0
+
+Class timespec
+ size=16 align=8
+ base size=16 base align=8
+timespec (0x0x7fb80a6cf060) 0
+
+Class __pthread_rwlock_arch_t
+ size=56 align=8
+ base size=56 base align=8
+__pthread_rwlock_arch_t (0x0x7fb80a6cf120) 0
+
+Class __pthread_internal_list
+ size=16 align=8
+ base size=16 base align=8
+__pthread_internal_list (0x0x7fb80a6cf180) 0
+
+Class __pthread_mutex_s
+ size=40 align=8
+ base size=40 base align=8
+__pthread_mutex_s (0x0x7fb80a6cf1e0) 0
+
+Class __pthread_cond_s
+ size=48 align=8
+ base size=48 base align=8
+__pthread_cond_s (0x0x7fb80a6cf240) 0
+
+Class pthread_attr_t
+ size=56 align=8
+ base size=56 base align=8
+pthread_attr_t (0x0x7fb80a6cf4e0) 0
+
+Class random_data
+ size=48 align=8
+ base size=48 base align=8
+random_data (0x0x7fb80a6cf780) 0
+
+Class drand48_data
+ size=24 align=8
+ base size=24 base align=8
+drand48_data (0x0x7fb80a6cf7e0) 0
+
+Vtable for std::exception
+std::exception::_ZTVSt9exception: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt9exception)
+16 (int (*)(...))std::exception::~exception
+24 (int (*)(...))std::exception::~exception
+32 (int (*)(...))std::exception::what
+
+Class std::exception
+ size=8 align=8
+ base size=8 base align=8
+std::exception (0x0x7fb80a7865a0) 0 nearly-empty
+ vptr=((& std::exception::_ZTVSt9exception) + 16)
+
+Vtable for std::bad_exception
+std::bad_exception::_ZTVSt13bad_exception: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt13bad_exception)
+16 (int (*)(...))std::bad_exception::~bad_exception
+24 (int (*)(...))std::bad_exception::~bad_exception
+32 (int (*)(...))std::bad_exception::what
+
+Class std::bad_exception
+ size=8 align=8
+ base size=8 base align=8
+std::bad_exception (0x0x7fb80a85fdd0) 0 nearly-empty
+ vptr=((& std::bad_exception::_ZTVSt13bad_exception) + 16)
+ std::exception (0x0x7fb80a786780) 0 nearly-empty
+ primary-for std::bad_exception (0x0x7fb80a85fdd0)
+
+Vtable for std::type_info
+std::type_info::_ZTVSt9type_info: 8 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt9type_info)
+16 (int (*)(...))std::type_info::~type_info
+24 (int (*)(...))std::type_info::~type_info
+32 (int (*)(...))std::type_info::__is_pointer_p
+40 (int (*)(...))std::type_info::__is_function_p
+48 (int (*)(...))std::type_info::__do_catch
+56 (int (*)(...))std::type_info::__do_upcast
+
+Class std::type_info
+ size=16 align=8
+ base size=16 base align=8
+std::type_info (0x0x7fb80a786960) 0
+ vptr=((& std::type_info::_ZTVSt9type_info) + 16)
+
+Vtable for std::bad_cast
+std::bad_cast::_ZTVSt8bad_cast: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt8bad_cast)
+16 (int (*)(...))std::bad_cast::~bad_cast
+24 (int (*)(...))std::bad_cast::~bad_cast
+32 (int (*)(...))std::bad_cast::what
+
+Class std::bad_cast
+ size=8 align=8
+ base size=8 base align=8
+std::bad_cast (0x0x7fb80a85fe38) 0 nearly-empty
+ vptr=((& std::bad_cast::_ZTVSt8bad_cast) + 16)
+ std::exception (0x0x7fb80a786d20) 0 nearly-empty
+ primary-for std::bad_cast (0x0x7fb80a85fe38)
+
+Vtable for std::bad_typeid
+std::bad_typeid::_ZTVSt10bad_typeid: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt10bad_typeid)
+16 (int (*)(...))std::bad_typeid::~bad_typeid
+24 (int (*)(...))std::bad_typeid::~bad_typeid
+32 (int (*)(...))std::bad_typeid::what
+
+Class std::bad_typeid
+ size=8 align=8
+ base size=8 base align=8
+std::bad_typeid (0x0x7fb80a85fea0) 0 nearly-empty
+ vptr=((& std::bad_typeid::_ZTVSt10bad_typeid) + 16)
+ std::exception (0x0x7fb80a786f00) 0 nearly-empty
+ primary-for std::bad_typeid (0x0x7fb80a85fea0)
+
+Class std::__exception_ptr::exception_ptr
+ size=8 align=8
+ base size=8 base align=8
+std::__exception_ptr::exception_ptr (0x0x7fb80a7b6120) 0
+
+Vtable for std::nested_exception
+std::nested_exception::_ZTVSt16nested_exception: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt16nested_exception)
+16 (int (*)(...))std::nested_exception::~nested_exception
+24 (int (*)(...))std::nested_exception::~nested_exception
+
+Class std::nested_exception
+ size=16 align=8
+ base size=16 base align=8
+std::nested_exception (0x0x7fb80a7b66c0) 0
+ vptr=((& std::nested_exception::_ZTVSt16nested_exception) + 16)
+
+Vtable for std::bad_alloc
+std::bad_alloc::_ZTVSt9bad_alloc: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt9bad_alloc)
+16 (int (*)(...))std::bad_alloc::~bad_alloc
+24 (int (*)(...))std::bad_alloc::~bad_alloc
+32 (int (*)(...))std::bad_alloc::what
+
+Class std::bad_alloc
+ size=8 align=8
+ base size=8 base align=8
+std::bad_alloc (0x0x7fb80a85ff08) 0 nearly-empty
+ vptr=((& std::bad_alloc::_ZTVSt9bad_alloc) + 16)
+ std::exception (0x0x7fb80a7b6d80) 0 nearly-empty
+ primary-for std::bad_alloc (0x0x7fb80a85ff08)
+
+Vtable for std::bad_array_new_length
+std::bad_array_new_length::_ZTVSt20bad_array_new_length: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt20bad_array_new_length)
+16 (int (*)(...))std::bad_array_new_length::~bad_array_new_length
+24 (int (*)(...))std::bad_array_new_length::~bad_array_new_length
+32 (int (*)(...))std::bad_array_new_length::what
+
+Class std::bad_array_new_length
+ size=8 align=8
+ base size=8 base align=8
+std::bad_array_new_length (0x0x7fb80a85ff70) 0 nearly-empty
+ vptr=((& std::bad_array_new_length::_ZTVSt20bad_array_new_length) + 16)
+ std::bad_alloc (0x0x7fb80a7e9000) 0 nearly-empty
+ primary-for std::bad_array_new_length (0x0x7fb80a85ff70)
+ std::exception (0x0x7fb80a7b6f60) 0 nearly-empty
+ primary-for std::bad_alloc (0x0x7fb80a7e9000)
+
+Class std::nothrow_t
+ size=1 align=1
+ base size=0 base align=1
+std::nothrow_t (0x0x7fb80a7ef180) 0 empty
+
+Class std::__allocator_traits_base
+ size=1 align=1
+ base size=0 base align=1
+std::__allocator_traits_base (0x0x7fb80a7ef360) 0 empty
+
+Class std::__numeric_limits_base
+ size=1 align=1
+ base size=0 base align=1
+std::__numeric_limits_base (0x0x7fb80a464840) 0 empty
+
+Class QSysInfo
+ size=1 align=1
+ base size=0 base align=1
+QSysInfo (0x0x7fb80a0dcd80) 0 empty
+
+Class QMessageLogContext
+ size=32 align=8
+ base size=32 base align=8
+QMessageLogContext (0x0x7fb80a0dcea0) 0
+
+Class QMessageLogger
+ size=32 align=8
+ base size=32 base align=8
+QMessageLogger (0x0x7fb80a1120c0) 0
+
+Class QFlag
+ size=4 align=4
+ base size=4 base align=4
+QFlag (0x0x7fb80a112780) 0
+
+Class QIncompatibleFlag
+ size=4 align=4
+ base size=4 base align=4
+QIncompatibleFlag (0x0x7fb80a159f00) 0
+
+Class std::__atomic_flag_base
+ size=1 align=1
+ base size=1 base align=1
+std::__atomic_flag_base (0x0x7fb80a208420) 0
+
+Class std::atomic_flag
+ size=1 align=1
+ base size=1 base align=1
+std::atomic_flag (0x0x7fb80a19be38) 0
+ std::__atomic_flag_base (0x0x7fb80a208480) 0
+
+Class QAtomicInt
+ size=4 align=4
+ base size=4 base align=4
+QAtomicInt (0x0x7fb809f515b0) 0
+ QAtomicInteger<int> (0x0x7fb809f51618) 0
+ QBasicAtomicInteger<int> (0x0x7fb809d3d6c0) 0
+
+Class QInternal
+ size=1 align=1
+ base size=0 base align=1
+QInternal (0x0x7fb809998240) 0 empty
+
+Class QtPrivate::QSlotObjectBase
+ size=16 align=8
+ base size=16 base align=8
+QtPrivate::QSlotObjectBase (0x0x7fb8099db7e0) 0
+
+Class QGenericArgument
+ size=16 align=8
+ base size=16 base align=8
+QGenericArgument (0x0x7fb8099dbf00) 0
+
+Class QGenericReturnArgument
+ size=16 align=8
+ base size=16 base align=8
+QGenericReturnArgument (0x0x7fb809a0d270) 0
+ QGenericArgument (0x0x7fb809a1b1e0) 0
+
+Class QMetaObject::SuperData
+ size=8 align=8
+ base size=8 base align=8
+QMetaObject::SuperData (0x0x7fb809a1b660) 0
+
+Class QMetaObject
+ size=48 align=8
+ base size=48 base align=8
+QMetaObject (0x0x7fb809a1b600) 0
+
+Class QMetaObject::Connection
+ size=8 align=8
+ base size=8 base align=8
+QMetaObject::Connection (0x0x7fb809a1bf00) 0
+
+Class QLatin1Char
+ size=1 align=1
+ base size=1 base align=1
+QLatin1Char (0x0x7fb8096caa20) 0
+
+Class QChar
+ size=2 align=2
+ base size=2 base align=2
+QChar (0x0x7fb8096ee180) 0
+
+Class QtPrivate::RefCount
+ size=4 align=4
+ base size=4 base align=4
+QtPrivate::RefCount (0x0x7fb80979ef60) 0
+
+Class QArrayData
+ size=24 align=8
+ base size=24 base align=8
+QArrayData (0x0x7fb8097c4300) 0
+
+Class QtPrivate::QContainerImplHelper
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::QContainerImplHelper (0x0x7fb809826600) 0 empty
+
+Class lconv
+ size=96 align=8
+ base size=96 base align=8
+lconv (0x0x7fb8094d6e40) 0
+
+Vtable for __cxxabiv1::__forced_unwind
+__cxxabiv1::__forced_unwind::_ZTVN10__cxxabiv115__forced_unwindE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN10__cxxabiv115__forced_unwindE)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class __cxxabiv1::__forced_unwind
+ size=8 align=8
+ base size=8 base align=8
+__cxxabiv1::__forced_unwind (0x0x7fb8094d6f00) 0 nearly-empty
+ vptr=((& __cxxabiv1::__forced_unwind::_ZTVN10__cxxabiv115__forced_unwindE) + 16)
+
+Class sched_param
+ size=4 align=4
+ base size=4 base align=4
+sched_param (0x0x7fb8095ca060) 0
+
+Class timex
+ size=208 align=8
+ base size=208 base align=8
+timex (0x0x7fb8095ca120) 0
+
+Class tm
+ size=56 align=8
+ base size=56 base align=8
+tm (0x0x7fb8095ca180) 0
+
+Class itimerspec
+ size=32 align=8
+ base size=32 base align=8
+itimerspec (0x0x7fb8095ca1e0) 0
+
+Class _pthread_cleanup_buffer
+ size=32 align=8
+ base size=32 base align=8
+_pthread_cleanup_buffer (0x0x7fb8095ca240) 0
+
+Class __pthread_cleanup_frame
+ size=24 align=8
+ base size=24 base align=8
+__pthread_cleanup_frame (0x0x7fb8095ca360) 0
+
+Class __pthread_cleanup_class
+ size=24 align=8
+ base size=24 base align=8
+__pthread_cleanup_class (0x0x7fb8095ca3c0) 0
+
+Class _IO_marker
+ size=24 align=8
+ base size=24 base align=8
+_IO_marker (0x0x7fb80930f360) 0
+
+Class _IO_FILE
+ size=216 align=8
+ base size=216 base align=8
+_IO_FILE (0x0x7fb80930f3c0) 0
+
+Class std::_Hash_impl
+ size=1 align=1
+ base size=0 base align=1
+std::_Hash_impl (0x0x7fb8090c1420) 0 empty
+
+Class std::_Fnv_hash_impl
+ size=1 align=1
+ base size=0 base align=1
+std::_Fnv_hash_impl (0x0x7fb8090c15a0) 0 empty
+
+Class std::locale
+ size=8 align=8
+ base size=8 base align=8
+std::locale (0x0x7fb80923b720) 0
+
+Vtable for std::locale::facet
+std::locale::facet::_ZTVNSt6locale5facetE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt6locale5facetE)
+16 (int (*)(...))std::locale::facet::~facet
+24 (int (*)(...))std::locale::facet::~facet
+
+Class std::locale::facet
+ size=16 align=8
+ base size=12 base align=8
+std::locale::facet (0x0x7fb80923bae0) 0
+ vptr=((& std::locale::facet::_ZTVNSt6locale5facetE) + 16)
+
+Class std::locale::id
+ size=8 align=8
+ base size=8 base align=8
+std::locale::id (0x0x7fb80923bd80) 0
+
+Class std::locale::_Impl
+ size=40 align=8
+ base size=40 base align=8
+std::locale::_Impl (0x0x7fb80923bf60) 0
+
+Class std::__cow_string
+ size=8 align=8
+ base size=8 base align=8
+std::__cow_string (0x0x7fb808e95f60) 0
+
+Vtable for std::logic_error
+std::logic_error::_ZTVSt11logic_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt11logic_error)
+16 (int (*)(...))std::logic_error::~logic_error
+24 (int (*)(...))std::logic_error::~logic_error
+32 (int (*)(...))std::logic_error::what
+
+Class std::logic_error
+ size=16 align=8
+ base size=16 base align=8
+std::logic_error (0x0x7fb808ec8208) 0
+ vptr=((& std::logic_error::_ZTVSt11logic_error) + 16)
+ std::exception (0x0x7fb808edb060) 0 nearly-empty
+ primary-for std::logic_error (0x0x7fb808ec8208)
+
+Vtable for std::domain_error
+std::domain_error::_ZTVSt12domain_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12domain_error)
+16 (int (*)(...))std::domain_error::~domain_error
+24 (int (*)(...))std::domain_error::~domain_error
+32 (int (*)(...))std::logic_error::what
+
+Class std::domain_error
+ size=16 align=8
+ base size=16 base align=8
+std::domain_error (0x0x7fb808ec8270) 0
+ vptr=((& std::domain_error::_ZTVSt12domain_error) + 16)
+ std::logic_error (0x0x7fb808ec82d8) 0
+ primary-for std::domain_error (0x0x7fb808ec8270)
+ std::exception (0x0x7fb808edb0c0) 0 nearly-empty
+ primary-for std::logic_error (0x0x7fb808ec82d8)
+
+Vtable for std::invalid_argument
+std::invalid_argument::_ZTVSt16invalid_argument: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt16invalid_argument)
+16 (int (*)(...))std::invalid_argument::~invalid_argument
+24 (int (*)(...))std::invalid_argument::~invalid_argument
+32 (int (*)(...))std::logic_error::what
+
+Class std::invalid_argument
+ size=16 align=8
+ base size=16 base align=8
+std::invalid_argument (0x0x7fb808ec8340) 0
+ vptr=((& std::invalid_argument::_ZTVSt16invalid_argument) + 16)
+ std::logic_error (0x0x7fb808ec83a8) 0
+ primary-for std::invalid_argument (0x0x7fb808ec8340)
+ std::exception (0x0x7fb808edb120) 0 nearly-empty
+ primary-for std::logic_error (0x0x7fb808ec83a8)
+
+Vtable for std::length_error
+std::length_error::_ZTVSt12length_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12length_error)
+16 (int (*)(...))std::length_error::~length_error
+24 (int (*)(...))std::length_error::~length_error
+32 (int (*)(...))std::logic_error::what
+
+Class std::length_error
+ size=16 align=8
+ base size=16 base align=8
+std::length_error (0x0x7fb808ec8410) 0
+ vptr=((& std::length_error::_ZTVSt12length_error) + 16)
+ std::logic_error (0x0x7fb808ec8478) 0
+ primary-for std::length_error (0x0x7fb808ec8410)
+ std::exception (0x0x7fb808edb180) 0 nearly-empty
+ primary-for std::logic_error (0x0x7fb808ec8478)
+
+Vtable for std::out_of_range
+std::out_of_range::_ZTVSt12out_of_range: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12out_of_range)
+16 (int (*)(...))std::out_of_range::~out_of_range
+24 (int (*)(...))std::out_of_range::~out_of_range
+32 (int (*)(...))std::logic_error::what
+
+Class std::out_of_range
+ size=16 align=8
+ base size=16 base align=8
+std::out_of_range (0x0x7fb808ec84e0) 0
+ vptr=((& std::out_of_range::_ZTVSt12out_of_range) + 16)
+ std::logic_error (0x0x7fb808ec8548) 0
+ primary-for std::out_of_range (0x0x7fb808ec84e0)
+ std::exception (0x0x7fb808edb1e0) 0 nearly-empty
+ primary-for std::logic_error (0x0x7fb808ec8548)
+
+Vtable for std::runtime_error
+std::runtime_error::_ZTVSt13runtime_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt13runtime_error)
+16 (int (*)(...))std::runtime_error::~runtime_error
+24 (int (*)(...))std::runtime_error::~runtime_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::runtime_error
+ size=16 align=8
+ base size=16 base align=8
+std::runtime_error (0x0x7fb808ec85b0) 0
+ vptr=((& std::runtime_error::_ZTVSt13runtime_error) + 16)
+ std::exception (0x0x7fb808edb240) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7fb808ec85b0)
+
+Vtable for std::range_error
+std::range_error::_ZTVSt11range_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt11range_error)
+16 (int (*)(...))std::range_error::~range_error
+24 (int (*)(...))std::range_error::~range_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::range_error
+ size=16 align=8
+ base size=16 base align=8
+std::range_error (0x0x7fb808ec8618) 0
+ vptr=((& std::range_error::_ZTVSt11range_error) + 16)
+ std::runtime_error (0x0x7fb808ec8680) 0
+ primary-for std::range_error (0x0x7fb808ec8618)
+ std::exception (0x0x7fb808edb2a0) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7fb808ec8680)
+
+Vtable for std::overflow_error
+std::overflow_error::_ZTVSt14overflow_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt14overflow_error)
+16 (int (*)(...))std::overflow_error::~overflow_error
+24 (int (*)(...))std::overflow_error::~overflow_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::overflow_error
+ size=16 align=8
+ base size=16 base align=8
+std::overflow_error (0x0x7fb808ec86e8) 0
+ vptr=((& std::overflow_error::_ZTVSt14overflow_error) + 16)
+ std::runtime_error (0x0x7fb808ec8750) 0
+ primary-for std::overflow_error (0x0x7fb808ec86e8)
+ std::exception (0x0x7fb808edb300) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7fb808ec8750)
+
+Vtable for std::underflow_error
+std::underflow_error::_ZTVSt15underflow_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt15underflow_error)
+16 (int (*)(...))std::underflow_error::~underflow_error
+24 (int (*)(...))std::underflow_error::~underflow_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::underflow_error
+ size=16 align=8
+ base size=16 base align=8
+std::underflow_error (0x0x7fb808ec87b8) 0
+ vptr=((& std::underflow_error::_ZTVSt15underflow_error) + 16)
+ std::runtime_error (0x0x7fb808ec8820) 0
+ primary-for std::underflow_error (0x0x7fb808ec87b8)
+ std::exception (0x0x7fb808edb360) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7fb808ec8820)
+
+Vtable for std::_V2::error_category
+std::_V2::error_category::_ZTVNSt3_V214error_categoryE: 10 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt3_V214error_categoryE)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+40 (int (*)(...))std::_V2::error_category::_M_message
+48 (int (*)(...))__cxa_pure_virtual
+56 (int (*)(...))std::_V2::error_category::default_error_condition
+64 (int (*)(...))std::_V2::error_category::equivalent
+72 (int (*)(...))std::_V2::error_category::equivalent
+
+Class std::_V2::error_category
+ size=8 align=8
+ base size=8 base align=8
+std::_V2::error_category (0x0x7fb808edb4e0) 0 nearly-empty
+ vptr=((& std::_V2::error_category::_ZTVNSt3_V214error_categoryE) + 16)
+
+Class std::error_code
+ size=16 align=8
+ base size=16 base align=8
+std::error_code (0x0x7fb808edb840) 0
+
+Class std::error_condition
+ size=16 align=8
+ base size=16 base align=8
+std::error_condition (0x0x7fb808f2b0c0) 0
+
+Vtable for std::system_error
+std::system_error::_ZTVSt12system_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12system_error)
+16 (int (*)(...))std::system_error::~system_error
+24 (int (*)(...))std::system_error::~system_error
+32 (int (*)(...))std::runtime_error::what
+
+Class std::system_error
+ size=32 align=8
+ base size=32 base align=8
+std::system_error (0x0x7fb808ec8c30) 0
+ vptr=((& std::system_error::_ZTVSt12system_error) + 16)
+ std::runtime_error (0x0x7fb808ec8c98) 0
+ primary-for std::system_error (0x0x7fb808ec8c30)
+ std::exception (0x0x7fb808f2bc60) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7fb808ec8c98)
+
+Vtable for std::ios_base::failure
+std::ios_base::failure::_ZTVNSt8ios_base7failureB5cxx11E: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt8ios_base7failureB5cxx11E)
+16 (int (*)(...))std::ios_base::failure::~failure
+24 (int (*)(...))std::ios_base::failure::~failure
+32 (int (*)(...))std::ios_base::failure::what
+
+Class std::ios_base::failure
+ size=32 align=8
+ base size=32 base align=8
+std::ios_base::failure (0x0x7fb808ec8f08) 0
+ vptr=((& std::ios_base::failure::_ZTVNSt8ios_base7failureB5cxx11E) + 16)
+ std::system_error (0x0x7fb808ec8f70) 0
+ primary-for std::ios_base::failure (0x0x7fb808ec8f08)
+ std::runtime_error (0x0x7fb808f8e000) 0
+ primary-for std::system_error (0x0x7fb808ec8f70)
+ std::exception (0x0x7fb808f86240) 0 nearly-empty
+ primary-for std::runtime_error (0x0x7fb808f8e000)
+
+Class std::ios_base::_Callback_list
+ size=24 align=8
+ base size=24 base align=8
+std::ios_base::_Callback_list (0x0x7fb808f862a0) 0
+
+Class std::ios_base::_Words
+ size=16 align=8
+ base size=16 base align=8
+std::ios_base::_Words (0x0x7fb808f86300) 0
+
+Class std::ios_base::Init
+ size=1 align=1
+ base size=0 base align=1
+std::ios_base::Init (0x0x7fb808f86360) 0 empty
+
+Vtable for std::ios_base
+std::ios_base::_ZTVSt8ios_base: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt8ios_base)
+16 (int (*)(...))std::ios_base::~ios_base
+24 (int (*)(...))std::ios_base::~ios_base
+
+Class std::ios_base
+ size=216 align=8
+ base size=216 base align=8
+std::ios_base (0x0x7fb808f861e0) 0
+ vptr=((& std::ios_base::_ZTVSt8ios_base) + 16)
+
+Class std::ctype_base
+ size=1 align=1
+ base size=0 base align=1
+std::ctype_base (0x0x7fb809056c60) 0 empty
+
+Class std::__num_base
+ size=1 align=1
+ base size=0 base align=1
+std::__num_base (0x0x7fb808cffe40) 0 empty
+
+VTT for std::basic_ostream<char>
+std::basic_ostream<char>::_ZTTSo: 2 entries
+0 ((& std::basic_ostream<char>::_ZTVSo) + 24)
+8 ((& std::basic_ostream<char>::_ZTVSo) + 64)
+
+VTT for std::basic_ostream<wchar_t>
+std::basic_ostream<wchar_t>::_ZTTSt13basic_ostreamIwSt11char_traitsIwEE: 2 entries
+0 ((& std::basic_ostream<wchar_t>::_ZTVSt13basic_ostreamIwSt11char_traitsIwEE) + 24)
+8 ((& std::basic_ostream<wchar_t>::_ZTVSt13basic_ostreamIwSt11char_traitsIwEE) + 64)
+
+VTT for std::basic_istream<char>
+std::basic_istream<char>::_ZTTSi: 2 entries
+0 ((& std::basic_istream<char>::_ZTVSi) + 24)
+8 ((& std::basic_istream<char>::_ZTVSi) + 64)
+
+VTT for std::basic_istream<wchar_t>
+std::basic_istream<wchar_t>::_ZTTSt13basic_istreamIwSt11char_traitsIwEE: 2 entries
+0 ((& std::basic_istream<wchar_t>::_ZTVSt13basic_istreamIwSt11char_traitsIwEE) + 24)
+8 ((& std::basic_istream<wchar_t>::_ZTVSt13basic_istreamIwSt11char_traitsIwEE) + 64)
+
+Construction vtable for std::basic_istream<char> (0x0x7fb8088d06e8 instance) in std::basic_iostream<char>
+std::basic_iostream<char>::_ZTCSd0_Si: 10 entries
+0 24
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISi)
+24 0
+32 0
+40 18446744073709551592
+48 (int (*)(...))-24
+56 (int (*)(...))(& _ZTISi)
+64 0
+72 0
+
+Construction vtable for std::basic_ostream<char> (0x0x7fb8088d07b8 instance) in std::basic_iostream<char>
+std::basic_iostream<char>::_ZTCSd16_So: 10 entries
+0 8
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISo)
+24 0
+32 0
+40 18446744073709551608
+48 (int (*)(...))-8
+56 (int (*)(...))(& _ZTISo)
+64 0
+72 0
+
+VTT for std::basic_iostream<char>
+std::basic_iostream<char>::_ZTTSd: 7 entries
+0 ((& std::basic_iostream<char>::_ZTVSd) + 24)
+8 ((& std::basic_iostream<char>::_ZTCSd0_Si) + 24)
+16 ((& std::basic_iostream<char>::_ZTCSd0_Si) + 64)
+24 ((& std::basic_iostream<char>::_ZTCSd16_So) + 24)
+32 ((& std::basic_iostream<char>::_ZTCSd16_So) + 64)
+40 ((& std::basic_iostream<char>::_ZTVSd) + 104)
+48 ((& std::basic_iostream<char>::_ZTVSd) + 64)
+
+Construction vtable for std::basic_istream<wchar_t> (0x0x7fb80890e478 instance) in std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E: 10 entries
+0 24
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISt13basic_istreamIwSt11char_traitsIwEE)
+24 0
+32 0
+40 18446744073709551592
+48 (int (*)(...))-24
+56 (int (*)(...))(& _ZTISt13basic_istreamIwSt11char_traitsIwEE)
+64 0
+72 0
+
+Construction vtable for std::basic_ostream<wchar_t> (0x0x7fb80890e548 instance) in std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E: 10 entries
+0 8
+8 (int (*)(...))0
+16 (int (*)(...))(& _ZTISt13basic_ostreamIwSt11char_traitsIwEE)
+24 0
+32 0
+40 18446744073709551608
+48 (int (*)(...))-8
+56 (int (*)(...))(& _ZTISt13basic_ostreamIwSt11char_traitsIwEE)
+64 0
+72 0
+
+VTT for std::basic_iostream<wchar_t>
+std::basic_iostream<wchar_t>::_ZTTSt14basic_iostreamIwSt11char_traitsIwEE: 7 entries
+0 ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 24)
+8 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E) + 24)
+16 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE0_St13basic_istreamIwS1_E) + 64)
+24 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E) + 24)
+32 ((& std::basic_iostream<wchar_t>::_ZTCSt14basic_iostreamIwSt11char_traitsIwEE16_St13basic_ostreamIwS1_E) + 64)
+40 ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 104)
+48 ((& std::basic_iostream<wchar_t>::_ZTVSt14basic_iostreamIwSt11char_traitsIwEE) + 64)
+
+Class QByteArrayDataPtr
+ size=8 align=8
+ base size=8 base align=8
+QByteArrayDataPtr (0x0x7fb8089377e0) 0
+
+Class QByteArray
+ size=8 align=8
+ base size=8 base align=8
+QByteArray (0x0x7fb808937840) 0
+
+Class QByteRef
+ size=16 align=8
+ base size=12 base align=8
+QByteRef (0x0x7fb808663c00) 0
+
+Class QStringDataPtr
+ size=8 align=8
+ base size=8 base align=8
+QStringDataPtr (0x0x7fb80870aa80) 0
+
+Class QStringView
+ size=16 align=8
+ base size=16 base align=8
+QStringView (0x0x7fb80870af00) 0
+
+Class QLatin1String
+ size=16 align=8
+ base size=16 base align=8
+QLatin1String (0x0x7fb80880d000) 0
+
+Class QString::Null
+ size=1 align=1
+ base size=0 base align=1
+QString::Null (0x0x7fb80849ff60) 0 empty
+
+Class QString
+ size=8 align=8
+ base size=8 base align=8
+QString (0x0x7fb80849fe40) 0
+
+Class QCharRef
+ size=16 align=8
+ base size=12 base align=8
+QCharRef (0x0x7fb80835fde0) 0
+
+Class QStringRef
+ size=16 align=8
+ base size=16 base align=8
+QStringRef (0x0x7fb8080f79c0) 0
+
+Class QtPrivate::ArgBase
+ size=1 align=1
+ base size=1 base align=1
+QtPrivate::ArgBase (0x0x7fb807d807e0) 0
+
+Class QtPrivate::QStringViewArg
+ size=24 align=8
+ base size=24 base align=8
+QtPrivate::QStringViewArg (0x0x7fb80819d3a8) 0
+ QtPrivate::ArgBase (0x0x7fb807d80840) 0
+
+Class QtPrivate::QLatin1StringArg
+ size=24 align=8
+ base size=24 base align=8
+QtPrivate::QLatin1StringArg (0x0x7fb80819d410) 0
+ QtPrivate::ArgBase (0x0x7fb807d80a20) 0
+
+Class std::__erased_type
+ size=1 align=1
+ base size=0 base align=1
+std::__erased_type (0x0x7fb807e56960) 0 empty
+
+Class std::allocator_arg_t
+ size=1 align=1
+ base size=0 base align=1
+std::allocator_arg_t (0x0x7fb807e569c0) 0 empty
+
+Class std::__uses_alloc_base
+ size=1 align=1
+ base size=0 base align=1
+std::__uses_alloc_base (0x0x7fb807e56b40) 0 empty
+
+Class std::__uses_alloc0::_Sink
+ size=1 align=1
+ base size=0 base align=1
+std::__uses_alloc0::_Sink (0x0x7fb807e56c00) 0 empty
+
+Class std::__uses_alloc0
+ size=1 align=1
+ base size=1 base align=1
+std::__uses_alloc0 (0x0x7fb80819d7b8) 0
+ std::__uses_alloc_base (0x0x7fb807e56ba0) 0 empty
+
+Class std::_Swallow_assign
+ size=1 align=1
+ base size=0 base align=1
+std::_Swallow_assign (0x0x7fb807badf60) 0 empty
+
+Vtable for std::bad_function_call
+std::bad_function_call::_ZTVSt17bad_function_call: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt17bad_function_call)
+16 (int (*)(...))std::bad_function_call::~bad_function_call
+24 (int (*)(...))std::bad_function_call::~bad_function_call
+32 (int (*)(...))std::bad_function_call::what
+
+Class std::bad_function_call
+ size=8 align=8
+ base size=8 base align=8
+std::bad_function_call (0x0x7fb807bd5a28) 0 nearly-empty
+ vptr=((& std::bad_function_call::_ZTVSt17bad_function_call) + 16)
+ std::exception (0x0x7fb807c298a0) 0 nearly-empty
+ primary-for std::bad_function_call (0x0x7fb807bd5a28)
+
+Class std::_Nocopy_types
+ size=16 align=8
+ base size=16 base align=8
+std::_Nocopy_types (0x0x7fb807c29960) 0
+
+Class std::_Any_data
+ size=16 align=8
+ base size=16 base align=8
+std::_Any_data (0x0x7fb807c299c0) 0
+
+Class std::_Function_base
+ size=24 align=8
+ base size=24 base align=8
+std::_Function_base (0x0x7fb807c29cc0) 0
+
+Class QtPrivate::QHashCombine
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::QHashCombine (0x0x7fb807a5a180) 0 empty
+
+Class QtPrivate::QHashCombineCommutative
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::QHashCombineCommutative (0x0x7fb807a5a240) 0 empty
+
+Class std::_Bit_reference
+ size=16 align=8
+ base size=16 base align=8
+std::_Bit_reference (0x0x7fb807760960) 0
+
+Class std::_Bit_iterator_base
+ size=16 align=8
+ base size=12 base align=8
+std::_Bit_iterator_base (0x0x7fb807a9c5b0) 0
+ std::iterator<std::random_access_iterator_tag, bool> (0x0x7fb8077820c0) 0 empty
+
+Class std::_Bit_iterator
+ size=16 align=8
+ base size=12 base align=8
+std::_Bit_iterator (0x0x7fb807a9c6e8) 0
+ std::_Bit_iterator_base (0x0x7fb807a9c750) 0
+ std::iterator<std::random_access_iterator_tag, bool> (0x0x7fb807782720) 0 empty
+
+Class std::_Bit_const_iterator
+ size=16 align=8
+ base size=12 base align=8
+std::_Bit_const_iterator (0x0x7fb807a9c7b8) 0
+ std::_Bit_iterator_base (0x0x7fb807a9c820) 0
+ std::iterator<std::random_access_iterator_tag, bool> (0x0x7fb807782f00) 0 empty
+
+Class std::__detail::_List_node_base
+ size=16 align=8
+ base size=16 base align=8
+std::__detail::_List_node_base (0x0x7fb8075d7a80) 0
+
+Class QListData::NotArrayCompatibleLayout
+ size=1 align=1
+ base size=0 base align=1
+QListData::NotArrayCompatibleLayout (0x0x7fb8076ab840) 0 empty
+
+Class QListData::NotIndirectLayout
+ size=1 align=1
+ base size=0 base align=1
+QListData::NotIndirectLayout (0x0x7fb8076ab8a0) 0 empty
+
+Class QListData::ArrayCompatibleLayout
+ size=1 align=1
+ base size=1 base align=1
+QListData::ArrayCompatibleLayout (0x0x7fb80757f340) 0 empty
+ QListData::NotIndirectLayout (0x0x7fb8076ab900) 0 empty
+
+Class QListData::InlineWithPaddingLayout
+ size=1 align=1
+ base size=1 base align=1
+QListData::InlineWithPaddingLayout (0x0x7fb80760d8c0) 0 empty
+ QListData::NotArrayCompatibleLayout (0x0x7fb8076ab960) 0 empty
+ QListData::NotIndirectLayout (0x0x7fb8076ab9c0) 0 empty
+
+Class QListData::IndirectLayout
+ size=1 align=1
+ base size=1 base align=1
+QListData::IndirectLayout (0x0x7fb80757f3a8) 0 empty
+ QListData::NotArrayCompatibleLayout (0x0x7fb8076aba20) 0 empty
+
+Class QListData::Data
+ size=24 align=8
+ base size=24 base align=8
+QListData::Data (0x0x7fb8076aba80) 0
+
+Class QListData
+ size=8 align=8
+ base size=8 base align=8
+QListData (0x0x7fb8076ab7e0) 0
+
+Class QRegExp
+ size=8 align=8
+ base size=8 base align=8
+QRegExp (0x0x7fb80739dc00) 0
+
+Class QStringMatcher::Data
+ size=272 align=8
+ base size=272 base align=8
+QStringMatcher::Data (0x0x7fb807497180) 0
+
+Class QStringMatcher
+ size=1048 align=8
+ base size=1048 base align=8
+QStringMatcher (0x0x7fb807497120) 0
+
+Class QStringList
+ size=8 align=8
+ base size=8 base align=8
+QStringList (0x0x7fb8074af068) 0
+ QList<QString> (0x0x7fb8074af0d0) 0
+ QListSpecialMethods<QString> (0x0x7fb8074973c0) 0 empty
+
+Class QScopedPointerPodDeleter
+ size=1 align=1
+ base size=0 base align=1
+QScopedPointerPodDeleter (0x0x7fb807178300) 0 empty
+
+Class std::_Rb_tree_node_base
+ size=32 align=8
+ base size=32 base align=8
+std::_Rb_tree_node_base (0x0x7fb807200540) 0
+
+Class std::_Rb_tree_header
+ size=40 align=8
+ base size=40 base align=8
+std::_Rb_tree_header (0x0x7fb8072008a0) 0
+
+Class QtPrivate::AbstractDebugStreamFunction
+ size=16 align=8
+ base size=16 base align=8
+QtPrivate::AbstractDebugStreamFunction (0x0x7fb806f47ea0) 0
+
+Class QtPrivate::AbstractComparatorFunction
+ size=24 align=8
+ base size=24 base align=8
+QtPrivate::AbstractComparatorFunction (0x0x7fb806f63240) 0
+
+Class QtPrivate::AbstractConverterFunction
+ size=8 align=8
+ base size=8 base align=8
+QtPrivate::AbstractConverterFunction (0x0x7fb806f63780) 0
+
+Class QMetaType
+ size=80 align=8
+ base size=80 base align=8
+QMetaType (0x0x7fb806f63cc0) 0
+
+Class QtMetaTypePrivate::VariantData
+ size=24 align=8
+ base size=20 base align=8
+QtMetaTypePrivate::VariantData (0x0x7fb806fb4ea0) 0
+
+Class QtMetaTypePrivate::VectorBoolElements
+ size=1 align=1
+ base size=0 base align=1
+QtMetaTypePrivate::VectorBoolElements (0x0x7fb806fed5a0) 0 empty
+
+Class QtMetaTypePrivate::QSequentialIterableImpl
+ size=104 align=8
+ base size=104 base align=8
+QtMetaTypePrivate::QSequentialIterableImpl (0x0x7fb806c86420) 0
+
+Class QtMetaTypePrivate::QAssociativeIterableImpl
+ size=112 align=8
+ base size=112 base align=8
+QtMetaTypePrivate::QAssociativeIterableImpl (0x0x7fb806ce0ae0) 0
+
+Class QtMetaTypePrivate::QPairVariantInterfaceImpl
+ size=40 align=8
+ base size=40 base align=8
+QtMetaTypePrivate::QPairVariantInterfaceImpl (0x0x7fb806d57060) 0
+
+Class std::chrono::_V2::system_clock
+ size=1 align=1
+ base size=0 base align=1
+std::chrono::_V2::system_clock (0x0x7fb806bfe600) 0 empty
+
+Class std::chrono::_V2::steady_clock
+ size=1 align=1
+ base size=0 base align=1
+std::chrono::_V2::steady_clock (0x0x7fb80692a0c0) 0 empty
+
+Vtable for QObjectData
+QObjectData::_ZTV11QObjectData: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QObjectData)
+16 (int (*)(...))__cxa_pure_virtual
+24 (int (*)(...))__cxa_pure_virtual
+
+Class QObjectData
+ size=48 align=8
+ base size=48 base align=8
+QObjectData (0x0x7fb80692a120) 0
+ vptr=((& QObjectData::_ZTV11QObjectData) + 16)
+
+Class QObject::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QObject::QPrivateSignal (0x0x7fb80692a300) 0 empty
+
+Vtable for QObject
+QObject::_ZTV7QObject: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI7QObject)
+16 (int (*)(...))QObject::metaObject
+24 (int (*)(...))QObject::qt_metacast
+32 (int (*)(...))QObject::qt_metacall
+40 (int (*)(...))QObject::~QObject
+48 (int (*)(...))QObject::~QObject
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QObject
+ size=16 align=8
+ base size=16 base align=8
+QObject (0x0x7fb80692a2a0) 0
+ vptr=((& QObject::_ZTV7QObject) + 16)
+
+Vtable for QObjectUserData
+QObjectUserData::_ZTV15QObjectUserData: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QObjectUserData)
+16 (int (*)(...))QObjectUserData::~QObjectUserData
+24 (int (*)(...))QObjectUserData::~QObjectUserData
+
+Class QObjectUserData
+ size=8 align=8
+ base size=8 base align=8
+QObjectUserData (0x0x7fb8069fb120) 0 nearly-empty
+ vptr=((& QObjectUserData::_ZTV15QObjectUserData) + 16)
+
+Class QSignalBlocker
+ size=16 align=8
+ base size=10 base align=8
+QSignalBlocker (0x0x7fb8069fb2a0) 0
+
+Class QAbstractAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractAnimation::QPrivateSignal (0x0x7fb8069fbb40) 0 empty
+
+Vtable for QAbstractAnimation
+QAbstractAnimation::_ZTV18QAbstractAnimation: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QAbstractAnimation)
+16 (int (*)(...))QAbstractAnimation::metaObject
+24 (int (*)(...))QAbstractAnimation::qt_metacast
+32 (int (*)(...))QAbstractAnimation::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAbstractAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QAbstractAnimation
+ size=16 align=8
+ base size=16 base align=8
+QAbstractAnimation (0x0x7fb8069f8208) 0
+ vptr=((& QAbstractAnimation::_ZTV18QAbstractAnimation) + 16)
+ QObject (0x0x7fb8069fbae0) 0
+ primary-for QAbstractAnimation (0x0x7fb8069f8208)
+
+Class QAnimationDriver::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAnimationDriver::QPrivateSignal (0x0x7fb8069fbf00) 0 empty
+
+Vtable for QAnimationDriver
+QAnimationDriver::_ZTV16QAnimationDriver: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QAnimationDriver)
+16 (int (*)(...))QAnimationDriver::metaObject
+24 (int (*)(...))QAnimationDriver::qt_metacast
+32 (int (*)(...))QAnimationDriver::qt_metacall
+40 (int (*)(...))QAnimationDriver::~QAnimationDriver
+48 (int (*)(...))QAnimationDriver::~QAnimationDriver
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAnimationDriver::advance
+120 (int (*)(...))QAnimationDriver::elapsed
+128 (int (*)(...))QAnimationDriver::start
+136 (int (*)(...))QAnimationDriver::stop
+
+Class QAnimationDriver
+ size=16 align=8
+ base size=16 base align=8
+QAnimationDriver (0x0x7fb8069f8270) 0
+ vptr=((& QAnimationDriver::_ZTV16QAnimationDriver) + 16)
+ QObject (0x0x7fb8069fbea0) 0
+ primary-for QAnimationDriver (0x0x7fb8069f8270)
+
+Class QEventLoop::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QEventLoop::QPrivateSignal (0x0x7fb806a3f180) 0 empty
+
+Vtable for QEventLoop
+QEventLoop::_ZTV10QEventLoop: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QEventLoop)
+16 (int (*)(...))QEventLoop::metaObject
+24 (int (*)(...))QEventLoop::qt_metacast
+32 (int (*)(...))QEventLoop::qt_metacall
+40 (int (*)(...))QEventLoop::~QEventLoop
+48 (int (*)(...))QEventLoop::~QEventLoop
+56 (int (*)(...))QEventLoop::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QEventLoop
+ size=16 align=8
+ base size=16 base align=8
+QEventLoop (0x0x7fb8069f82d8) 0
+ vptr=((& QEventLoop::_ZTV10QEventLoop) + 16)
+ QObject (0x0x7fb806a3f120) 0
+ primary-for QEventLoop (0x0x7fb8069f82d8)
+
+Class QEventLoopLocker
+ size=8 align=8
+ base size=8 base align=8
+QEventLoopLocker (0x0x7fb806a3fa20) 0
+
+Class QAbstractEventDispatcher::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractEventDispatcher::QPrivateSignal (0x0x7fb806a3fae0) 0 empty
+
+Class QAbstractEventDispatcher::TimerInfo
+ size=12 align=4
+ base size=12 base align=4
+QAbstractEventDispatcher::TimerInfo (0x0x7fb806a3fb40) 0
+
+Vtable for QAbstractEventDispatcher
+QAbstractEventDispatcher::_ZTV24QAbstractEventDispatcher: 28 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI24QAbstractEventDispatcher)
+16 (int (*)(...))QAbstractEventDispatcher::metaObject
+24 (int (*)(...))QAbstractEventDispatcher::qt_metacast
+32 (int (*)(...))QAbstractEventDispatcher::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))__cxa_pure_virtual
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))__cxa_pure_virtual
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))__cxa_pure_virtual
+176 (int (*)(...))__cxa_pure_virtual
+184 (int (*)(...))__cxa_pure_virtual
+192 (int (*)(...))__cxa_pure_virtual
+200 (int (*)(...))__cxa_pure_virtual
+208 (int (*)(...))QAbstractEventDispatcher::startingUp
+216 (int (*)(...))QAbstractEventDispatcher::closingDown
+
+Class QAbstractEventDispatcher
+ size=16 align=8
+ base size=16 base align=8
+QAbstractEventDispatcher (0x0x7fb8069f8410) 0
+ vptr=((& QAbstractEventDispatcher::_ZTV24QAbstractEventDispatcher) + 16)
+ QObject (0x0x7fb806a3fa80) 0
+ primary-for QAbstractEventDispatcher (0x0x7fb8069f8410)
+
+Class QMapNodeBase
+ size=24 align=8
+ base size=24 base align=8
+QMapNodeBase (0x0x7fb8066b7b40) 0
+
+Class QMapDataBase
+ size=40 align=8
+ base size=40 base align=8
+QMapDataBase (0x0x7fb8066e07e0) 0
+
+Class QHashData::Node
+ size=16 align=8
+ base size=16 base align=8
+QHashData::Node (0x0x7fb8067cd180) 0
+
+Class QHashData
+ size=48 align=8
+ base size=44 base align=8
+QHashData (0x0x7fb8067cd120) 0
+
+Class QHashDummyValue
+ size=1 align=1
+ base size=0 base align=1
+QHashDummyValue (0x0x7fb8067cd420) 0 empty
+
+Class QVariant::PrivateShared
+ size=16 align=8
+ base size=12 base align=8
+QVariant::PrivateShared (0x0x7fb8064dab40) 0
+
+Class QVariant::Private::Data
+ size=8 align=8
+ base size=8 base align=8
+QVariant::Private::Data (0x0x7fb8064dac00) 0
+
+Class QVariant::Private
+ size=16 align=8
+ base size=12 base align=8
+QVariant::Private (0x0x7fb8064daba0) 0
+
+Class QVariant::Handler
+ size=72 align=8
+ base size=72 base align=8
+QVariant::Handler (0x0x7fb8064dac60) 0
+
+Class QVariant
+ size=16 align=8
+ base size=16 base align=8
+QVariant (0x0x7fb8064daae0) 0
+
+Class QVariantComparisonHelper
+ size=8 align=8
+ base size=8 base align=8
+QVariantComparisonHelper (0x0x7fb8065d3f00) 0
+
+Class QSequentialIterable::const_iterator
+ size=112 align=8
+ base size=112 base align=8
+QSequentialIterable::const_iterator (0x0x7fb8062a15a0) 0
+
+Class QSequentialIterable
+ size=104 align=8
+ base size=104 base align=8
+QSequentialIterable (0x0x7fb8062a1540) 0
+
+Class QAssociativeIterable::const_iterator
+ size=120 align=8
+ base size=120 base align=8
+QAssociativeIterable::const_iterator (0x0x7fb8062a16c0) 0
+
+Class QAssociativeIterable
+ size=112 align=8
+ base size=112 base align=8
+QAssociativeIterable (0x0x7fb8062a1660) 0
+
+Class QModelIndex
+ size=24 align=8
+ base size=24 base align=8
+QModelIndex (0x0x7fb80636b840) 0
+
+Class QPersistentModelIndex
+ size=8 align=8
+ base size=8 base align=8
+QPersistentModelIndex (0x0x7fb8063e0480) 0
+
+Class QAbstractItemModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractItemModel::QPrivateSignal (0x0x7fb8060b02a0) 0 empty
+
+Vtable for QAbstractItemModel
+QAbstractItemModel::_ZTV18QAbstractItemModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QAbstractItemModel)
+16 (int (*)(...))QAbstractItemModel::metaObject
+24 (int (*)(...))QAbstractItemModel::qt_metacast
+32 (int (*)(...))QAbstractItemModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractItemModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))QAbstractItemModel::hasChildren
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))QAbstractItemModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractItemModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractItemModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractItemModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractItemModel (0x0x7fb8060af5b0) 0
+ vptr=((& QAbstractItemModel::_ZTV18QAbstractItemModel) + 16)
+ QObject (0x0x7fb8060b0240) 0
+ primary-for QAbstractItemModel (0x0x7fb8060af5b0)
+
+Class QAbstractTableModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractTableModel::QPrivateSignal (0x0x7fb806176660) 0 empty
+
+Vtable for QAbstractTableModel
+QAbstractTableModel::_ZTV19QAbstractTableModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QAbstractTableModel)
+16 (int (*)(...))QAbstractTableModel::metaObject
+24 (int (*)(...))QAbstractTableModel::qt_metacast
+32 (int (*)(...))QAbstractTableModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractTableModel::index
+120 (int (*)(...))QAbstractTableModel::parent
+128 (int (*)(...))QAbstractTableModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))QAbstractTableModel::hasChildren
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))QAbstractItemModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractTableModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractTableModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractTableModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractTableModel (0x0x7fb8060afbc8) 0
+ vptr=((& QAbstractTableModel::_ZTV19QAbstractTableModel) + 16)
+ QAbstractItemModel (0x0x7fb8060afc30) 0
+ primary-for QAbstractTableModel (0x0x7fb8060afbc8)
+ QObject (0x0x7fb806176600) 0
+ primary-for QAbstractItemModel (0x0x7fb8060afc30)
+
+Class QAbstractListModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractListModel::QPrivateSignal (0x0x7fb8061767e0) 0 empty
+
+Vtable for QAbstractListModel
+QAbstractListModel::_ZTV18QAbstractListModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QAbstractListModel)
+16 (int (*)(...))QAbstractListModel::metaObject
+24 (int (*)(...))QAbstractListModel::qt_metacast
+32 (int (*)(...))QAbstractListModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractListModel::index
+120 (int (*)(...))QAbstractListModel::parent
+128 (int (*)(...))QAbstractListModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))QAbstractListModel::columnCount
+152 (int (*)(...))QAbstractListModel::hasChildren
+160 (int (*)(...))__cxa_pure_virtual
+168 (int (*)(...))QAbstractItemModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QAbstractItemModel::itemData
+200 (int (*)(...))QAbstractItemModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractListModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QAbstractListModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QAbstractListModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractListModel (0x0x7fb8060afc98) 0
+ vptr=((& QAbstractListModel::_ZTV18QAbstractListModel) + 16)
+ QAbstractItemModel (0x0x7fb8060afd00) 0
+ primary-for QAbstractListModel (0x0x7fb8060afc98)
+ QObject (0x0x7fb806176780) 0
+ primary-for QAbstractItemModel (0x0x7fb8060afd00)
+
+Vtable for QAbstractNativeEventFilter
+QAbstractNativeEventFilter::_ZTV26QAbstractNativeEventFilter: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI26QAbstractNativeEventFilter)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractNativeEventFilter
+ size=16 align=8
+ base size=16 base align=8
+QAbstractNativeEventFilter (0x0x7fb806176f00) 0
+ vptr=((& QAbstractNativeEventFilter::_ZTV26QAbstractNativeEventFilter) + 16)
+
+Class QAbstractProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractProxyModel::QPrivateSignal (0x0x7fb8061e8000) 0 empty
+
+Vtable for QAbstractProxyModel
+QAbstractProxyModel::_ZTV19QAbstractProxyModel: 53 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QAbstractProxyModel)
+16 (int (*)(...))QAbstractProxyModel::metaObject
+24 (int (*)(...))QAbstractProxyModel::qt_metacast
+32 (int (*)(...))QAbstractProxyModel::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractProxyModel::sibling
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))__cxa_pure_virtual
+152 (int (*)(...))QAbstractProxyModel::hasChildren
+160 (int (*)(...))QAbstractProxyModel::data
+168 (int (*)(...))QAbstractProxyModel::setData
+176 (int (*)(...))QAbstractProxyModel::headerData
+184 (int (*)(...))QAbstractProxyModel::setHeaderData
+192 (int (*)(...))QAbstractProxyModel::itemData
+200 (int (*)(...))QAbstractProxyModel::setItemData
+208 (int (*)(...))QAbstractProxyModel::mimeTypes
+216 (int (*)(...))QAbstractProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QAbstractProxyModel::dropMimeData
+240 (int (*)(...))QAbstractProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractProxyModel::fetchMore
+312 (int (*)(...))QAbstractProxyModel::canFetchMore
+320 (int (*)(...))QAbstractProxyModel::flags
+328 (int (*)(...))QAbstractProxyModel::sort
+336 (int (*)(...))QAbstractProxyModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QAbstractProxyModel::setSourceModel
+392 (int (*)(...))__cxa_pure_virtual
+400 (int (*)(...))__cxa_pure_virtual
+408 (int (*)(...))QAbstractProxyModel::mapSelectionToSource
+416 (int (*)(...))QAbstractProxyModel::mapSelectionFromSource
+
+Class QAbstractProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QAbstractProxyModel (0x0x7fb8060afdd0) 0
+ vptr=((& QAbstractProxyModel::_ZTV19QAbstractProxyModel) + 16)
+ QAbstractItemModel (0x0x7fb8060afe38) 0
+ primary-for QAbstractProxyModel (0x0x7fb8060afdd0)
+ QObject (0x0x7fb806176f60) 0
+ primary-for QAbstractItemModel (0x0x7fb8060afe38)
+
+Class QAbstractState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractState::QPrivateSignal (0x0x7fb8061e8240) 0 empty
+
+Vtable for QAbstractState
+QAbstractState::_ZTV14QAbstractState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI14QAbstractState)
+16 (int (*)(...))QAbstractState::metaObject
+24 (int (*)(...))QAbstractState::qt_metacast
+32 (int (*)(...))QAbstractState::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAbstractState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractState
+ size=16 align=8
+ base size=16 base align=8
+QAbstractState (0x0x7fb8060afea0) 0
+ vptr=((& QAbstractState::_ZTV14QAbstractState) + 16)
+ QObject (0x0x7fb8061e81e0) 0
+ primary-for QAbstractState (0x0x7fb8060afea0)
+
+Class QAbstractTransition::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAbstractTransition::QPrivateSignal (0x0x7fb8061e8480) 0 empty
+
+Vtable for QAbstractTransition
+QAbstractTransition::_ZTV19QAbstractTransition: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QAbstractTransition)
+16 (int (*)(...))QAbstractTransition::metaObject
+24 (int (*)(...))QAbstractTransition::qt_metacast
+32 (int (*)(...))QAbstractTransition::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAbstractTransition::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QAbstractTransition
+ size=16 align=8
+ base size=16 base align=8
+QAbstractTransition (0x0x7fb8060aff08) 0
+ vptr=((& QAbstractTransition::_ZTV19QAbstractTransition) + 16)
+ QObject (0x0x7fb8061e8420) 0
+ primary-for QAbstractTransition (0x0x7fb8060aff08)
+
+Class QAnimationGroup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QAnimationGroup::QPrivateSignal (0x0x7fb8061e8780) 0 empty
+
+Vtable for QAnimationGroup
+QAnimationGroup::_ZTV15QAnimationGroup: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QAnimationGroup)
+16 (int (*)(...))QAnimationGroup::metaObject
+24 (int (*)(...))QAnimationGroup::qt_metacast
+32 (int (*)(...))QAnimationGroup::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QAnimationGroup::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+128 (int (*)(...))QAbstractAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QAnimationGroup
+ size=16 align=8
+ base size=16 base align=8
+QAnimationGroup (0x0x7fb8060aff70) 0
+ vptr=((& QAnimationGroup::_ZTV15QAnimationGroup) + 16)
+ QAbstractAnimation (0x0x7fb80621e000) 0
+ primary-for QAnimationGroup (0x0x7fb8060aff70)
+ QObject (0x0x7fb8061e8720) 0
+ primary-for QAbstractAnimation (0x0x7fb80621e000)
+
+Class QBasicTimer
+ size=4 align=4
+ base size=4 base align=4
+QBasicTimer (0x0x7fb805e6aa80) 0
+
+Class QBitArray
+ size=8 align=8
+ base size=8 base align=8
+QBitArray (0x0x7fb805f00420) 0
+
+Class QBitRef
+ size=16 align=8
+ base size=12 base align=8
+QBitRef (0x0x7fb805f548a0) 0
+
+Class QIODevice::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QIODevice::QPrivateSignal (0x0x7fb805fa7b40) 0 empty
+
+Vtable for QIODevice
+QIODevice::_ZTV9QIODevice: 30 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QIODevice)
+16 (int (*)(...))QIODevice::metaObject
+24 (int (*)(...))QIODevice::qt_metacast
+32 (int (*)(...))QIODevice::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QIODevice::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QIODevice::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QIODevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))__cxa_pure_virtual
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))__cxa_pure_virtual
+
+Class QIODevice
+ size=16 align=8
+ base size=16 base align=8
+QIODevice (0x0x7fb805fb45b0) 0
+ vptr=((& QIODevice::_ZTV9QIODevice) + 16)
+ QObject (0x0x7fb805fa7ae0) 0
+ primary-for QIODevice (0x0x7fb805fb45b0)
+
+Class QBuffer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QBuffer::QPrivateSignal (0x0x7fb805ff04e0) 0 empty
+
+Vtable for QBuffer
+QBuffer::_ZTV7QBuffer: 30 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI7QBuffer)
+16 (int (*)(...))QBuffer::metaObject
+24 (int (*)(...))QBuffer::qt_metacast
+32 (int (*)(...))QBuffer::qt_metacall
+40 (int (*)(...))QBuffer::~QBuffer
+48 (int (*)(...))QBuffer::~QBuffer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QBuffer::connectNotify
+104 (int (*)(...))QBuffer::disconnectNotify
+112 (int (*)(...))QIODevice::isSequential
+120 (int (*)(...))QBuffer::open
+128 (int (*)(...))QBuffer::close
+136 (int (*)(...))QBuffer::pos
+144 (int (*)(...))QBuffer::size
+152 (int (*)(...))QBuffer::seek
+160 (int (*)(...))QBuffer::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QBuffer::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QBuffer::readData
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QBuffer::writeData
+
+Class QBuffer
+ size=16 align=8
+ base size=16 base align=8
+QBuffer (0x0x7fb805fb46e8) 0
+ vptr=((& QBuffer::_ZTV7QBuffer) + 16)
+ QIODevice (0x0x7fb805fb4750) 0
+ primary-for QBuffer (0x0x7fb805fb46e8)
+ QObject (0x0x7fb805ff0480) 0
+ primary-for QIODevice (0x0x7fb805fb4750)
+
+Class QByteArrayMatcher::Data
+ size=272 align=8
+ base size=272 base align=8
+QByteArrayMatcher::Data (0x0x7fb805ff0780) 0
+
+Class QByteArrayMatcher
+ size=1040 align=8
+ base size=1040 base align=8
+QByteArrayMatcher (0x0x7fb805ff0720) 0
+
+Class QStaticByteArrayMatcherBase::Skiptable
+ size=256 align=1
+ base size=256 base align=1
+QStaticByteArrayMatcherBase::Skiptable (0x0x7fb805ff0900) 0
+
+Class QStaticByteArrayMatcherBase
+ size=256 align=16
+ base size=256 base align=16
+QStaticByteArrayMatcherBase (0x0x7fb805ff08a0) 0
+
+Class QSharedData
+ size=4 align=4
+ base size=4 base align=4
+QSharedData (0x0x7fb8060437e0) 0
+
+Class QLocale
+ size=8 align=8
+ base size=8 base align=8
+QLocale (0x0x7fb805c866c0) 0
+
+Class QCalendar::YearMonthDay
+ size=12 align=4
+ base size=12 base align=4
+QCalendar::YearMonthDay (0x0x7fb805de0ba0) 0
+
+Class QCalendar
+ size=8 align=8
+ base size=8 base align=8
+QCalendar (0x0x7fb805de0b40) 0
+
+Class QDate
+ size=8 align=8
+ base size=8 base align=8
+QDate (0x0x7fb805e2a3c0) 0
+
+Class QTime
+ size=4 align=4
+ base size=4 base align=4
+QTime (0x0x7fb805a81c60) 0
+
+Class QDateTime::ShortData
+ size=8 align=8
+ base size=8 base align=8
+QDateTime::ShortData (0x0x7fb805aed900) 0
+
+Class QDateTime::Data
+ size=8 align=8
+ base size=8 base align=8
+QDateTime::Data (0x0x7fb805aed960) 0
+
+Class QDateTime
+ size=8 align=8
+ base size=8 base align=8
+QDateTime (0x0x7fb805aed8a0) 0
+
+Vtable for QTextStream
+QTextStream::_ZTV11QTextStream: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QTextStream)
+16 (int (*)(...))QTextStream::~QTextStream
+24 (int (*)(...))QTextStream::~QTextStream
+
+Class QTextStream
+ size=16 align=8
+ base size=16 base align=8
+QTextStream (0x0x7fb805bdc060) 0
+ vptr=((& QTextStream::_ZTV11QTextStream) + 16)
+
+Class QTextStreamManipulator
+ size=40 align=8
+ base size=38 base align=8
+QTextStreamManipulator (0x0x7fb805bdc900) 0
+
+Class QContiguousCacheData
+ size=24 align=4
+ base size=24 base align=4
+QContiguousCacheData (0x0x7fb8058b45a0) 0
+
+Vtable for __gnu_cxx::__concurrence_lock_error
+__gnu_cxx::__concurrence_lock_error::_ZTVN9__gnu_cxx24__concurrence_lock_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx24__concurrence_lock_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_lock_error::~__concurrence_lock_error
+24 (int (*)(...))__gnu_cxx::__concurrence_lock_error::~__concurrence_lock_error
+32 (int (*)(...))__gnu_cxx::__concurrence_lock_error::what
+
+Class __gnu_cxx::__concurrence_lock_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_lock_error (0x0x7fb805bd3750) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_lock_error::_ZTVN9__gnu_cxx24__concurrence_lock_errorE) + 16)
+ std::exception (0x0x7fb805903420) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_lock_error (0x0x7fb805bd3750)
+
+Vtable for __gnu_cxx::__concurrence_unlock_error
+__gnu_cxx::__concurrence_unlock_error::_ZTVN9__gnu_cxx26__concurrence_unlock_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx26__concurrence_unlock_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_unlock_error::~__concurrence_unlock_error
+24 (int (*)(...))__gnu_cxx::__concurrence_unlock_error::~__concurrence_unlock_error
+32 (int (*)(...))__gnu_cxx::__concurrence_unlock_error::what
+
+Class __gnu_cxx::__concurrence_unlock_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_unlock_error (0x0x7fb805bd37b8) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_unlock_error::_ZTVN9__gnu_cxx26__concurrence_unlock_errorE) + 16)
+ std::exception (0x0x7fb805903540) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_unlock_error (0x0x7fb805bd37b8)
+
+Vtable for __gnu_cxx::__concurrence_broadcast_error
+__gnu_cxx::__concurrence_broadcast_error::_ZTVN9__gnu_cxx29__concurrence_broadcast_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx29__concurrence_broadcast_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::~__concurrence_broadcast_error
+24 (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::~__concurrence_broadcast_error
+32 (int (*)(...))__gnu_cxx::__concurrence_broadcast_error::what
+
+Class __gnu_cxx::__concurrence_broadcast_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_broadcast_error (0x0x7fb805bd3820) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_broadcast_error::_ZTVN9__gnu_cxx29__concurrence_broadcast_errorE) + 16)
+ std::exception (0x0x7fb805903660) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_broadcast_error (0x0x7fb805bd3820)
+
+Vtable for __gnu_cxx::__concurrence_wait_error
+__gnu_cxx::__concurrence_wait_error::_ZTVN9__gnu_cxx24__concurrence_wait_errorE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9__gnu_cxx24__concurrence_wait_errorE)
+16 (int (*)(...))__gnu_cxx::__concurrence_wait_error::~__concurrence_wait_error
+24 (int (*)(...))__gnu_cxx::__concurrence_wait_error::~__concurrence_wait_error
+32 (int (*)(...))__gnu_cxx::__concurrence_wait_error::what
+
+Class __gnu_cxx::__concurrence_wait_error
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__concurrence_wait_error (0x0x7fb805bd38f0) 0 nearly-empty
+ vptr=((& __gnu_cxx::__concurrence_wait_error::_ZTVN9__gnu_cxx24__concurrence_wait_errorE) + 16)
+ std::exception (0x0x7fb805903780) 0 nearly-empty
+ primary-for __gnu_cxx::__concurrence_wait_error (0x0x7fb805bd38f0)
+
+Class __gnu_cxx::__mutex
+ size=40 align=8
+ base size=40 base align=8
+__gnu_cxx::__mutex (0x0x7fb8059277e0) 0
+
+Class __gnu_cxx::__recursive_mutex
+ size=40 align=8
+ base size=40 base align=8
+__gnu_cxx::__recursive_mutex (0x0x7fb805927ae0) 0
+
+Class __gnu_cxx::__scoped_lock
+ size=8 align=8
+ base size=8 base align=8
+__gnu_cxx::__scoped_lock (0x0x7fb805927de0) 0
+
+Class __gnu_cxx::__cond
+ size=48 align=8
+ base size=48 base align=8
+__gnu_cxx::__cond (0x0x7fb80594e180) 0
+
+Vtable for std::bad_weak_ptr
+std::bad_weak_ptr::_ZTVSt12bad_weak_ptr: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12bad_weak_ptr)
+16 (int (*)(...))std::bad_weak_ptr::~bad_weak_ptr
+24 (int (*)(...))std::bad_weak_ptr::~bad_weak_ptr
+32 (int (*)(...))std::bad_weak_ptr::what
+
+Class std::bad_weak_ptr
+ size=8 align=8
+ base size=8 base align=8
+std::bad_weak_ptr (0x0x7fb805bd3958) 0 nearly-empty
+ vptr=((& std::bad_weak_ptr::_ZTVSt12bad_weak_ptr) + 16)
+ std::exception (0x0x7fb8059c8360) 0 nearly-empty
+ primary-for std::bad_weak_ptr (0x0x7fb805bd3958)
+
+Class std::_Sp_make_shared_tag
+ size=1 align=1
+ base size=0 base align=1
+std::_Sp_make_shared_tag (0x0x7fb805a34300) 0 empty
+
+Class std::__sp_array_delete
+ size=1 align=1
+ base size=0 base align=1
+std::__sp_array_delete (0x0x7fb805a34720) 0 empty
+
+Class std::_Sp_locker
+ size=2 align=1
+ base size=2 base align=1
+std::_Sp_locker (0x0x7fb8057735a0) 0
+
+Class QtSharedPointer::NormalDeleter
+ size=1 align=1
+ base size=0 base align=1
+QtSharedPointer::NormalDeleter (0x0x7fb8057aaa80) 0 empty
+
+Class QtSharedPointer::ExternalRefCountData
+ size=16 align=8
+ base size=16 base align=8
+QtSharedPointer::ExternalRefCountData (0x0x7fb8057aac00) 0
+
+Class QtPrivate::EnableInternalData
+ size=1 align=1
+ base size=0 base align=1
+QtPrivate::EnableInternalData (0x0x7fb805833540) 0 empty
+
+Class QDebug::Stream
+ size=80 align=8
+ base size=76 base align=8
+QDebug::Stream (0x0x7fb80545bc00) 0
+
+Class QDebug
+ size=8 align=8
+ base size=8 base align=8
+QDebug (0x0x7fb80545bba0) 0
+
+Class QDebugStateSaver
+ size=8 align=8
+ base size=8 base align=8
+QDebugStateSaver (0x0x7fb8055f0540) 0
+
+Class QNoDebug
+ size=1 align=1
+ base size=0 base align=1
+QNoDebug (0x0x7fb8055f0600) 0 empty
+
+Class QCborError
+ size=4 align=4
+ base size=4 base align=4
+QCborError (0x0x7fb805270840) 0
+
+Class QRegularExpression
+ size=8 align=8
+ base size=8 base align=8
+QRegularExpression (0x0x7fb8052a8000) 0
+
+Class QRegularExpressionMatch
+ size=8 align=8
+ base size=8 base align=8
+QRegularExpressionMatch (0x0x7fb80532cea0) 0
+
+Class QRegularExpressionMatchIterator
+ size=8 align=8
+ base size=8 base align=8
+QRegularExpressionMatchIterator (0x0x7fb805392c60) 0
+
+Class QUrl
+ size=8 align=8
+ base size=8 base align=8
+QUrl (0x0x7fb8054146c0) 0
+
+Class QUuid
+ size=16 align=4
+ base size=16 base align=4
+QUuid (0x0x7fb80515c660) 0
+
+Class QCborParserError
+ size=16 align=8
+ base size=12 base align=8
+QCborParserError (0x0x7fb8051df1e0) 0
+
+Class QCborValue
+ size=24 align=8
+ base size=20 base align=8
+QCborValue (0x0x7fb8051df2a0) 0
+
+Class QCborValueRef
+ size=16 align=8
+ base size=16 base align=8
+QCborValueRef (0x0x7fb80501de40) 0
+
+Class QCborArray::Iterator
+ size=16 align=8
+ base size=16 base align=8
+QCborArray::Iterator (0x0x7fb804cd58a0) 0
+
+Class QCborArray::ConstIterator
+ size=16 align=8
+ base size=16 base align=8
+QCborArray::ConstIterator (0x0x7fb804cd5900) 0
+
+Class QCborArray
+ size=8 align=8
+ base size=8 base align=8
+QCborArray (0x0x7fb804cd5840) 0
+
+Class QCborMap::Iterator
+ size=16 align=8
+ base size=16 base align=8
+QCborMap::Iterator (0x0x7fb804e564e0) 0
+
+Class QCborMap::ConstIterator
+ size=16 align=8
+ base size=16 base align=8
+QCborMap::ConstIterator (0x0x7fb804e56540) 0
+
+Class QCborMap
+ size=8 align=8
+ base size=8 base align=8
+QCborMap (0x0x7fb804e56480) 0
+
+Class qfloat16::Wrap
+ size=2 align=2
+ base size=2 base align=2
+qfloat16::Wrap (0x0x7fb80485bcc0) 0
+
+Class qfloat16
+ size=2 align=2
+ base size=2 base align=2
+qfloat16 (0x0x7fb80485bc60) 0
+
+Class QCborStreamWriter
+ size=8 align=8
+ base size=8 base align=8
+QCborStreamWriter (0x0x7fb80493e960) 0
+
+Class QCborStreamReader
+ size=24 align=8
+ base size=20 base align=8
+QCborStreamReader (0x0x7fb8049756c0) 0
+
+Class QCollatorSortKey
+ size=8 align=8
+ base size=8 base align=8
+QCollatorSortKey (0x0x7fb8049fb7e0) 0
+
+Class QCollator
+ size=8 align=8
+ base size=8 base align=8
+QCollator (0x0x7fb8049fb9c0) 0
+
+Class QCommandLineOption
+ size=8 align=8
+ base size=8 base align=8
+QCommandLineOption (0x0x7fb804711000) 0
+
+Vtable for QEvent
+QEvent::_ZTV6QEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI6QEvent)
+16 (int (*)(...))QEvent::~QEvent
+24 (int (*)(...))QEvent::~QEvent
+
+Class QEvent
+ size=24 align=8
+ base size=20 base align=8
+QEvent (0x0x7fb8047ed540) 0
+ vptr=((& QEvent::_ZTV6QEvent) + 16)
+
+Vtable for QTimerEvent
+QTimerEvent::_ZTV11QTimerEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QTimerEvent)
+16 (int (*)(...))QTimerEvent::~QTimerEvent
+24 (int (*)(...))QTimerEvent::~QTimerEvent
+
+Class QTimerEvent
+ size=24 align=8
+ base size=24 base align=8
+QTimerEvent (0x0x7fb8047cd3a8) 0
+ vptr=((& QTimerEvent::_ZTV11QTimerEvent) + 16)
+ QEvent (0x0x7fb8047ed900) 0
+ primary-for QTimerEvent (0x0x7fb8047cd3a8)
+
+Vtable for QChildEvent
+QChildEvent::_ZTV11QChildEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QChildEvent)
+16 (int (*)(...))QChildEvent::~QChildEvent
+24 (int (*)(...))QChildEvent::~QChildEvent
+
+Class QChildEvent
+ size=32 align=8
+ base size=32 base align=8
+QChildEvent (0x0x7fb8047cd410) 0
+ vptr=((& QChildEvent::_ZTV11QChildEvent) + 16)
+ QEvent (0x0x7fb8047ed9c0) 0
+ primary-for QChildEvent (0x0x7fb8047cd410)
+
+Vtable for QDynamicPropertyChangeEvent
+QDynamicPropertyChangeEvent::_ZTV27QDynamicPropertyChangeEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI27QDynamicPropertyChangeEvent)
+16 (int (*)(...))QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent
+24 (int (*)(...))QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent
+
+Class QDynamicPropertyChangeEvent
+ size=32 align=8
+ base size=32 base align=8
+QDynamicPropertyChangeEvent (0x0x7fb8047cd958) 0
+ vptr=((& QDynamicPropertyChangeEvent::_ZTV27QDynamicPropertyChangeEvent) + 16)
+ QEvent (0x0x7fb804829060) 0
+ primary-for QDynamicPropertyChangeEvent (0x0x7fb8047cd958)
+
+Vtable for QDeferredDeleteEvent
+QDeferredDeleteEvent::_ZTV20QDeferredDeleteEvent: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QDeferredDeleteEvent)
+16 (int (*)(...))QDeferredDeleteEvent::~QDeferredDeleteEvent
+24 (int (*)(...))QDeferredDeleteEvent::~QDeferredDeleteEvent
+
+Class QDeferredDeleteEvent
+ size=24 align=8
+ base size=24 base align=8
+QDeferredDeleteEvent (0x0x7fb8047cd9c0) 0
+ vptr=((& QDeferredDeleteEvent::_ZTV20QDeferredDeleteEvent) + 16)
+ QEvent (0x0x7fb804829120) 0
+ primary-for QDeferredDeleteEvent (0x0x7fb8047cd9c0)
+
+Class QCoreApplication::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QCoreApplication::QPrivateSignal (0x0x7fb804829240) 0 empty
+
+Vtable for QCoreApplication
+QCoreApplication::_ZTV16QCoreApplication: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QCoreApplication)
+16 (int (*)(...))QCoreApplication::metaObject
+24 (int (*)(...))QCoreApplication::qt_metacast
+32 (int (*)(...))QCoreApplication::qt_metacall
+40 (int (*)(...))QCoreApplication::~QCoreApplication
+48 (int (*)(...))QCoreApplication::~QCoreApplication
+56 (int (*)(...))QCoreApplication::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QCoreApplication::notify
+120 (int (*)(...))QCoreApplication::compressEvent
+
+Class QCoreApplication
+ size=16 align=8
+ base size=16 base align=8
+QCoreApplication (0x0x7fb8047cda28) 0
+ vptr=((& QCoreApplication::_ZTV16QCoreApplication) + 16)
+ QObject (0x0x7fb8048291e0) 0
+ primary-for QCoreApplication (0x0x7fb8047cda28)
+
+Class QCommandLineParser
+ size=8 align=8
+ base size=8 base align=8
+QCommandLineParser (0x0x7fb804829480) 0
+
+Class QConcatenateTablesProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QConcatenateTablesProxyModel::QPrivateSignal (0x0x7fb804829600) 0 empty
+
+Vtable for QConcatenateTablesProxyModel
+QConcatenateTablesProxyModel::_ZTV28QConcatenateTablesProxyModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI28QConcatenateTablesProxyModel)
+16 (int (*)(...))QConcatenateTablesProxyModel::metaObject
+24 (int (*)(...))QConcatenateTablesProxyModel::qt_metacast
+32 (int (*)(...))QConcatenateTablesProxyModel::qt_metacall
+40 (int (*)(...))QConcatenateTablesProxyModel::~QConcatenateTablesProxyModel
+48 (int (*)(...))QConcatenateTablesProxyModel::~QConcatenateTablesProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QConcatenateTablesProxyModel::index
+120 (int (*)(...))QConcatenateTablesProxyModel::parent
+128 (int (*)(...))QAbstractItemModel::sibling
+136 (int (*)(...))QConcatenateTablesProxyModel::rowCount
+144 (int (*)(...))QConcatenateTablesProxyModel::columnCount
+152 (int (*)(...))QAbstractItemModel::hasChildren
+160 (int (*)(...))QConcatenateTablesProxyModel::data
+168 (int (*)(...))QConcatenateTablesProxyModel::setData
+176 (int (*)(...))QConcatenateTablesProxyModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QConcatenateTablesProxyModel::itemData
+200 (int (*)(...))QConcatenateTablesProxyModel::setItemData
+208 (int (*)(...))QConcatenateTablesProxyModel::mimeTypes
+216 (int (*)(...))QConcatenateTablesProxyModel::mimeData
+224 (int (*)(...))QConcatenateTablesProxyModel::canDropMimeData
+232 (int (*)(...))QConcatenateTablesProxyModel::dropMimeData
+240 (int (*)(...))QAbstractItemModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QAbstractItemModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QAbstractItemModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QConcatenateTablesProxyModel::flags
+328 (int (*)(...))QAbstractItemModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QConcatenateTablesProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QConcatenateTablesProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QConcatenateTablesProxyModel (0x0x7fb8047cda90) 0
+ vptr=((& QConcatenateTablesProxyModel::_ZTV28QConcatenateTablesProxyModel) + 16)
+ QAbstractItemModel (0x0x7fb8047cdaf8) 0
+ primary-for QConcatenateTablesProxyModel (0x0x7fb8047cda90)
+ QObject (0x0x7fb8048295a0) 0
+ primary-for QAbstractItemModel (0x0x7fb8047cdaf8)
+
+Class QCryptographicHash
+ size=8 align=8
+ base size=8 base align=8
+QCryptographicHash (0x0x7fb8048297e0) 0
+
+Class QDataStream
+ size=32 align=8
+ base size=32 base align=8
+QDataStream (0x0x7fb804829900) 0
+
+Class QtPrivate::StreamStateSaver
+ size=16 align=8
+ base size=12 base align=8
+QtPrivate::StreamStateSaver (0x0x7fb804829a80) 0
+
+Class QElapsedTimer
+ size=16 align=8
+ base size=16 base align=8
+QElapsedTimer (0x0x7fb8044ef1e0) 0
+
+Class QDeadlineTimer
+ size=16 align=8
+ base size=16 base align=8
+QDeadlineTimer (0x0x7fb8044ef900) 0
+
+Class QFileDevice::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFileDevice::QPrivateSignal (0x0x7fb804630600) 0 empty
+
+Vtable for QFileDevice
+QFileDevice::_ZTV11QFileDevice: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QFileDevice)
+16 (int (*)(...))QFileDevice::metaObject
+24 (int (*)(...))QFileDevice::qt_metacast
+32 (int (*)(...))QFileDevice::qt_metacall
+40 (int (*)(...))QFileDevice::~QFileDevice
+48 (int (*)(...))QFileDevice::~QFileDevice
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QIODevice::open
+128 (int (*)(...))QFileDevice::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFileDevice::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QFileDevice::writeData
+240 (int (*)(...))QFileDevice::fileName
+248 (int (*)(...))QFileDevice::resize
+256 (int (*)(...))QFileDevice::permissions
+264 (int (*)(...))QFileDevice::setPermissions
+
+Class QFileDevice
+ size=16 align=8
+ base size=16 base align=8
+QFileDevice (0x0x7fb804620d00) 0
+ vptr=((& QFileDevice::_ZTV11QFileDevice) + 16)
+ QIODevice (0x0x7fb804620d68) 0
+ primary-for QFileDevice (0x0x7fb804620d00)
+ QObject (0x0x7fb8046305a0) 0
+ primary-for QIODevice (0x0x7fb804620d68)
+
+Class QFile::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFile::QPrivateSignal (0x0x7fb804630f00) 0 empty
+
+Vtable for QFile
+QFile::_ZTV5QFile: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI5QFile)
+16 (int (*)(...))QFile::metaObject
+24 (int (*)(...))QFile::qt_metacast
+32 (int (*)(...))QFile::qt_metacall
+40 (int (*)(...))QFile::~QFile
+48 (int (*)(...))QFile::~QFile
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QFile::open
+128 (int (*)(...))QFileDevice::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFile::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QFileDevice::writeData
+240 (int (*)(...))QFile::fileName
+248 (int (*)(...))QFile::resize
+256 (int (*)(...))QFile::permissions
+264 (int (*)(...))QFile::setPermissions
+
+Class QFile
+ size=16 align=8
+ base size=16 base align=8
+QFile (0x0x7fb804620ea0) 0
+ vptr=((& QFile::_ZTV5QFile) + 16)
+ QFileDevice (0x0x7fb804620f08) 0
+ primary-for QFile (0x0x7fb804620ea0)
+ QIODevice (0x0x7fb804620f70) 0
+ primary-for QFileDevice (0x0x7fb804620f08)
+ QObject (0x0x7fb804630ea0) 0
+ primary-for QIODevice (0x0x7fb804620f70)
+
+Class QFileInfo
+ size=8 align=8
+ base size=8 base align=8
+QFileInfo (0x0x7fb8042955a0) 0
+
+Class QDir
+ size=8 align=8
+ base size=8 base align=8
+QDir (0x0x7fb804372480) 0
+
+Class QDirIterator
+ size=8 align=8
+ base size=8 base align=8
+QDirIterator (0x0x7fb804089480) 0
+
+Class QEasingCurve
+ size=8 align=8
+ base size=8 base align=8
+QEasingCurve (0x0x7fb804089c00) 0
+
+Class QEventTransition::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QEventTransition::QPrivateSignal (0x0x7fb8041c7d20) 0 empty
+
+Vtable for QEventTransition
+QEventTransition::_ZTV16QEventTransition: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QEventTransition)
+16 (int (*)(...))QEventTransition::metaObject
+24 (int (*)(...))QEventTransition::qt_metacast
+32 (int (*)(...))QEventTransition::qt_metacall
+40 (int (*)(...))QEventTransition::~QEventTransition
+48 (int (*)(...))QEventTransition::~QEventTransition
+56 (int (*)(...))QEventTransition::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QEventTransition::eventTest
+120 (int (*)(...))QEventTransition::onTransition
+
+Class QEventTransition
+ size=16 align=8
+ base size=16 base align=8
+QEventTransition (0x0x7fb80418dc30) 0
+ vptr=((& QEventTransition::_ZTV16QEventTransition) + 16)
+ QAbstractTransition (0x0x7fb80418dc98) 0
+ primary-for QEventTransition (0x0x7fb80418dc30)
+ QObject (0x0x7fb8041c7cc0) 0
+ primary-for QAbstractTransition (0x0x7fb80418dc98)
+
+Vtable for QException
+QException::_ZTV10QException: 7 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QException)
+16 (int (*)(...))QException::~QException
+24 (int (*)(...))QException::~QException
+32 (int (*)(...))std::exception::what
+40 (int (*)(...))QException::raise
+48 (int (*)(...))QException::clone
+
+Class QException
+ size=8 align=8
+ base size=8 base align=8
+QException (0x0x7fb80418dd00) 0 nearly-empty
+ vptr=((& QException::_ZTV10QException) + 16)
+ std::exception (0x0x7fb8041c7f00) 0 nearly-empty
+ primary-for QException (0x0x7fb80418dd00)
+
+Vtable for QUnhandledException
+QUnhandledException::_ZTV19QUnhandledException: 7 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QUnhandledException)
+16 (int (*)(...))QUnhandledException::~QUnhandledException
+24 (int (*)(...))QUnhandledException::~QUnhandledException
+32 (int (*)(...))std::exception::what
+40 (int (*)(...))QUnhandledException::raise
+48 (int (*)(...))QUnhandledException::clone
+
+Class QUnhandledException
+ size=8 align=8
+ base size=8 base align=8
+QUnhandledException (0x0x7fb80418dd68) 0 nearly-empty
+ vptr=((& QUnhandledException::_ZTV19QUnhandledException) + 16)
+ QException (0x0x7fb80418ddd0) 0 nearly-empty
+ primary-for QUnhandledException (0x0x7fb80418dd68)
+ std::exception (0x0x7fb8041c7f60) 0 nearly-empty
+ primary-for QException (0x0x7fb80418ddd0)
+
+Class QtPrivate::ExceptionHolder
+ size=8 align=8
+ base size=8 base align=8
+QtPrivate::ExceptionHolder (0x0x7fb8041fe000) 0
+
+Class QtPrivate::ExceptionStore
+ size=8 align=8
+ base size=8 base align=8
+QtPrivate::ExceptionStore (0x0x7fb8041fe0c0) 0
+
+Vtable for QFactoryInterface
+QFactoryInterface::_ZTV17QFactoryInterface: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QFactoryInterface)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class QFactoryInterface
+ size=8 align=8
+ base size=8 base align=8
+QFactoryInterface (0x0x7fb8041fe120) 0 nearly-empty
+ vptr=((& QFactoryInterface::_ZTV17QFactoryInterface) + 16)
+
+Class QFileSelector::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFileSelector::QPrivateSignal (0x0x7fb8041fe360) 0 empty
+
+Vtable for QFileSelector
+QFileSelector::_ZTV13QFileSelector: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QFileSelector)
+16 (int (*)(...))QFileSelector::metaObject
+24 (int (*)(...))QFileSelector::qt_metacast
+32 (int (*)(...))QFileSelector::qt_metacall
+40 (int (*)(...))QFileSelector::~QFileSelector
+48 (int (*)(...))QFileSelector::~QFileSelector
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QFileSelector
+ size=16 align=8
+ base size=16 base align=8
+QFileSelector (0x0x7fb80418de38) 0
+ vptr=((& QFileSelector::_ZTV13QFileSelector) + 16)
+ QObject (0x0x7fb8041fe300) 0
+ primary-for QFileSelector (0x0x7fb80418de38)
+
+Class QFileSystemWatcher::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFileSystemWatcher::QPrivateSignal (0x0x7fb8041fe5a0) 0 empty
+
+Vtable for QFileSystemWatcher
+QFileSystemWatcher::_ZTV18QFileSystemWatcher: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QFileSystemWatcher)
+16 (int (*)(...))QFileSystemWatcher::metaObject
+24 (int (*)(...))QFileSystemWatcher::qt_metacast
+32 (int (*)(...))QFileSystemWatcher::qt_metacall
+40 (int (*)(...))QFileSystemWatcher::~QFileSystemWatcher
+48 (int (*)(...))QFileSystemWatcher::~QFileSystemWatcher
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QFileSystemWatcher
+ size=16 align=8
+ base size=16 base align=8
+QFileSystemWatcher (0x0x7fb80418dea0) 0
+ vptr=((& QFileSystemWatcher::_ZTV18QFileSystemWatcher) + 16)
+ QObject (0x0x7fb8041fe540) 0
+ primary-for QFileSystemWatcher (0x0x7fb80418dea0)
+
+Class QFinalState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFinalState::QPrivateSignal (0x0x7fb8041fe7e0) 0 empty
+
+Vtable for QFinalState
+QFinalState::_ZTV11QFinalState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QFinalState)
+16 (int (*)(...))QFinalState::metaObject
+24 (int (*)(...))QFinalState::qt_metacast
+32 (int (*)(...))QFinalState::qt_metacall
+40 (int (*)(...))QFinalState::~QFinalState
+48 (int (*)(...))QFinalState::~QFinalState
+56 (int (*)(...))QFinalState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFinalState::onEntry
+120 (int (*)(...))QFinalState::onExit
+
+Class QFinalState
+ size=16 align=8
+ base size=16 base align=8
+QFinalState (0x0x7fb80418df08) 0
+ vptr=((& QFinalState::_ZTV11QFinalState) + 16)
+ QAbstractState (0x0x7fb80418df70) 0
+ primary-for QFinalState (0x0x7fb80418df08)
+ QObject (0x0x7fb8041fe780) 0
+ primary-for QAbstractState (0x0x7fb80418df70)
+
+Vtable for QRunnable
+QRunnable::_ZTV9QRunnable: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QRunnable)
+16 (int (*)(...))__cxa_pure_virtual
+24 0
+32 0
+
+Class QRunnable
+ size=16 align=8
+ base size=12 base align=8
+QRunnable (0x0x7fb8041fe9c0) 0
+ vptr=((& QRunnable::_ZTV9QRunnable) + 16)
+
+Class QBasicMutex
+ size=8 align=8
+ base size=8 base align=8
+QBasicMutex (0x0x7fb8041fec60) 0
+
+Class QMutex
+ size=8 align=8
+ base size=8 base align=8
+QMutex (0x0x7fb803e34068) 0
+ QBasicMutex (0x0x7fb803e6d900) 0
+
+Class QRecursiveMutex
+ size=8 align=8
+ base size=8 base align=8
+QRecursiveMutex (0x0x7fb803e340d0) 0
+ QMutex (0x0x7fb803e34138) 0
+ QBasicMutex (0x0x7fb803e6db40) 0
+
+Class QMutexLocker
+ size=8 align=8
+ base size=8 base align=8
+QMutexLocker (0x0x7fb803e6dba0) 0
+
+Class QtPrivate::ResultItem
+ size=16 align=8
+ base size=16 base align=8
+QtPrivate::ResultItem (0x0x7fb803e941e0) 0
+
+Class QtPrivate::ResultIteratorBase
+ size=16 align=8
+ base size=12 base align=8
+QtPrivate::ResultIteratorBase (0x0x7fb803e947e0) 0
+
+Vtable for QtPrivate::ResultStoreBase
+QtPrivate::ResultStoreBase::_ZTVN9QtPrivate15ResultStoreBaseE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN9QtPrivate15ResultStoreBaseE)
+16 (int (*)(...))QtPrivate::ResultStoreBase::~ResultStoreBase
+24 (int (*)(...))QtPrivate::ResultStoreBase::~ResultStoreBase
+
+Class QtPrivate::ResultStoreBase
+ size=48 align=8
+ base size=44 base align=8
+QtPrivate::ResultStoreBase (0x0x7fb803e949c0) 0
+ vptr=((& QtPrivate::ResultStoreBase::_ZTVN9QtPrivate15ResultStoreBaseE) + 16)
+
+Class std::__mutex_base
+ size=40 align=8
+ base size=40 base align=8
+std::__mutex_base (0x0x7fb803f281e0) 0
+
+Class std::mutex
+ size=40 align=8
+ base size=40 base align=8
+std::mutex (0x0x7fb803f13a28) 0
+ std::__mutex_base (0x0x7fb803f28240) 0
+
+Class std::defer_lock_t
+ size=1 align=1
+ base size=0 base align=1
+std::defer_lock_t (0x0x7fb803f28420) 0 empty
+
+Class std::try_to_lock_t
+ size=1 align=1
+ base size=0 base align=1
+std::try_to_lock_t (0x0x7fb803f28480) 0 empty
+
+Class std::adopt_lock_t
+ size=1 align=1
+ base size=0 base align=1
+std::adopt_lock_t (0x0x7fb803f284e0) 0 empty
+
+Class std::__recursive_mutex_base
+ size=40 align=8
+ base size=40 base align=8
+std::__recursive_mutex_base (0x0x7fb803f28f00) 0
+
+Class std::recursive_mutex
+ size=40 align=8
+ base size=40 base align=8
+std::recursive_mutex (0x0x7fb803f13a90) 0
+ std::__recursive_mutex_base (0x0x7fb803f28f60) 0
+
+Class std::timed_mutex
+ size=40 align=8
+ base size=40 base align=8
+std::timed_mutex (0x0x7fb803f33af0) 0
+ std::__mutex_base (0x0x7fb803f64360) 0
+ std::__timed_mutex_impl<std::timed_mutex> (0x0x7fb803f643c0) 0 empty
+
+Class std::recursive_timed_mutex
+ size=40 align=8
+ base size=40 base align=8
+std::recursive_timed_mutex (0x0x7fb803f33e70) 0
+ std::__recursive_mutex_base (0x0x7fb803f64720) 0
+ std::__timed_mutex_impl<std::recursive_timed_mutex> (0x0x7fb803f64780) 0 empty
+
+Class std::once_flag
+ size=4 align=4
+ base size=4 base align=4
+std::once_flag (0x0x7fb803f64ea0) 0
+
+Vtable for QFutureInterfaceBase
+QFutureInterfaceBase::_ZTV20QFutureInterfaceBase: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QFutureInterfaceBase)
+16 (int (*)(...))QFutureInterfaceBase::~QFutureInterfaceBase
+24 (int (*)(...))QFutureInterfaceBase::~QFutureInterfaceBase
+
+Class QFutureInterfaceBase
+ size=16 align=8
+ base size=16 base align=8
+QFutureInterfaceBase (0x0x7fb803fab120) 0
+ vptr=((& QFutureInterfaceBase::_ZTV20QFutureInterfaceBase) + 16)
+
+Class QFutureWatcherBase::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QFutureWatcherBase::QPrivateSignal (0x0x7fb803c53480) 0 empty
+
+Vtable for QFutureWatcherBase
+QFutureWatcherBase::_ZTV18QFutureWatcherBase: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QFutureWatcherBase)
+16 (int (*)(...))QFutureWatcherBase::metaObject
+24 (int (*)(...))QFutureWatcherBase::qt_metacast
+32 (int (*)(...))QFutureWatcherBase::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QFutureWatcherBase::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QFutureWatcherBase::connectNotify
+104 (int (*)(...))QFutureWatcherBase::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))__cxa_pure_virtual
+
+Class QFutureWatcherBase
+ size=16 align=8
+ base size=16 base align=8
+QFutureWatcherBase (0x0x7fb803fd9888) 0
+ vptr=((& QFutureWatcherBase::_ZTV18QFutureWatcherBase) + 16)
+ QObject (0x0x7fb803c53420) 0
+ primary-for QFutureWatcherBase (0x0x7fb803fd9888)
+
+Class QHistoryState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QHistoryState::QPrivateSignal (0x0x7fb803c7d7e0) 0 empty
+
+Vtable for QHistoryState
+QHistoryState::_ZTV13QHistoryState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QHistoryState)
+16 (int (*)(...))QHistoryState::metaObject
+24 (int (*)(...))QHistoryState::qt_metacast
+32 (int (*)(...))QHistoryState::qt_metacall
+40 (int (*)(...))QHistoryState::~QHistoryState
+48 (int (*)(...))QHistoryState::~QHistoryState
+56 (int (*)(...))QHistoryState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QHistoryState::onEntry
+120 (int (*)(...))QHistoryState::onExit
+
+Class QHistoryState
+ size=16 align=8
+ base size=16 base align=8
+QHistoryState (0x0x7fb803c890d0) 0
+ vptr=((& QHistoryState::_ZTV13QHistoryState) + 16)
+ QAbstractState (0x0x7fb803c89138) 0
+ primary-for QHistoryState (0x0x7fb803c890d0)
+ QObject (0x0x7fb803c7d780) 0
+ primary-for QAbstractState (0x0x7fb803c89138)
+
+Class QIdentityProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QIdentityProxyModel::QPrivateSignal (0x0x7fb803c7dae0) 0 empty
+
+Vtable for QIdentityProxyModel
+QIdentityProxyModel::_ZTV19QIdentityProxyModel: 53 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QIdentityProxyModel)
+16 (int (*)(...))QIdentityProxyModel::metaObject
+24 (int (*)(...))QIdentityProxyModel::qt_metacast
+32 (int (*)(...))QIdentityProxyModel::qt_metacall
+40 (int (*)(...))QIdentityProxyModel::~QIdentityProxyModel
+48 (int (*)(...))QIdentityProxyModel::~QIdentityProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QIdentityProxyModel::index
+120 (int (*)(...))QIdentityProxyModel::parent
+128 (int (*)(...))QIdentityProxyModel::sibling
+136 (int (*)(...))QIdentityProxyModel::rowCount
+144 (int (*)(...))QIdentityProxyModel::columnCount
+152 (int (*)(...))QAbstractProxyModel::hasChildren
+160 (int (*)(...))QAbstractProxyModel::data
+168 (int (*)(...))QAbstractProxyModel::setData
+176 (int (*)(...))QIdentityProxyModel::headerData
+184 (int (*)(...))QAbstractProxyModel::setHeaderData
+192 (int (*)(...))QAbstractProxyModel::itemData
+200 (int (*)(...))QAbstractProxyModel::setItemData
+208 (int (*)(...))QAbstractProxyModel::mimeTypes
+216 (int (*)(...))QAbstractProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QIdentityProxyModel::dropMimeData
+240 (int (*)(...))QAbstractProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QIdentityProxyModel::insertRows
+264 (int (*)(...))QIdentityProxyModel::insertColumns
+272 (int (*)(...))QIdentityProxyModel::removeRows
+280 (int (*)(...))QIdentityProxyModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractProxyModel::fetchMore
+312 (int (*)(...))QAbstractProxyModel::canFetchMore
+320 (int (*)(...))QAbstractProxyModel::flags
+328 (int (*)(...))QAbstractProxyModel::sort
+336 (int (*)(...))QAbstractProxyModel::buddy
+344 (int (*)(...))QIdentityProxyModel::match
+352 (int (*)(...))QAbstractProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QIdentityProxyModel::setSourceModel
+392 (int (*)(...))QIdentityProxyModel::mapToSource
+400 (int (*)(...))QIdentityProxyModel::mapFromSource
+408 (int (*)(...))QIdentityProxyModel::mapSelectionToSource
+416 (int (*)(...))QIdentityProxyModel::mapSelectionFromSource
+
+Class QIdentityProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QIdentityProxyModel (0x0x7fb803c891a0) 0
+ vptr=((& QIdentityProxyModel::_ZTV19QIdentityProxyModel) + 16)
+ QAbstractProxyModel (0x0x7fb803c89208) 0
+ primary-for QIdentityProxyModel (0x0x7fb803c891a0)
+ QAbstractItemModel (0x0x7fb803c89270) 0
+ primary-for QAbstractProxyModel (0x0x7fb803c89208)
+ QObject (0x0x7fb803c7da80) 0
+ primary-for QAbstractItemModel (0x0x7fb803c89270)
+
+Class QItemSelectionRange
+ size=16 align=8
+ base size=16 base align=8
+QItemSelectionRange (0x0x7fb803c7dcc0) 0
+
+Class QItemSelectionModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QItemSelectionModel::QPrivateSignal (0x0x7fb803d64600) 0 empty
+
+Vtable for QItemSelectionModel
+QItemSelectionModel::_ZTV19QItemSelectionModel: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI19QItemSelectionModel)
+16 (int (*)(...))QItemSelectionModel::metaObject
+24 (int (*)(...))QItemSelectionModel::qt_metacast
+32 (int (*)(...))QItemSelectionModel::qt_metacall
+40 (int (*)(...))QItemSelectionModel::~QItemSelectionModel
+48 (int (*)(...))QItemSelectionModel::~QItemSelectionModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QItemSelectionModel::setCurrentIndex
+120 (int (*)(...))QItemSelectionModel::select
+128 (int (*)(...))QItemSelectionModel::select
+136 (int (*)(...))QItemSelectionModel::clear
+144 (int (*)(...))QItemSelectionModel::reset
+152 (int (*)(...))QItemSelectionModel::clearCurrentIndex
+
+Class QItemSelectionModel
+ size=16 align=8
+ base size=16 base align=8
+QItemSelectionModel (0x0x7fb803d59bc8) 0
+ vptr=((& QItemSelectionModel::_ZTV19QItemSelectionModel) + 16)
+ QObject (0x0x7fb803d645a0) 0
+ primary-for QItemSelectionModel (0x0x7fb803d59bc8)
+
+Class QItemSelection
+ size=8 align=8
+ base size=8 base align=8
+QItemSelection (0x0x7fb803d59d68) 0
+ QList<QItemSelectionRange> (0x0x7fb803d59dd0) 0
+ QListSpecialMethods<QItemSelectionRange> (0x0x7fb803dab120) 0 empty
+
+Class QJsonValue
+ size=24 align=8
+ base size=20 base align=8
+QJsonValue (0x0x7fb803e12a20) 0
+
+Class QJsonValueRef
+ size=16 align=8
+ base size=12 base align=8
+QJsonValueRef (0x0x7fb803b696c0) 0
+
+Class QJsonValuePtr
+ size=24 align=8
+ base size=24 base align=8
+QJsonValuePtr (0x0x7fb803bba660) 0
+
+Class QJsonValueRefPtr
+ size=16 align=8
+ base size=16 base align=8
+QJsonValueRefPtr (0x0x7fb803bba900) 0
+
+Class QJsonArray::iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonArray::iterator (0x0x7fb803bfdc60) 0
+
+Class QJsonArray::const_iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonArray::const_iterator (0x0x7fb803bfdcc0) 0
+
+Class QJsonArray
+ size=16 align=8
+ base size=16 base align=8
+QJsonArray (0x0x7fb803bfdc00) 0
+
+Class QJsonParseError
+ size=8 align=4
+ base size=8 base align=4
+QJsonParseError (0x0x7fb80392aba0) 0
+
+Class QJsonDocument
+ size=8 align=8
+ base size=8 base align=8
+QJsonDocument (0x0x7fb80392ac00) 0
+
+Class QJsonObject::iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonObject::iterator (0x0x7fb803998420) 0
+
+Class QJsonObject::const_iterator
+ size=16 align=8
+ base size=12 base align=8
+QJsonObject::const_iterator (0x0x7fb803998480) 0
+
+Class QJsonObject
+ size=16 align=8
+ base size=16 base align=8
+QJsonObject (0x0x7fb8039983c0) 0
+
+Class QLibrary::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QLibrary::QPrivateSignal (0x0x7fb8036bc8a0) 0 empty
+
+Vtable for QLibrary
+QLibrary::_ZTV8QLibrary: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI8QLibrary)
+16 (int (*)(...))QLibrary::metaObject
+24 (int (*)(...))QLibrary::qt_metacast
+32 (int (*)(...))QLibrary::qt_metacall
+40 (int (*)(...))QLibrary::~QLibrary
+48 (int (*)(...))QLibrary::~QLibrary
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QLibrary
+ size=32 align=8
+ base size=25 base align=8
+QLibrary (0x0x7fb8036b6a28) 0
+ vptr=((& QLibrary::_ZTV8QLibrary) + 16)
+ QObject (0x0x7fb8036bc840) 0
+ primary-for QLibrary (0x0x7fb8036b6a28)
+
+Class QVersionNumber::SegmentStorage
+ size=8 align=8
+ base size=8 base align=8
+QVersionNumber::SegmentStorage (0x0x7fb8036ff720) 0
+
+Class QVersionNumber
+ size=8 align=8
+ base size=8 base align=8
+QVersionNumber (0x0x7fb8036ff240) 0
+
+Class QLibraryInfo
+ size=1 align=1
+ base size=0 base align=1
+QLibraryInfo (0x0x7fb80379aea0) 0 empty
+
+Class QPoint
+ size=8 align=4
+ base size=8 base align=4
+QPoint (0x0x7fb80379af00) 0
+
+Class QPointF
+ size=16 align=8
+ base size=16 base align=8
+QPointF (0x0x7fb803811d80) 0
+
+Class QLine
+ size=16 align=4
+ base size=16 base align=4
+QLine (0x0x7fb803482f60) 0
+
+Class QLineF
+ size=32 align=8
+ base size=32 base align=8
+QLineF (0x0x7fb803512360) 0
+
+Class QLinkedListData
+ size=32 align=8
+ base size=25 base align=8
+QLinkedListData (0x0x7fb803589600) 0
+
+Class QLockFile
+ size=8 align=8
+ base size=8 base align=8
+QLockFile (0x0x7fb803233b40) 0
+
+Class QLoggingCategory::AtomicBools
+ size=4 align=1
+ base size=4 base align=1
+QLoggingCategory::AtomicBools (0x0x7fb803233d80) 0
+
+Class QLoggingCategory
+ size=24 align=8
+ base size=24 base align=8
+QLoggingCategory (0x0x7fb803233d20) 0
+
+Class QMargins
+ size=16 align=4
+ base size=16 base align=4
+QMargins (0x0x7fb8032a41e0) 0
+
+Class QMarginsF
+ size=32 align=8
+ base size=32 base align=8
+QMarginsF (0x0x7fb803323120) 0
+
+Class QMessageAuthenticationCode
+ size=8 align=8
+ base size=8 base align=8
+QMessageAuthenticationCode (0x0x7fb80315c900) 0
+
+Class QMetaMethod
+ size=16 align=8
+ base size=12 base align=8
+QMetaMethod (0x0x7fb80315c960) 0
+
+Class QMetaEnum
+ size=16 align=8
+ base size=12 base align=8
+QMetaEnum (0x0x7fb8031e31e0) 0
+
+Class QMetaProperty
+ size=32 align=8
+ base size=32 base align=8
+QMetaProperty (0x0x7fb802da63c0) 0
+
+Class QMetaClassInfo
+ size=16 align=8
+ base size=12 base align=8
+QMetaClassInfo (0x0x7fb802da64e0) 0
+
+Class QMimeData::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QMimeData::QPrivateSignal (0x0x7fb802de5a80) 0 empty
+
+Vtable for QMimeData
+QMimeData::_ZTV9QMimeData: 17 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QMimeData)
+16 (int (*)(...))QMimeData::metaObject
+24 (int (*)(...))QMimeData::qt_metacast
+32 (int (*)(...))QMimeData::qt_metacall
+40 (int (*)(...))QMimeData::~QMimeData
+48 (int (*)(...))QMimeData::~QMimeData
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QMimeData::hasFormat
+120 (int (*)(...))QMimeData::formats
+128 (int (*)(...))QMimeData::retrieveData
+
+Class QMimeData
+ size=16 align=8
+ base size=16 base align=8
+QMimeData (0x0x7fb802dec680) 0
+ vptr=((& QMimeData::_ZTV9QMimeData) + 16)
+ QObject (0x0x7fb802de5a20) 0
+ primary-for QMimeData (0x0x7fb802dec680)
+
+Class QMimeType
+ size=8 align=8
+ base size=8 base align=8
+QMimeType (0x0x7fb802de5c60) 0
+
+Class QMimeDatabase
+ size=8 align=8
+ base size=8 base align=8
+QMimeDatabase (0x0x7fb802eb1ba0) 0
+
+Class QObjectCleanupHandler::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QObjectCleanupHandler::QPrivateSignal (0x0x7fb802eb1c60) 0 empty
+
+Vtable for QObjectCleanupHandler
+QObjectCleanupHandler::_ZTV21QObjectCleanupHandler: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QObjectCleanupHandler)
+16 (int (*)(...))QObjectCleanupHandler::metaObject
+24 (int (*)(...))QObjectCleanupHandler::qt_metacast
+32 (int (*)(...))QObjectCleanupHandler::qt_metacall
+40 (int (*)(...))QObjectCleanupHandler::~QObjectCleanupHandler
+48 (int (*)(...))QObjectCleanupHandler::~QObjectCleanupHandler
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QObjectCleanupHandler
+ size=24 align=8
+ base size=24 base align=8
+QObjectCleanupHandler (0x0x7fb802ec4208) 0
+ vptr=((& QObjectCleanupHandler::_ZTV21QObjectCleanupHandler) + 16)
+ QObject (0x0x7fb802eb1c00) 0
+ primary-for QObjectCleanupHandler (0x0x7fb802ec4208)
+
+Class QOperatingSystemVersion
+ size=16 align=4
+ base size=16 base align=4
+QOperatingSystemVersion (0x0x7fb802eb1d80) 0
+
+Class QParallelAnimationGroup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QParallelAnimationGroup::QPrivateSignal (0x0x7fb802f3f540) 0 empty
+
+Vtable for QParallelAnimationGroup
+QParallelAnimationGroup::_ZTV23QParallelAnimationGroup: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI23QParallelAnimationGroup)
+16 (int (*)(...))QParallelAnimationGroup::metaObject
+24 (int (*)(...))QParallelAnimationGroup::qt_metacast
+32 (int (*)(...))QParallelAnimationGroup::qt_metacall
+40 (int (*)(...))QParallelAnimationGroup::~QParallelAnimationGroup
+48 (int (*)(...))QParallelAnimationGroup::~QParallelAnimationGroup
+56 (int (*)(...))QParallelAnimationGroup::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QParallelAnimationGroup::duration
+120 (int (*)(...))QParallelAnimationGroup::updateCurrentTime
+128 (int (*)(...))QParallelAnimationGroup::updateState
+136 (int (*)(...))QParallelAnimationGroup::updateDirection
+
+Class QParallelAnimationGroup
+ size=16 align=8
+ base size=16 base align=8
+QParallelAnimationGroup (0x0x7fb802f3ca90) 0
+ vptr=((& QParallelAnimationGroup::_ZTV23QParallelAnimationGroup) + 16)
+ QAnimationGroup (0x0x7fb802f3caf8) 0
+ primary-for QParallelAnimationGroup (0x0x7fb802f3ca90)
+ QAbstractAnimation (0x0x7fb802f3cb60) 0
+ primary-for QAnimationGroup (0x0x7fb802f3caf8)
+ QObject (0x0x7fb802f3f4e0) 0
+ primary-for QAbstractAnimation (0x0x7fb802f3cb60)
+
+Class QPauseAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QPauseAnimation::QPrivateSignal (0x0x7fb802f3f780) 0 empty
+
+Vtable for QPauseAnimation
+QPauseAnimation::_ZTV15QPauseAnimation: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QPauseAnimation)
+16 (int (*)(...))QPauseAnimation::metaObject
+24 (int (*)(...))QPauseAnimation::qt_metacast
+32 (int (*)(...))QPauseAnimation::qt_metacall
+40 (int (*)(...))QPauseAnimation::~QPauseAnimation
+48 (int (*)(...))QPauseAnimation::~QPauseAnimation
+56 (int (*)(...))QPauseAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QPauseAnimation::duration
+120 (int (*)(...))QPauseAnimation::updateCurrentTime
+128 (int (*)(...))QAbstractAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+
+Class QPauseAnimation
+ size=16 align=8
+ base size=16 base align=8
+QPauseAnimation (0x0x7fb802f3cbc8) 0
+ vptr=((& QPauseAnimation::_ZTV15QPauseAnimation) + 16)
+ QAbstractAnimation (0x0x7fb802f3cc30) 0
+ primary-for QPauseAnimation (0x0x7fb802f3cbc8)
+ QObject (0x0x7fb802f3f720) 0
+ primary-for QAbstractAnimation (0x0x7fb802f3cc30)
+
+Class QStaticPlugin
+ size=16 align=8
+ base size=16 base align=8
+QStaticPlugin (0x0x7fb802f78300) 0
+
+Class QPluginLoader::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QPluginLoader::QPrivateSignal (0x0x7fb802bb6480) 0 empty
+
+Vtable for QPluginLoader
+QPluginLoader::_ZTV13QPluginLoader: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QPluginLoader)
+16 (int (*)(...))QPluginLoader::metaObject
+24 (int (*)(...))QPluginLoader::qt_metacast
+32 (int (*)(...))QPluginLoader::qt_metacall
+40 (int (*)(...))QPluginLoader::~QPluginLoader
+48 (int (*)(...))QPluginLoader::~QPluginLoader
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QPluginLoader
+ size=32 align=8
+ base size=25 base align=8
+QPluginLoader (0x0x7fb802ba6f70) 0
+ vptr=((& QPluginLoader::_ZTV13QPluginLoader) + 16)
+ QObject (0x0x7fb802bb6420) 0
+ primary-for QPluginLoader (0x0x7fb802ba6f70)
+
+Class QProcessEnvironment
+ size=8 align=8
+ base size=8 base align=8
+QProcessEnvironment (0x0x7fb802bb65a0) 0
+
+Class QProcess::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QProcess::QPrivateSignal (0x0x7fb802c88a20) 0 empty
+
+Vtable for QProcess
+QProcess::_ZTV8QProcess: 31 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI8QProcess)
+16 (int (*)(...))QProcess::metaObject
+24 (int (*)(...))QProcess::qt_metacast
+32 (int (*)(...))QProcess::qt_metacall
+40 (int (*)(...))QProcess::~QProcess
+48 (int (*)(...))QProcess::~QProcess
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QProcess::isSequential
+120 (int (*)(...))QProcess::open
+128 (int (*)(...))QProcess::close
+136 (int (*)(...))QIODevice::pos
+144 (int (*)(...))QIODevice::size
+152 (int (*)(...))QIODevice::seek
+160 (int (*)(...))QProcess::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QProcess::bytesAvailable
+184 (int (*)(...))QProcess::bytesToWrite
+192 (int (*)(...))QProcess::canReadLine
+200 (int (*)(...))QProcess::waitForReadyRead
+208 (int (*)(...))QProcess::waitForBytesWritten
+216 (int (*)(...))QProcess::readData
+224 (int (*)(...))QIODevice::readLineData
+232 (int (*)(...))QProcess::writeData
+240 (int (*)(...))QProcess::setupChildProcess
+
+Class QProcess
+ size=16 align=8
+ base size=16 base align=8
+QProcess (0x0x7fb802c8e410) 0
+ vptr=((& QProcess::_ZTV8QProcess) + 16)
+ QIODevice (0x0x7fb802c8e478) 0
+ primary-for QProcess (0x0x7fb802c8e410)
+ QObject (0x0x7fb802c889c0) 0
+ primary-for QIODevice (0x0x7fb802c8e478)
+
+Class QVariantAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QVariantAnimation::QPrivateSignal (0x0x7fb802cc6120) 0 empty
+
+Vtable for QVariantAnimation
+QVariantAnimation::_ZTV17QVariantAnimation: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QVariantAnimation)
+16 (int (*)(...))QVariantAnimation::metaObject
+24 (int (*)(...))QVariantAnimation::qt_metacast
+32 (int (*)(...))QVariantAnimation::qt_metacall
+40 (int (*)(...))QVariantAnimation::~QVariantAnimation
+48 (int (*)(...))QVariantAnimation::~QVariantAnimation
+56 (int (*)(...))QVariantAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QVariantAnimation::duration
+120 (int (*)(...))QVariantAnimation::updateCurrentTime
+128 (int (*)(...))QVariantAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+144 (int (*)(...))QVariantAnimation::updateCurrentValue
+152 (int (*)(...))QVariantAnimation::interpolated
+
+Class QVariantAnimation
+ size=16 align=8
+ base size=16 base align=8
+QVariantAnimation (0x0x7fb802c8e4e0) 0
+ vptr=((& QVariantAnimation::_ZTV17QVariantAnimation) + 16)
+ QAbstractAnimation (0x0x7fb802c8e548) 0
+ primary-for QVariantAnimation (0x0x7fb802c8e4e0)
+ QObject (0x0x7fb802cc60c0) 0
+ primary-for QAbstractAnimation (0x0x7fb802c8e548)
+
+Class QPropertyAnimation::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QPropertyAnimation::QPrivateSignal (0x0x7fb802cc63c0) 0 empty
+
+Vtable for QPropertyAnimation
+QPropertyAnimation::_ZTV18QPropertyAnimation: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI18QPropertyAnimation)
+16 (int (*)(...))QPropertyAnimation::metaObject
+24 (int (*)(...))QPropertyAnimation::qt_metacast
+32 (int (*)(...))QPropertyAnimation::qt_metacall
+40 (int (*)(...))QPropertyAnimation::~QPropertyAnimation
+48 (int (*)(...))QPropertyAnimation::~QPropertyAnimation
+56 (int (*)(...))QPropertyAnimation::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QVariantAnimation::duration
+120 (int (*)(...))QVariantAnimation::updateCurrentTime
+128 (int (*)(...))QPropertyAnimation::updateState
+136 (int (*)(...))QAbstractAnimation::updateDirection
+144 (int (*)(...))QPropertyAnimation::updateCurrentValue
+152 (int (*)(...))QVariantAnimation::interpolated
+
+Class QPropertyAnimation
+ size=16 align=8
+ base size=16 base align=8
+QPropertyAnimation (0x0x7fb802c8e618) 0
+ vptr=((& QPropertyAnimation::_ZTV18QPropertyAnimation) + 16)
+ QVariantAnimation (0x0x7fb802c8e680) 0
+ primary-for QPropertyAnimation (0x0x7fb802c8e618)
+ QAbstractAnimation (0x0x7fb802c8e6e8) 0
+ primary-for QVariantAnimation (0x0x7fb802c8e680)
+ QObject (0x0x7fb802cc6360) 0
+ primary-for QAbstractAnimation (0x0x7fb802c8e6e8)
+
+Class std::random_device
+ size=5000 align=8
+ base size=5000 base align=8
+std::random_device (0x0x7fb802d4dae0) 0
+
+Class std::bernoulli_distribution::param_type
+ size=8 align=8
+ base size=8 base align=8
+std::bernoulli_distribution::param_type (0x0x7fb802a44840) 0
+
+Class std::bernoulli_distribution
+ size=8 align=8
+ base size=8 base align=8
+std::bernoulli_distribution (0x0x7fb802a447e0) 0
+
+Class std::seed_seq
+ size=24 align=8
+ base size=24 base align=8
+std::seed_seq (0x0x7fb80284b5a0) 0
+
+Class QRandomGenerator::Storage
+ size=2504 align=8
+ base size=2504 base align=8
+QRandomGenerator::Storage (0x0x7fb80267f240) 0
+
+Class QRandomGenerator
+ size=2512 align=8
+ base size=2512 base align=8
+QRandomGenerator (0x0x7fb80267f1e0) 0
+
+Class QRandomGenerator64
+ size=2512 align=8
+ base size=2512 base align=8
+QRandomGenerator64 (0x0x7fb8027003a8) 0
+ QRandomGenerator (0x0x7fb8026f8d20) 0
+
+Class QReadWriteLock
+ size=8 align=8
+ base size=8 base align=8
+QReadWriteLock (0x0x7fb802724900) 0
+
+Class QReadLocker
+ size=8 align=8
+ base size=8 base align=8
+QReadLocker (0x0x7fb802724ba0) 0
+
+Class QWriteLocker
+ size=8 align=8
+ base size=8 base align=8
+QWriteLocker (0x0x7fb8023a80c0) 0
+
+Class QSize
+ size=8 align=4
+ base size=8 base align=4
+QSize (0x0x7fb8023a85a0) 0
+
+Class QSizeF
+ size=16 align=8
+ base size=16 base align=8
+QSizeF (0x0x7fb802419480) 0
+
+Class QRect
+ size=16 align=4
+ base size=16 base align=4
+QRect (0x0x7fb8024924e0) 0
+
+Class QRectF
+ size=32 align=8
+ base size=32 base align=8
+QRectF (0x0x7fb80254c540) 0
+
+Class QResource
+ size=8 align=8
+ base size=8 base align=8
+QResource (0x0x7fb802208660) 0
+
+Class QSaveFile::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSaveFile::QPrivateSignal (0x0x7fb802208900) 0 empty
+
+Vtable for QSaveFile
+QSaveFile::_ZTV9QSaveFile: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QSaveFile)
+16 (int (*)(...))QSaveFile::metaObject
+24 (int (*)(...))QSaveFile::qt_metacast
+32 (int (*)(...))QSaveFile::qt_metacall
+40 (int (*)(...))QSaveFile::~QSaveFile
+48 (int (*)(...))QSaveFile::~QSaveFile
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QSaveFile::open
+128 (int (*)(...))QSaveFile::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFileDevice::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QSaveFile::writeData
+240 (int (*)(...))QSaveFile::fileName
+248 (int (*)(...))QFileDevice::resize
+256 (int (*)(...))QFileDevice::permissions
+264 (int (*)(...))QFileDevice::setPermissions
+
+Class QSaveFile
+ size=16 align=8
+ base size=16 base align=8
+QSaveFile (0x0x7fb8021b2d68) 0
+ vptr=((& QSaveFile::_ZTV9QSaveFile) + 16)
+ QFileDevice (0x0x7fb8021b2dd0) 0
+ primary-for QSaveFile (0x0x7fb8021b2d68)
+ QIODevice (0x0x7fb8021b2e38) 0
+ primary-for QFileDevice (0x0x7fb8021b2dd0)
+ QObject (0x0x7fb8022088a0) 0
+ primary-for QIODevice (0x0x7fb8021b2e38)
+
+Class QSemaphore
+ size=8 align=8
+ base size=8 base align=8
+QSemaphore (0x0x7fb802208f00) 0
+
+Class QSemaphoreReleaser
+ size=16 align=8
+ base size=12 base align=8
+QSemaphoreReleaser (0x0x7fb8022600c0) 0
+
+Class QSequentialAnimationGroup::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSequentialAnimationGroup::QPrivateSignal (0x0x7fb80230bcc0) 0 empty
+
+Vtable for QSequentialAnimationGroup
+QSequentialAnimationGroup::_ZTV25QSequentialAnimationGroup: 18 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI25QSequentialAnimationGroup)
+16 (int (*)(...))QSequentialAnimationGroup::metaObject
+24 (int (*)(...))QSequentialAnimationGroup::qt_metacast
+32 (int (*)(...))QSequentialAnimationGroup::qt_metacall
+40 (int (*)(...))QSequentialAnimationGroup::~QSequentialAnimationGroup
+48 (int (*)(...))QSequentialAnimationGroup::~QSequentialAnimationGroup
+56 (int (*)(...))QSequentialAnimationGroup::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QSequentialAnimationGroup::duration
+120 (int (*)(...))QSequentialAnimationGroup::updateCurrentTime
+128 (int (*)(...))QSequentialAnimationGroup::updateState
+136 (int (*)(...))QSequentialAnimationGroup::updateDirection
+
+Class QSequentialAnimationGroup
+ size=16 align=8
+ base size=16 base align=8
+QSequentialAnimationGroup (0x0x7fb80231f618) 0
+ vptr=((& QSequentialAnimationGroup::_ZTV25QSequentialAnimationGroup) + 16)
+ QAnimationGroup (0x0x7fb80231f680) 0
+ primary-for QSequentialAnimationGroup (0x0x7fb80231f618)
+ QAbstractAnimation (0x0x7fb80231f6e8) 0
+ primary-for QAnimationGroup (0x0x7fb80231f680)
+ QObject (0x0x7fb80230bc60) 0
+ primary-for QAbstractAnimation (0x0x7fb80231f6e8)
+
+Class QSettings::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSettings::QPrivateSignal (0x0x7fb80230bf00) 0 empty
+
+Vtable for QSettings
+QSettings::_ZTV9QSettings: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QSettings)
+16 (int (*)(...))QSettings::metaObject
+24 (int (*)(...))QSettings::qt_metacast
+32 (int (*)(...))QSettings::qt_metacall
+40 (int (*)(...))QSettings::~QSettings
+48 (int (*)(...))QSettings::~QSettings
+56 (int (*)(...))QSettings::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSettings
+ size=16 align=8
+ base size=16 base align=8
+QSettings (0x0x7fb80231f750) 0
+ vptr=((& QSettings::_ZTV9QSettings) + 16)
+ QObject (0x0x7fb80230bea0) 0
+ primary-for QSettings (0x0x7fb80231f750)
+
+Class QSharedMemory::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSharedMemory::QPrivateSignal (0x0x7fb8023533c0) 0 empty
+
+Vtable for QSharedMemory
+QSharedMemory::_ZTV13QSharedMemory: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QSharedMemory)
+16 (int (*)(...))QSharedMemory::metaObject
+24 (int (*)(...))QSharedMemory::qt_metacast
+32 (int (*)(...))QSharedMemory::qt_metacall
+40 (int (*)(...))QSharedMemory::~QSharedMemory
+48 (int (*)(...))QSharedMemory::~QSharedMemory
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSharedMemory
+ size=16 align=8
+ base size=16 base align=8
+QSharedMemory (0x0x7fb80231f7b8) 0
+ vptr=((& QSharedMemory::_ZTV13QSharedMemory) + 16)
+ QObject (0x0x7fb802353360) 0
+ primary-for QSharedMemory (0x0x7fb80231f7b8)
+
+Class QSignalMapper::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSignalMapper::QPrivateSignal (0x0x7fb802353600) 0 empty
+
+Vtable for QSignalMapper
+QSignalMapper::_ZTV13QSignalMapper: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QSignalMapper)
+16 (int (*)(...))QSignalMapper::metaObject
+24 (int (*)(...))QSignalMapper::qt_metacast
+32 (int (*)(...))QSignalMapper::qt_metacall
+40 (int (*)(...))QSignalMapper::~QSignalMapper
+48 (int (*)(...))QSignalMapper::~QSignalMapper
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSignalMapper
+ size=16 align=8
+ base size=16 base align=8
+QSignalMapper (0x0x7fb80231f820) 0
+ vptr=((& QSignalMapper::_ZTV13QSignalMapper) + 16)
+ QObject (0x0x7fb8023535a0) 0
+ primary-for QSignalMapper (0x0x7fb80231f820)
+
+Class QSignalTransition::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSignalTransition::QPrivateSignal (0x0x7fb802353840) 0 empty
+
+Vtable for QSignalTransition
+QSignalTransition::_ZTV17QSignalTransition: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QSignalTransition)
+16 (int (*)(...))QSignalTransition::metaObject
+24 (int (*)(...))QSignalTransition::qt_metacast
+32 (int (*)(...))QSignalTransition::qt_metacall
+40 (int (*)(...))QSignalTransition::~QSignalTransition
+48 (int (*)(...))QSignalTransition::~QSignalTransition
+56 (int (*)(...))QSignalTransition::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QSignalTransition::eventTest
+120 (int (*)(...))QSignalTransition::onTransition
+
+Class QSignalTransition
+ size=16 align=8
+ base size=16 base align=8
+QSignalTransition (0x0x7fb80231f888) 0
+ vptr=((& QSignalTransition::_ZTV17QSignalTransition) + 16)
+ QAbstractTransition (0x0x7fb80231f8f0) 0
+ primary-for QSignalTransition (0x0x7fb80231f888)
+ QObject (0x0x7fb8023537e0) 0
+ primary-for QAbstractTransition (0x0x7fb80231f8f0)
+
+Class QSocketNotifier::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSocketNotifier::QPrivateSignal (0x0x7fb802353ae0) 0 empty
+
+Vtable for QSocketNotifier
+QSocketNotifier::_ZTV15QSocketNotifier: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI15QSocketNotifier)
+16 (int (*)(...))QSocketNotifier::metaObject
+24 (int (*)(...))QSocketNotifier::qt_metacast
+32 (int (*)(...))QSocketNotifier::qt_metacall
+40 (int (*)(...))QSocketNotifier::~QSocketNotifier
+48 (int (*)(...))QSocketNotifier::~QSocketNotifier
+56 (int (*)(...))QSocketNotifier::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QSocketNotifier
+ size=16 align=8
+ base size=16 base align=8
+QSocketNotifier (0x0x7fb80231f958) 0
+ vptr=((& QSocketNotifier::_ZTV15QSocketNotifier) + 16)
+ QObject (0x0x7fb802353a80) 0
+ primary-for QSocketNotifier (0x0x7fb80231f958)
+
+Class QSortFilterProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QSortFilterProxyModel::QPrivateSignal (0x0x7fb802353d20) 0 empty
+
+Vtable for QSortFilterProxyModel
+QSortFilterProxyModel::_ZTV21QSortFilterProxyModel: 56 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QSortFilterProxyModel)
+16 (int (*)(...))QSortFilterProxyModel::metaObject
+24 (int (*)(...))QSortFilterProxyModel::qt_metacast
+32 (int (*)(...))QSortFilterProxyModel::qt_metacall
+40 (int (*)(...))QSortFilterProxyModel::~QSortFilterProxyModel
+48 (int (*)(...))QSortFilterProxyModel::~QSortFilterProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QSortFilterProxyModel::index
+120 (int (*)(...))QSortFilterProxyModel::parent
+128 (int (*)(...))QSortFilterProxyModel::sibling
+136 (int (*)(...))QSortFilterProxyModel::rowCount
+144 (int (*)(...))QSortFilterProxyModel::columnCount
+152 (int (*)(...))QSortFilterProxyModel::hasChildren
+160 (int (*)(...))QSortFilterProxyModel::data
+168 (int (*)(...))QSortFilterProxyModel::setData
+176 (int (*)(...))QSortFilterProxyModel::headerData
+184 (int (*)(...))QSortFilterProxyModel::setHeaderData
+192 (int (*)(...))QAbstractProxyModel::itemData
+200 (int (*)(...))QAbstractProxyModel::setItemData
+208 (int (*)(...))QSortFilterProxyModel::mimeTypes
+216 (int (*)(...))QSortFilterProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QSortFilterProxyModel::dropMimeData
+240 (int (*)(...))QSortFilterProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QSortFilterProxyModel::insertRows
+264 (int (*)(...))QSortFilterProxyModel::insertColumns
+272 (int (*)(...))QSortFilterProxyModel::removeRows
+280 (int (*)(...))QSortFilterProxyModel::removeColumns
+288 (int (*)(...))QAbstractItemModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QSortFilterProxyModel::fetchMore
+312 (int (*)(...))QSortFilterProxyModel::canFetchMore
+320 (int (*)(...))QSortFilterProxyModel::flags
+328 (int (*)(...))QSortFilterProxyModel::sort
+336 (int (*)(...))QSortFilterProxyModel::buddy
+344 (int (*)(...))QSortFilterProxyModel::match
+352 (int (*)(...))QSortFilterProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QSortFilterProxyModel::setSourceModel
+392 (int (*)(...))QSortFilterProxyModel::mapToSource
+400 (int (*)(...))QSortFilterProxyModel::mapFromSource
+408 (int (*)(...))QSortFilterProxyModel::mapSelectionToSource
+416 (int (*)(...))QSortFilterProxyModel::mapSelectionFromSource
+424 (int (*)(...))QSortFilterProxyModel::filterAcceptsRow
+432 (int (*)(...))QSortFilterProxyModel::filterAcceptsColumn
+440 (int (*)(...))QSortFilterProxyModel::lessThan
+
+Class QSortFilterProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QSortFilterProxyModel (0x0x7fb80231f9c0) 0
+ vptr=((& QSortFilterProxyModel::_ZTV21QSortFilterProxyModel) + 16)
+ QAbstractProxyModel (0x0x7fb80231fa28) 0
+ primary-for QSortFilterProxyModel (0x0x7fb80231f9c0)
+ QAbstractItemModel (0x0x7fb80231fa90) 0
+ primary-for QAbstractProxyModel (0x0x7fb80231fa28)
+ QObject (0x0x7fb802353cc0) 0
+ primary-for QAbstractItemModel (0x0x7fb80231fa90)
+
+Class QStandardPaths
+ size=1 align=1
+ base size=0 base align=1
+QStandardPaths (0x0x7fb801fc0180) 0 empty
+
+Class QState::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QState::QPrivateSignal (0x0x7fb801fc0a80) 0 empty
+
+Vtable for QState
+QState::_ZTV6QState: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI6QState)
+16 (int (*)(...))QState::metaObject
+24 (int (*)(...))QState::qt_metacast
+32 (int (*)(...))QState::qt_metacall
+40 (int (*)(...))QState::~QState
+48 (int (*)(...))QState::~QState
+56 (int (*)(...))QState::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QState::onEntry
+120 (int (*)(...))QState::onExit
+
+Class QState
+ size=16 align=8
+ base size=16 base align=8
+QState (0x0x7fb80231fc30) 0
+ vptr=((& QState::_ZTV6QState) + 16)
+ QAbstractState (0x0x7fb80231fc98) 0
+ primary-for QState (0x0x7fb80231fc30)
+ QObject (0x0x7fb801fc0a20) 0
+ primary-for QAbstractState (0x0x7fb80231fc98)
+
+Class QStateMachine::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QStateMachine::QPrivateSignal (0x0x7fb801fc0f00) 0 empty
+
+Vtable for QStateMachine::SignalEvent
+QStateMachine::SignalEvent::_ZTVN13QStateMachine11SignalEventE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN13QStateMachine11SignalEventE)
+16 (int (*)(...))QStateMachine::SignalEvent::~SignalEvent
+24 (int (*)(...))QStateMachine::SignalEvent::~SignalEvent
+
+Class QStateMachine::SignalEvent
+ size=48 align=8
+ base size=48 base align=8
+QStateMachine::SignalEvent (0x0x7fb80231fe38) 0
+ vptr=((& QStateMachine::SignalEvent::_ZTVN13QStateMachine11SignalEventE) + 16)
+ QEvent (0x0x7fb801fc0f60) 0
+ primary-for QStateMachine::SignalEvent (0x0x7fb80231fe38)
+
+Vtable for QStateMachine::WrappedEvent
+QStateMachine::WrappedEvent::_ZTVN13QStateMachine12WrappedEventE: 4 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTIN13QStateMachine12WrappedEventE)
+16 (int (*)(...))QStateMachine::WrappedEvent::~WrappedEvent
+24 (int (*)(...))QStateMachine::WrappedEvent::~WrappedEvent
+
+Class QStateMachine::WrappedEvent
+ size=40 align=8
+ base size=40 base align=8
+QStateMachine::WrappedEvent (0x0x7fb80231fea0) 0
+ vptr=((& QStateMachine::WrappedEvent::_ZTVN13QStateMachine12WrappedEventE) + 16)
+ QEvent (0x0x7fb802018000) 0
+ primary-for QStateMachine::WrappedEvent (0x0x7fb80231fea0)
+
+Vtable for QStateMachine
+QStateMachine::_ZTV13QStateMachine: 20 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI13QStateMachine)
+16 (int (*)(...))QStateMachine::metaObject
+24 (int (*)(...))QStateMachine::qt_metacast
+32 (int (*)(...))QStateMachine::qt_metacall
+40 (int (*)(...))QStateMachine::~QStateMachine
+48 (int (*)(...))QStateMachine::~QStateMachine
+56 (int (*)(...))QStateMachine::event
+64 (int (*)(...))QStateMachine::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QStateMachine::onEntry
+120 (int (*)(...))QStateMachine::onExit
+128 (int (*)(...))QStateMachine::beginSelectTransitions
+136 (int (*)(...))QStateMachine::endSelectTransitions
+144 (int (*)(...))QStateMachine::beginMicrostep
+152 (int (*)(...))QStateMachine::endMicrostep
+
+Class QStateMachine
+ size=16 align=8
+ base size=16 base align=8
+QStateMachine (0x0x7fb80231fd00) 0
+ vptr=((& QStateMachine::_ZTV13QStateMachine) + 16)
+ QState (0x0x7fb80231fd68) 0
+ primary-for QStateMachine (0x0x7fb80231fd00)
+ QAbstractState (0x0x7fb80231fdd0) 0
+ primary-for QState (0x0x7fb80231fd68)
+ QObject (0x0x7fb801fc0ea0) 0
+ primary-for QAbstractState (0x0x7fb80231fdd0)
+
+Class QStorageInfo
+ size=8 align=8
+ base size=8 base align=8
+QStorageInfo (0x0x7fb8020183c0) 0
+
+Class QAbstractConcatenable
+ size=1 align=1
+ base size=0 base align=1
+QAbstractConcatenable (0x0x7fb802124180) 0 empty
+
+Class QStringListModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QStringListModel::QPrivateSignal (0x0x7fb801dad4e0) 0 empty
+
+Vtable for QStringListModel
+QStringListModel::_ZTV16QStringListModel: 48 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QStringListModel)
+16 (int (*)(...))QStringListModel::metaObject
+24 (int (*)(...))QStringListModel::qt_metacast
+32 (int (*)(...))QStringListModel::qt_metacall
+40 (int (*)(...))QStringListModel::~QStringListModel
+48 (int (*)(...))QStringListModel::~QStringListModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QAbstractListModel::index
+120 (int (*)(...))QAbstractListModel::parent
+128 (int (*)(...))QStringListModel::sibling
+136 (int (*)(...))QStringListModel::rowCount
+144 (int (*)(...))QAbstractListModel::columnCount
+152 (int (*)(...))QAbstractListModel::hasChildren
+160 (int (*)(...))QStringListModel::data
+168 (int (*)(...))QStringListModel::setData
+176 (int (*)(...))QAbstractItemModel::headerData
+184 (int (*)(...))QAbstractItemModel::setHeaderData
+192 (int (*)(...))QStringListModel::itemData
+200 (int (*)(...))QStringListModel::setItemData
+208 (int (*)(...))QAbstractItemModel::mimeTypes
+216 (int (*)(...))QAbstractItemModel::mimeData
+224 (int (*)(...))QAbstractItemModel::canDropMimeData
+232 (int (*)(...))QAbstractListModel::dropMimeData
+240 (int (*)(...))QStringListModel::supportedDropActions
+248 (int (*)(...))QAbstractItemModel::supportedDragActions
+256 (int (*)(...))QStringListModel::insertRows
+264 (int (*)(...))QAbstractItemModel::insertColumns
+272 (int (*)(...))QStringListModel::removeRows
+280 (int (*)(...))QAbstractItemModel::removeColumns
+288 (int (*)(...))QStringListModel::moveRows
+296 (int (*)(...))QAbstractItemModel::moveColumns
+304 (int (*)(...))QAbstractItemModel::fetchMore
+312 (int (*)(...))QAbstractItemModel::canFetchMore
+320 (int (*)(...))QStringListModel::flags
+328 (int (*)(...))QStringListModel::sort
+336 (int (*)(...))QAbstractItemModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QAbstractItemModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractItemModel::submit
+376 (int (*)(...))QAbstractItemModel::revert
+
+Class QStringListModel
+ size=24 align=8
+ base size=24 base align=8
+QStringListModel (0x0x7fb801d9d7b8) 0
+ vptr=((& QStringListModel::_ZTV16QStringListModel) + 16)
+ QAbstractListModel (0x0x7fb801d9d820) 0
+ primary-for QStringListModel (0x0x7fb801d9d7b8)
+ QAbstractItemModel (0x0x7fb801d9d888) 0
+ primary-for QAbstractListModel (0x0x7fb801d9d820)
+ QObject (0x0x7fb801dad480) 0
+ primary-for QAbstractItemModel (0x0x7fb801d9d888)
+
+Class QSystemSemaphore
+ size=8 align=8
+ base size=8 base align=8
+QSystemSemaphore (0x0x7fb801dad600) 0
+
+Class QTemporaryDir
+ size=8 align=8
+ base size=8 base align=8
+QTemporaryDir (0x0x7fb801dad6c0) 0
+
+Class QTemporaryFile::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTemporaryFile::QPrivateSignal (0x0x7fb801dad7e0) 0 empty
+
+Vtable for QTemporaryFile
+QTemporaryFile::_ZTV14QTemporaryFile: 34 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI14QTemporaryFile)
+16 (int (*)(...))QTemporaryFile::metaObject
+24 (int (*)(...))QTemporaryFile::qt_metacast
+32 (int (*)(...))QTemporaryFile::qt_metacall
+40 (int (*)(...))QTemporaryFile::~QTemporaryFile
+48 (int (*)(...))QTemporaryFile::~QTemporaryFile
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QFileDevice::isSequential
+120 (int (*)(...))QTemporaryFile::open
+128 (int (*)(...))QFileDevice::close
+136 (int (*)(...))QFileDevice::pos
+144 (int (*)(...))QFile::size
+152 (int (*)(...))QFileDevice::seek
+160 (int (*)(...))QFileDevice::atEnd
+168 (int (*)(...))QIODevice::reset
+176 (int (*)(...))QIODevice::bytesAvailable
+184 (int (*)(...))QIODevice::bytesToWrite
+192 (int (*)(...))QIODevice::canReadLine
+200 (int (*)(...))QIODevice::waitForReadyRead
+208 (int (*)(...))QIODevice::waitForBytesWritten
+216 (int (*)(...))QFileDevice::readData
+224 (int (*)(...))QFileDevice::readLineData
+232 (int (*)(...))QFileDevice::writeData
+240 (int (*)(...))QTemporaryFile::fileName
+248 (int (*)(...))QFile::resize
+256 (int (*)(...))QFile::permissions
+264 (int (*)(...))QFile::setPermissions
+
+Class QTemporaryFile
+ size=16 align=8
+ base size=16 base align=8
+QTemporaryFile (0x0x7fb801d9d8f0) 0
+ vptr=((& QTemporaryFile::_ZTV14QTemporaryFile) + 16)
+ QFile (0x0x7fb801d9d958) 0
+ primary-for QTemporaryFile (0x0x7fb801d9d8f0)
+ QFileDevice (0x0x7fb801d9d9c0) 0
+ primary-for QFile (0x0x7fb801d9d958)
+ QIODevice (0x0x7fb801d9da28) 0
+ primary-for QFileDevice (0x0x7fb801d9d9c0)
+ QObject (0x0x7fb801dad780) 0
+ primary-for QIODevice (0x0x7fb801d9da28)
+
+Class QTextBoundaryFinder
+ size=48 align=8
+ base size=48 base align=8
+QTextBoundaryFinder (0x0x7fb801dadb40) 0
+
+Class QTextCodec::ConverterState
+ size=32 align=8
+ base size=32 base align=8
+QTextCodec::ConverterState (0x0x7fb801e2c3c0) 0
+
+Vtable for QTextCodec
+QTextCodec::_ZTV10QTextCodec: 9 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI10QTextCodec)
+16 (int (*)(...))__cxa_pure_virtual
+24 (int (*)(...))QTextCodec::aliases
+32 (int (*)(...))__cxa_pure_virtual
+40 (int (*)(...))__cxa_pure_virtual
+48 (int (*)(...))__cxa_pure_virtual
+56 0
+64 0
+
+Class QTextCodec
+ size=8 align=8
+ base size=8 base align=8
+QTextCodec (0x0x7fb801e2c360) 0 nearly-empty
+ vptr=((& QTextCodec::_ZTV10QTextCodec) + 16)
+
+Class QTextEncoder
+ size=40 align=8
+ base size=40 base align=8
+QTextEncoder (0x0x7fb801e2cd80) 0
+
+Class QTextDecoder
+ size=40 align=8
+ base size=40 base align=8
+QTextDecoder (0x0x7fb801e2cf60) 0
+
+Vtable for std::thread::_State
+std::thread::_State::_ZTVNSt6thread6_StateE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt6thread6_StateE)
+16 0
+24 0
+32 (int (*)(...))__cxa_pure_virtual
+
+Class std::thread::_State
+ size=8 align=8
+ base size=8 base align=8
+std::thread::_State (0x0x7fb801e831e0) 0 nearly-empty
+ vptr=((& std::thread::_State::_ZTVNSt6thread6_StateE) + 16)
+
+Class std::thread::id
+ size=8 align=8
+ base size=8 base align=8
+std::thread::id (0x0x7fb801e83240) 0
+
+Class std::thread
+ size=8 align=8
+ base size=8 base align=8
+std::thread (0x0x7fb801e83180) 0
+
+Class std::condition_variable
+ size=48 align=8
+ base size=48 base align=8
+std::condition_variable (0x0x7fb801d16600) 0
+
+Class std::__at_thread_exit_elt
+ size=16 align=8
+ base size=16 base align=8
+std::__at_thread_exit_elt (0x0x7fb801d169c0) 0
+
+Class std::_V2::condition_variable_any
+ size=64 align=8
+ base size=64 base align=8
+std::_V2::condition_variable_any (0x0x7fb801d16a20) 0
+
+Class std::__atomic_futex_unsigned_base
+ size=1 align=1
+ base size=0 base align=1
+std::__atomic_futex_unsigned_base (0x0x7fb801aa6d20) 0 empty
+
+Vtable for std::future_error
+std::future_error::_ZTVSt12future_error: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTISt12future_error)
+16 (int (*)(...))std::future_error::~future_error
+24 (int (*)(...))std::future_error::~future_error
+32 (int (*)(...))std::future_error::what
+
+Class std::future_error
+ size=32 align=8
+ base size=32 base align=8
+std::future_error (0x0x7fb801aa5dd0) 0
+ vptr=((& std::future_error::_ZTVSt12future_error) + 16)
+ std::logic_error (0x0x7fb801aa5e38) 0
+ primary-for std::future_error (0x0x7fb801aa5dd0)
+ std::exception (0x0x7fb801ad0480) 0 nearly-empty
+ primary-for std::logic_error (0x0x7fb801aa5e38)
+
+Class std::__future_base::_Result_base::_Deleter
+ size=1 align=1
+ base size=0 base align=1
+std::__future_base::_Result_base::_Deleter (0x0x7fb801ad0ba0) 0 empty
+
+Vtable for std::__future_base::_Result_base
+std::__future_base::_Result_base::_ZTVNSt13__future_base12_Result_baseE: 5 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt13__future_base12_Result_baseE)
+16 (int (*)(...))__cxa_pure_virtual
+24 0
+32 0
+
+Class std::__future_base::_Result_base
+ size=16 align=8
+ base size=16 base align=8
+std::__future_base::_Result_base (0x0x7fb801ad0b40) 0
+ vptr=((& std::__future_base::_Result_base::_ZTVNSt13__future_base12_Result_baseE) + 16)
+
+Class std::__future_base::_State_baseV2::__exception_ptr_tag
+ size=1 align=1
+ base size=0 base align=1
+std::__future_base::_State_baseV2::__exception_ptr_tag (0x0x7fb8018d5300) 0 empty
+
+Class std::__future_base::_State_baseV2::_Make_ready
+ size=32 align=8
+ base size=32 base align=8
+std::__future_base::_State_baseV2::_Make_ready (0x0x7fb8018cd680) 0
+ std::__at_thread_exit_elt (0x0x7fb8018d53c0) 0
+
+Vtable for std::__future_base::_State_baseV2
+std::__future_base::_State_baseV2::_ZTVNSt13__future_base13_State_baseV2E: 6 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt13__future_base13_State_baseV2E)
+16 (int (*)(...))std::__future_base::_State_baseV2::~_State_baseV2
+24 (int (*)(...))std::__future_base::_State_baseV2::~_State_baseV2
+32 (int (*)(...))std::__future_base::_State_baseV2::_M_complete_async
+40 (int (*)(...))std::__future_base::_State_baseV2::_M_is_deferred_future
+
+Class std::__future_base::_State_baseV2
+ size=32 align=8
+ base size=28 base align=8
+std::__future_base::_State_baseV2 (0x0x7fb801ad0d20) 0
+ vptr=((& std::__future_base::_State_baseV2::_ZTVNSt13__future_base13_State_baseV2E) + 16)
+
+Class std::__future_base
+ size=1 align=1
+ base size=0 base align=1
+std::__future_base (0x0x7fb801ad0ae0) 0 empty
+
+Vtable for std::__future_base::_Async_state_commonV2
+std::__future_base::_Async_state_commonV2::_ZTVNSt13__future_base21_Async_state_commonV2E: 6 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTINSt13__future_base21_Async_state_commonV2E)
+16 (int (*)(...))std::__future_base::_Async_state_commonV2::~_Async_state_commonV2
+24 (int (*)(...))std::__future_base::_Async_state_commonV2::~_Async_state_commonV2
+32 (int (*)(...))std::__future_base::_Async_state_commonV2::_M_complete_async
+40 (int (*)(...))std::__future_base::_State_baseV2::_M_is_deferred_future
+
+Class std::__future_base::_Async_state_commonV2
+ size=48 align=8
+ base size=44 base align=8
+std::__future_base::_Async_state_commonV2 (0x0x7fb8010503a8) 0
+ vptr=((& std::__future_base::_Async_state_commonV2::_ZTVNSt13__future_base21_Async_state_commonV2E) + 16)
+ std::__future_base::_State_baseV2 (0x0x7fb8010873c0) 0
+ primary-for std::__future_base::_Async_state_commonV2 (0x0x7fb8010503a8)
+
+Class QThread::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QThread::QPrivateSignal (0x0x7fb801087c60) 0 empty
+
+Vtable for QThread
+QThread::_ZTV7QThread: 15 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI7QThread)
+16 (int (*)(...))QThread::metaObject
+24 (int (*)(...))QThread::qt_metacast
+32 (int (*)(...))QThread::qt_metacall
+40 (int (*)(...))QThread::~QThread
+48 (int (*)(...))QThread::~QThread
+56 (int (*)(...))QThread::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QThread::run
+
+Class QThread
+ size=16 align=8
+ base size=16 base align=8
+QThread (0x0x7fb8010506e8) 0
+ vptr=((& QThread::_ZTV7QThread) + 16)
+ QObject (0x0x7fb801087c00) 0
+ primary-for QThread (0x0x7fb8010506e8)
+
+Class QThreadPool::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QThreadPool::QPrivateSignal (0x0x7fb8010c4060) 0 empty
+
+Vtable for QThreadPool
+QThreadPool::_ZTV11QThreadPool: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QThreadPool)
+16 (int (*)(...))QThreadPool::metaObject
+24 (int (*)(...))QThreadPool::qt_metacast
+32 (int (*)(...))QThreadPool::qt_metacall
+40 (int (*)(...))QThreadPool::~QThreadPool
+48 (int (*)(...))QThreadPool::~QThreadPool
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QThreadPool
+ size=16 align=8
+ base size=16 base align=8
+QThreadPool (0x0x7fb801050750) 0
+ vptr=((& QThreadPool::_ZTV11QThreadPool) + 16)
+ QObject (0x0x7fb8010c4000) 0
+ primary-for QThreadPool (0x0x7fb801050750)
+
+Class QThreadStorageData
+ size=4 align=4
+ base size=4 base align=4
+QThreadStorageData (0x0x7fb8010c4240) 0
+
+Class QTimeLine::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTimeLine::QPrivateSignal (0x0x7fb8010c4900) 0 empty
+
+Vtable for QTimeLine
+QTimeLine::_ZTV9QTimeLine: 15 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI9QTimeLine)
+16 (int (*)(...))QTimeLine::metaObject
+24 (int (*)(...))QTimeLine::qt_metacast
+32 (int (*)(...))QTimeLine::qt_metacall
+40 (int (*)(...))QTimeLine::~QTimeLine
+48 (int (*)(...))QTimeLine::~QTimeLine
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QTimeLine::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTimeLine::valueForTime
+
+Class QTimeLine
+ size=16 align=8
+ base size=16 base align=8
+QTimeLine (0x0x7fb8010507b8) 0
+ vptr=((& QTimeLine::_ZTV9QTimeLine) + 16)
+ QObject (0x0x7fb8010c48a0) 0
+ primary-for QTimeLine (0x0x7fb8010507b8)
+
+Class QTimer::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTimer::QPrivateSignal (0x0x7fb8010c4b40) 0 empty
+
+Vtable for QTimer
+QTimer::_ZTV6QTimer: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI6QTimer)
+16 (int (*)(...))QTimer::metaObject
+24 (int (*)(...))QTimer::qt_metacast
+32 (int (*)(...))QTimer::qt_metacall
+40 (int (*)(...))QTimer::~QTimer
+48 (int (*)(...))QTimer::~QTimer
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QTimer::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QTimer
+ size=32 align=8
+ base size=29 base align=8
+QTimer (0x0x7fb801050820) 0
+ vptr=((& QTimer::_ZTV6QTimer) + 16)
+ QObject (0x0x7fb8010c4ae0) 0
+ primary-for QTimer (0x0x7fb801050820)
+
+Class QTimeZone::OffsetData
+ size=32 align=8
+ base size=28 base align=8
+QTimeZone::OffsetData (0x0x7fb80113e4e0) 0
+
+Class QTimeZone
+ size=8 align=8
+ base size=8 base align=8
+QTimeZone (0x0x7fb80113e480) 0
+
+Class QTranslator::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTranslator::QPrivateSignal (0x0x7fb800ddd5a0) 0 empty
+
+Vtable for QTranslator
+QTranslator::_ZTV11QTranslator: 16 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI11QTranslator)
+16 (int (*)(...))QTranslator::metaObject
+24 (int (*)(...))QTranslator::qt_metacast
+32 (int (*)(...))QTranslator::qt_metacall
+40 (int (*)(...))QTranslator::~QTranslator
+48 (int (*)(...))QTranslator::~QTranslator
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTranslator::translate
+120 (int (*)(...))QTranslator::isEmpty
+
+Class QTranslator
+ size=16 align=8
+ base size=16 base align=8
+QTranslator (0x0x7fb800dcdf08) 0
+ vptr=((& QTranslator::_ZTV11QTranslator) + 16)
+ QObject (0x0x7fb800ddd540) 0
+ primary-for QTranslator (0x0x7fb800dcdf08)
+
+Class QTransposeProxyModel::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QTransposeProxyModel::QPrivateSignal (0x0x7fb800ddd7e0) 0 empty
+
+Vtable for QTransposeProxyModel
+QTransposeProxyModel::_ZTV20QTransposeProxyModel: 53 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI20QTransposeProxyModel)
+16 (int (*)(...))QTransposeProxyModel::metaObject
+24 (int (*)(...))QTransposeProxyModel::qt_metacast
+32 (int (*)(...))QTransposeProxyModel::qt_metacall
+40 (int (*)(...))QTransposeProxyModel::~QTransposeProxyModel
+48 (int (*)(...))QTransposeProxyModel::~QTransposeProxyModel
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))QTransposeProxyModel::index
+120 (int (*)(...))QTransposeProxyModel::parent
+128 (int (*)(...))QAbstractProxyModel::sibling
+136 (int (*)(...))QTransposeProxyModel::rowCount
+144 (int (*)(...))QTransposeProxyModel::columnCount
+152 (int (*)(...))QAbstractProxyModel::hasChildren
+160 (int (*)(...))QAbstractProxyModel::data
+168 (int (*)(...))QAbstractProxyModel::setData
+176 (int (*)(...))QTransposeProxyModel::headerData
+184 (int (*)(...))QTransposeProxyModel::setHeaderData
+192 (int (*)(...))QTransposeProxyModel::itemData
+200 (int (*)(...))QTransposeProxyModel::setItemData
+208 (int (*)(...))QAbstractProxyModel::mimeTypes
+216 (int (*)(...))QAbstractProxyModel::mimeData
+224 (int (*)(...))QAbstractProxyModel::canDropMimeData
+232 (int (*)(...))QAbstractProxyModel::dropMimeData
+240 (int (*)(...))QAbstractProxyModel::supportedDropActions
+248 (int (*)(...))QAbstractProxyModel::supportedDragActions
+256 (int (*)(...))QTransposeProxyModel::insertRows
+264 (int (*)(...))QTransposeProxyModel::insertColumns
+272 (int (*)(...))QTransposeProxyModel::removeRows
+280 (int (*)(...))QTransposeProxyModel::removeColumns
+288 (int (*)(...))QTransposeProxyModel::moveRows
+296 (int (*)(...))QTransposeProxyModel::moveColumns
+304 (int (*)(...))QAbstractProxyModel::fetchMore
+312 (int (*)(...))QAbstractProxyModel::canFetchMore
+320 (int (*)(...))QAbstractProxyModel::flags
+328 (int (*)(...))QTransposeProxyModel::sort
+336 (int (*)(...))QAbstractProxyModel::buddy
+344 (int (*)(...))QAbstractItemModel::match
+352 (int (*)(...))QTransposeProxyModel::span
+360 (int (*)(...))QAbstractItemModel::roleNames
+368 (int (*)(...))QAbstractProxyModel::submit
+376 (int (*)(...))QAbstractProxyModel::revert
+384 (int (*)(...))QTransposeProxyModel::setSourceModel
+392 (int (*)(...))QTransposeProxyModel::mapToSource
+400 (int (*)(...))QTransposeProxyModel::mapFromSource
+408 (int (*)(...))QAbstractProxyModel::mapSelectionToSource
+416 (int (*)(...))QAbstractProxyModel::mapSelectionFromSource
+
+Class QTransposeProxyModel
+ size=16 align=8
+ base size=16 base align=8
+QTransposeProxyModel (0x0x7fb800dcdf70) 0
+ vptr=((& QTransposeProxyModel::_ZTV20QTransposeProxyModel) + 16)
+ QAbstractProxyModel (0x0x7fb800df6000) 0
+ primary-for QTransposeProxyModel (0x0x7fb800dcdf70)
+ QAbstractItemModel (0x0x7fb800df6068) 0
+ primary-for QAbstractProxyModel (0x0x7fb800df6000)
+ QObject (0x0x7fb800ddd780) 0
+ primary-for QAbstractItemModel (0x0x7fb800df6068)
+
+Class QUrlQuery
+ size=8 align=8
+ base size=8 base align=8
+QUrlQuery (0x0x7fb800ddd9c0) 0
+
+Class QWaitCondition
+ size=8 align=8
+ base size=8 base align=8
+QWaitCondition (0x0x7fb800edaea0) 0
+
+Class QXmlStreamStringRef
+ size=16 align=8
+ base size=16 base align=8
+QXmlStreamStringRef (0x0x7fb800ef9000) 0
+
+Class QXmlStreamAttribute
+ size=80 align=8
+ base size=73 base align=8
+QXmlStreamAttribute (0x0x7fb800f863c0) 0
+
+Class QXmlStreamAttributes
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamAttributes (0x0x7fb800af2340) 0
+ QVector<QXmlStreamAttribute> (0x0x7fb800ae7ae0) 0
+
+Class QXmlStreamNamespaceDeclaration
+ size=40 align=8
+ base size=40 base align=8
+QXmlStreamNamespaceDeclaration (0x0x7fb800ae7de0) 0
+
+Class QXmlStreamNotationDeclaration
+ size=56 align=8
+ base size=56 base align=8
+QXmlStreamNotationDeclaration (0x0x7fb800b6cd80) 0
+
+Class QXmlStreamEntityDeclaration
+ size=88 align=8
+ base size=88 base align=8
+QXmlStreamEntityDeclaration (0x0x7fb800bc7d80) 0
+
+Vtable for QXmlStreamEntityResolver
+QXmlStreamEntityResolver::_ZTV24QXmlStreamEntityResolver: 6 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI24QXmlStreamEntityResolver)
+16 (int (*)(...))QXmlStreamEntityResolver::~QXmlStreamEntityResolver
+24 (int (*)(...))QXmlStreamEntityResolver::~QXmlStreamEntityResolver
+32 (int (*)(...))QXmlStreamEntityResolver::resolveEntity
+40 (int (*)(...))QXmlStreamEntityResolver::resolveUndeclaredEntity
+
+Class QXmlStreamEntityResolver
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamEntityResolver (0x0x7fb800c34e40) 0 nearly-empty
+ vptr=((& QXmlStreamEntityResolver::_ZTV24QXmlStreamEntityResolver) + 16)
+
+Class QXmlStreamReader
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamReader (0x0x7fb800c34ea0) 0
+
+Class QXmlStreamWriter
+ size=8 align=8
+ base size=8 base align=8
+QXmlStreamWriter (0x0x7fb800c72d80) 0
+
+Class QNdefRecord
+ size=8 align=8
+ base size=8 base align=8
+QNdefRecord (0x0x7fb800c72f60) 0
+
+Class QNdefFilter::Record
+ size=24 align=8
+ base size=24 base align=8
+QNdefFilter::Record (0x0x7fb8008cd180) 0
+
+Class QNdefFilter
+ size=8 align=8
+ base size=8 base align=8
+QNdefFilter (0x0x7fb8008cd120) 0
+
+Class QNdefMessage
+ size=8 align=8
+ base size=8 base align=8
+QNdefMessage (0x0x7fb8008ec068) 0
+ QList<QNdefRecord> (0x0x7fb8008ec0d0) 0
+ QListSpecialMethods<QNdefRecord> (0x0x7fb8008cd3c0) 0 empty
+
+Class QNdefNfcTextRecord
+ size=8 align=8
+ base size=8 base align=8
+QNdefNfcTextRecord (0x0x7fb8008ec138) 0
+ QNdefRecord (0x0x7fb8008cdc60) 0
+
+Class QNdefNfcUriRecord
+ size=8 align=8
+ base size=8 base align=8
+QNdefNfcUriRecord (0x0x7fb8008ec680) 0
+ QNdefRecord (0x0x7fb80093c4e0) 0
+
+Class QNdefNfcIconRecord
+ size=8 align=8
+ base size=8 base align=8
+QNdefNfcIconRecord (0x0x7fb8008ec6e8) 0
+ QNdefRecord (0x0x7fb80093c8a0) 0
+
+Class QNdefNfcSmartPosterRecord
+ size=16 align=8
+ base size=16 base align=8
+QNdefNfcSmartPosterRecord (0x0x7fb8008ec750) 0
+ QNdefRecord (0x0x7fb80093cc00) 0
+
+Class QNearFieldTarget::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNearFieldTarget::QPrivateSignal (0x0x7fb80093cde0) 0 empty
+
+Class QNearFieldTarget::RequestId
+ size=8 align=8
+ base size=8 base align=8
+QNearFieldTarget::RequestId (0x0x7fb80093ce40) 0
+
+Vtable for QNearFieldTarget
+QNearFieldTarget::_ZTV16QNearFieldTarget: 25 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI16QNearFieldTarget)
+16 (int (*)(...))QNearFieldTarget::metaObject
+24 (int (*)(...))QNearFieldTarget::qt_metacast
+32 (int (*)(...))QNearFieldTarget::qt_metacall
+40 0
+48 0
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+112 (int (*)(...))__cxa_pure_virtual
+120 (int (*)(...))QNearFieldTarget::url
+128 (int (*)(...))__cxa_pure_virtual
+136 (int (*)(...))__cxa_pure_virtual
+144 (int (*)(...))QNearFieldTarget::hasNdefMessage
+152 (int (*)(...))QNearFieldTarget::readNdefMessages
+160 (int (*)(...))QNearFieldTarget::writeNdefMessages
+168 (int (*)(...))QNearFieldTarget::sendCommand
+176 (int (*)(...))QNearFieldTarget::sendCommands
+184 (int (*)(...))QNearFieldTarget::waitForRequestCompleted
+192 (int (*)(...))QNearFieldTarget::handleResponse
+
+Class QNearFieldTarget
+ size=24 align=8
+ base size=24 base align=8
+QNearFieldTarget (0x0x7fb8008ec7b8) 0
+ vptr=((& QNearFieldTarget::_ZTV16QNearFieldTarget) + 16)
+ QObject (0x0x7fb80093cd80) 0
+ primary-for QNearFieldTarget (0x0x7fb8008ec7b8)
+
+Class QNearFieldManager::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNearFieldManager::QPrivateSignal (0x0x7fb8009c6c00) 0 empty
+
+Vtable for QNearFieldManager
+QNearFieldManager::_ZTV17QNearFieldManager: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI17QNearFieldManager)
+16 (int (*)(...))QNearFieldManager::metaObject
+24 (int (*)(...))QNearFieldManager::qt_metacast
+32 (int (*)(...))QNearFieldManager::qt_metacall
+40 (int (*)(...))QNearFieldManager::~QNearFieldManager
+48 (int (*)(...))QNearFieldManager::~QNearFieldManager
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QNearFieldManager
+ size=24 align=8
+ base size=24 base align=8
+QNearFieldManager (0x0x7fb8008ec8f0) 0
+ vptr=((& QNearFieldManager::_ZTV17QNearFieldManager) + 16)
+ QObject (0x0x7fb8009c6ba0) 0
+ primary-for QNearFieldManager (0x0x7fb8008ec8f0)
+
+Class QNearFieldShareManager::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNearFieldShareManager::QPrivateSignal (0x0x7fb800a0f6c0) 0 empty
+
+Vtable for QNearFieldShareManager
+QNearFieldShareManager::_ZTV22QNearFieldShareManager: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI22QNearFieldShareManager)
+16 (int (*)(...))QNearFieldShareManager::metaObject
+24 (int (*)(...))QNearFieldShareManager::qt_metacast
+32 (int (*)(...))QNearFieldShareManager::qt_metacall
+40 (int (*)(...))QNearFieldShareManager::~QNearFieldShareManager
+48 (int (*)(...))QNearFieldShareManager::~QNearFieldShareManager
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QNearFieldShareManager
+ size=24 align=8
+ base size=24 base align=8
+QNearFieldShareManager (0x0x7fb8008eca28) 0
+ vptr=((& QNearFieldShareManager::_ZTV22QNearFieldShareManager) + 16)
+ QObject (0x0x7fb800a0f660) 0
+ primary-for QNearFieldShareManager (0x0x7fb8008eca28)
+
+Class QNearFieldShareTarget::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QNearFieldShareTarget::QPrivateSignal (0x0x7fb800a75240) 0 empty
+
+Vtable for QNearFieldShareTarget
+QNearFieldShareTarget::_ZTV21QNearFieldShareTarget: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI21QNearFieldShareTarget)
+16 (int (*)(...))QNearFieldShareTarget::metaObject
+24 (int (*)(...))QNearFieldShareTarget::qt_metacast
+32 (int (*)(...))QNearFieldShareTarget::qt_metacall
+40 (int (*)(...))QNearFieldShareTarget::~QNearFieldShareTarget
+48 (int (*)(...))QNearFieldShareTarget::~QNearFieldShareTarget
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QNearFieldShareTarget
+ size=24 align=8
+ base size=24 base align=8
+QNearFieldShareTarget (0x0x7fb8008ecb60) 0
+ vptr=((& QNearFieldShareTarget::_ZTV21QNearFieldShareTarget) + 16)
+ QObject (0x0x7fb800a751e0) 0
+ primary-for QNearFieldShareTarget (0x0x7fb8008ecb60)
+
+Class QQmlNdefRecord::QPrivateSignal
+ size=1 align=1
+ base size=0 base align=1
+QQmlNdefRecord::QPrivateSignal (0x0x7fb800a75480) 0 empty
+
+Vtable for QQmlNdefRecord
+QQmlNdefRecord::_ZTV14QQmlNdefRecord: 14 entries
+0 (int (*)(...))0
+8 (int (*)(...))(& _ZTI14QQmlNdefRecord)
+16 (int (*)(...))QQmlNdefRecord::metaObject
+24 (int (*)(...))QQmlNdefRecord::qt_metacast
+32 (int (*)(...))QQmlNdefRecord::qt_metacall
+40 (int (*)(...))QQmlNdefRecord::~QQmlNdefRecord
+48 (int (*)(...))QQmlNdefRecord::~QQmlNdefRecord
+56 (int (*)(...))QObject::event
+64 (int (*)(...))QObject::eventFilter
+72 (int (*)(...))QObject::timerEvent
+80 (int (*)(...))QObject::childEvent
+88 (int (*)(...))QObject::customEvent
+96 (int (*)(...))QObject::connectNotify
+104 (int (*)(...))QObject::disconnectNotify
+
+Class QQmlNdefRecord
+ size=24 align=8
+ base size=24 base align=8
+QQmlNdefRecord (0x0x7fb8008ecbc8) 0
+ vptr=((& QQmlNdefRecord::_ZTV14QQmlNdefRecord) + 16)
+ QObject (0x0x7fb800a75420) 0
+ primary-for QQmlNdefRecord (0x0x7fb8008ecbc8)
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb8006c3a20) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb8006c3d80) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb8006c3f60) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb8006ee300) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb8006ee4e0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb8006ee840) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb8006eea20) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb8006eed80) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb8006eef60) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = char; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb800729300) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb8007294e0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb800729840) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb800729a20) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb800729d80) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb800729f60) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = char; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb800760300) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb80078a7e0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb80078ab40) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb80078acc0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long int; _Ret = long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb8007b8060) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb8007b81e0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long unsigned int; _Ret = long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb8007b8540) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb8007b86c0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long int; _Ret = long long int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb8007b8a20) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb8007b8ba0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long long unsigned int; _Ret = long long unsigned int; _CharT = wchar_t; _Base = {int}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb8007b8f00) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb8007ec0c0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = float; _Ret = float; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb8007ec420) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb8007ec5a0) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = double; _Ret = double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb8007ec900) 0 empty
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno
+ size=4 align=4
+ base size=4 base align=4
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Save_errno (0x0x7fb8007eca80) 0
+
+Class __gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk
+ size=1 align=1
+ base size=0 base align=1
+__gnu_cxx::__stoa(_TRet (*)(const _CharT*, _CharT**, _Base ...), const char*, const _CharT*, std::size_t*, _Base ...) [with _TRet = long double; _Ret = long double; _CharT = wchar_t; _Base = {}; std::size_t = long unsigned int]::_Range_chk (0x0x7fb8007ecde0) 0 empty
+
diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt
index 34bbf980..edb51051 100644
--- a/tests/auto/cmake/CMakeLists.txt
+++ b/tests/auto/cmake/CMakeLists.txt
@@ -1,19 +1,48 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-cmake_minimum_required(VERSION 2.8)
-
-project(qmake_cmake_files)
+# This is an automatic test for the CMake configuration files.
+# To run it manually,
+# 1) mkdir build # Create a build directory
+# 2) cd build
+# 3) # Run cmake on this directory
+# `$qt_prefix/bin/qt-cmake ..` or `cmake -DCMAKE_PREFIX_PATH=/path/to/qt ..`
+# 4) ctest # Run ctest
+cmake_minimum_required(VERSION 3.16)
+project(connectivity_cmake_tests)
enable_testing()
-find_package(Qt5Core REQUIRED)
+set(required_packages Core Bluetooth Nfc)
+
+# Setup the test when called as a completely standalone project.
+if(TARGET Qt6::Core)
+ # Tests are built as part of the repository's build tree.
+ # Setup paths so that the Qt packages are found.
+ qt_internal_set_up_build_dir_package_paths()
+endif()
+
+find_package(Qt6 REQUIRED COMPONENTS ${required_packages})
+
+# Setup common test variables which were previously set by ctest_testcase_common.prf.
+set(CMAKE_MODULES_UNDER_TEST "${required_packages}")
+
+foreach(qt_package ${CMAKE_MODULES_UNDER_TEST})
+ set(package_name "${QT_CMAKE_EXPORT_NAMESPACE}${qt_package}")
+ if(${package_name}_FOUND)
+ set(CMAKE_${qt_package}_MODULE_MAJOR_VERSION "${${package_name}_VERSION_MAJOR}")
+ set(CMAKE_${qt_package}_MODULE_MINOR_VERSION "${${package_name}_VERSION_MINOR}")
+ set(CMAKE_${qt_package}_MODULE_PATCH_VERSION "${${package_name}_VERSION_PATCH}")
+ endif()
+endforeach()
-include("${_Qt5CTestMacros}")
+include("${_Qt6CTestMacros}")
-set(qt_module_includes
+set(module_includes
Bluetooth QBluetoothAddress
Nfc QNdefRecord
)
-test_module_includes(
- ${qt_module_includes}
+_qt_internal_test_module_includes(
+ ${module_includes}
)
diff --git a/tests/auto/cmake/cmake.pro b/tests/auto/cmake/cmake.pro
deleted file mode 100644
index 7bd2c29e..00000000
--- a/tests/auto/cmake/cmake.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-
-# Cause make to do nothing.
-TEMPLATE = subdirs
-
-CMAKE_QT_MODULES_UNDER_TEST = bluetooth nfc
-
-CONFIG += ctest_testcase
diff --git a/tests/auto/nfccommons/qnearfieldmanager_emulator.cpp b/tests/auto/nfccommons/qnearfieldmanager_emulator.cpp
new file mode 100644
index 00000000..20e1f1f9
--- /dev/null
+++ b/tests/auto/nfccommons/qnearfieldmanager_emulator.cpp
@@ -0,0 +1,90 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qnearfieldmanager_emulator_p.h"
+#include "qnearfieldtarget_emulator_p.h"
+
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl()
+{
+ TagActivator *activator = TagActivator::instance();
+ activator->initialize();
+
+ connect(activator, &TagActivator::tagActivated, this, &QNearFieldManagerPrivateImpl::tagActivated);
+ connect(activator, &TagActivator::tagDeactivated, this, &QNearFieldManagerPrivateImpl::tagDeactivated);
+}
+
+QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
+{
+}
+
+bool QNearFieldManagerPrivateImpl::isEnabled() const
+{
+ return true;
+}
+
+bool QNearFieldManagerPrivateImpl::isSupported(QNearFieldTarget::AccessMethod accessMethod) const
+{
+ return accessMethod == QNearFieldTarget::NdefAccess
+ || accessMethod == QNearFieldTarget::AnyAccess;
+}
+
+bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::AccessMethod accessMethod)
+{
+ const bool supported = isSupported(accessMethod);
+ if (supported)
+ TagActivator::instance()->start();
+
+ return supported;
+}
+
+void QNearFieldManagerPrivateImpl::stopTargetDetection(const QString &message)
+{
+ setUserInformation(message);
+ TagActivator::instance()->stop();
+ emit targetDetectionStopped();
+}
+
+void QNearFieldManagerPrivateImpl::setUserInformation(const QString &message)
+{
+ emit userInformationChanged(message);
+}
+
+void QNearFieldManagerPrivateImpl::reset()
+{
+ TagActivator::instance()->reset();
+}
+
+void QNearFieldManagerPrivateImpl::tagActivated(TagBase *tag)
+{
+ QNearFieldTargetPrivate *target = targets.value(tag).data();
+ if (!target) {
+ if (dynamic_cast<NfcTagType1 *>(tag))
+ target = new TagType1(tag, this);
+ else if (dynamic_cast<NfcTagType2 *>(tag))
+ target = new TagType2(tag, this);
+ else
+ qFatal("Unknown emulator tag type");
+
+ targets.insert(tag, target);
+ }
+
+ Q_EMIT targetDetected(new QNearFieldTarget(target, this));
+}
+
+void QNearFieldManagerPrivateImpl::tagDeactivated(TagBase *tag)
+{
+ QNearFieldTargetPrivate *target = targets.value(tag).data();
+ if (!target) {
+ targets.remove(tag);
+ return;
+ }
+
+ Q_EMIT targetLost(target->q_ptr);
+ QMetaObject::invokeMethod(target->q_ptr, &QNearFieldTarget::disconnected);
+}
+
+QT_END_NAMESPACE
diff --git a/tests/auto/nfccommons/qnearfieldmanager_emulator_p.h b/tests/auto/nfccommons/qnearfieldmanager_emulator_p.h
new file mode 100644
index 00000000..b7316944
--- /dev/null
+++ b/tests/auto/nfccommons/qnearfieldmanager_emulator_p.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QNEARFIELDMANAGER_EMULATOR_H
+#define QNEARFIELDMANAGER_EMULATOR_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 <QtNfc/private/qnearfieldmanager_p.h>
+#include <QtNfc/private/qnearfieldtarget_p.h>
+#include <QtNfc/qndeffilter.h>
+
+#include <QtCore/QMetaMethod>
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class TagBase;
+class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivate
+{
+ Q_OBJECT
+
+public:
+ QNearFieldManagerPrivateImpl();
+ ~QNearFieldManagerPrivateImpl() override;
+
+ bool isEnabled() const override;
+
+ bool isSupported(QNearFieldTarget::AccessMethod accessMethod) const override;
+
+ bool startTargetDetection(QNearFieldTarget::AccessMethod accessMethod) override;
+ void stopTargetDetection(const QString &message) override;
+ void setUserInformation(const QString &message) override;
+
+ void reset();
+
+signals:
+ void userInformationChanged(const QString &message);
+
+private slots:
+ void tagActivated(TagBase *tag);
+ void tagDeactivated(TagBase *tag);
+
+private:
+ QMap<TagBase *, QPointer<QNearFieldTargetPrivate> > targets;
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QNEARFIELDMANAGER_EMULATOR_H
diff --git a/src/nfc/qnearfieldtagtype1.cpp b/tests/auto/nfccommons/qnearfieldtagtype1.cpp
index b3479203..cad1c1e7 100644
--- a/src/nfc/qnearfieldtagtype1.cpp
+++ b/tests/auto/nfccommons/qnearfieldtagtype1.cpp
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 GPL-3.0-only
#include "qnearfieldtagtype1_p.h"
-#include "qnearfieldtarget_p.h"
-#include "qndefmessage.h"
#include "qtlv_p.h"
+#include <QtNfc/private/qnearfieldtarget_p.h>
+#include <QtNfc/qndefmessage.h>
+
#include <QtCore/QByteArray>
#include <QtCore/QVariant>
@@ -81,9 +46,9 @@ class QNearFieldTagType1Private
public:
QNearFieldTagType1Private(QNearFieldTagType1 *q)
: q_ptr(q), m_readNdefMessageState(NotReadingNdefMessage),
- m_tlvReader(0),
+ m_tlvReader(nullptr),
m_writeNdefMessageState(NotWritingNdefMessage),
- m_tlvWriter(0)
+ m_tlvWriter(nullptr)
{ }
QNearFieldTagType1 *q_ptr;
@@ -139,7 +104,7 @@ void QNearFieldTagType1Private::progressToNextNdefReadMessageState()
if (data.isEmpty()) {
m_readNdefMessageState = NotReadingNdefMessage;
m_nextExpectedRequestId = QNearFieldTarget::RequestId();
- emit q->error(QNearFieldTarget::NdefReadError, m_readNdefRequestId);
+ Q_EMIT q->error(QNearFieldTarget::NdefReadError, m_readNdefRequestId);
m_readNdefRequestId = QNearFieldTarget::RequestId();
break;
}
@@ -150,7 +115,7 @@ void QNearFieldTagType1Private::progressToNextNdefReadMessageState()
if (!(hr0 & 0x10)) {
m_readNdefMessageState = NotReadingNdefMessage;
m_nextExpectedRequestId = QNearFieldTarget::RequestId();
- emit q->error(QNearFieldTarget::NdefReadError, m_readNdefRequestId);
+ Q_EMIT q->error(QNearFieldTarget::NdefReadError, m_readNdefRequestId);
m_readNdefRequestId = QNearFieldTarget::RequestId();
break;
}
@@ -165,7 +130,7 @@ void QNearFieldTagType1Private::progressToNextNdefReadMessageState()
if (ndefMagicNumber != 0xe1) {
m_readNdefMessageState = NotReadingNdefMessage;
- emit q->error(QNearFieldTarget::NdefReadError, m_readNdefRequestId);
+ Q_EMIT q->error(QNearFieldTarget::NdefReadError, m_readNdefRequestId);
m_readNdefRequestId = QNearFieldTarget::RequestId();
break;
}
@@ -186,16 +151,16 @@ void QNearFieldTagType1Private::progressToNextNdefReadMessageState()
if (m_tlvReader->tag() == 0x03) {
Q_Q(QNearFieldTagType1);
- emit q->ndefMessageRead(QNdefMessage::fromByteArray(m_tlvReader->data()));
+ Q_EMIT q->ndefMessageRead(QNdefMessage::fromByteArray(m_tlvReader->data()));
}
}
m_nextExpectedRequestId = m_tlvReader->requestId();
if (!m_nextExpectedRequestId.isValid()) {
delete m_tlvReader;
- m_tlvReader = 0;
+ m_tlvReader = nullptr;
m_readNdefMessageState = NotReadingNdefMessage;
- emit q->requestCompleted(m_readNdefRequestId);
+ Q_EMIT q->requestCompleted(m_readNdefRequestId);
m_readNdefRequestId = QNearFieldTarget::RequestId();
}
break;
@@ -217,7 +182,7 @@ void QNearFieldTagType1Private::progressToNextNdefWriteMessageState()
if (data.isEmpty()) {
m_writeNdefMessageState = NotWritingNdefMessage;
m_nextExpectedRequestId = QNearFieldTarget::RequestId();
- emit q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId);
+ Q_EMIT q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId);
m_writeNdefRequestId = QNearFieldTarget::RequestId();
break;
}
@@ -228,7 +193,7 @@ void QNearFieldTagType1Private::progressToNextNdefWriteMessageState()
if (!(hr0 & 0x10)) {
m_writeNdefMessageState = NotWritingNdefMessage;
m_nextExpectedRequestId = QNearFieldTarget::RequestId();
- emit q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId);
+ Q_EMIT q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId);
m_writeNdefRequestId = QNearFieldTarget::RequestId();
break;
}
@@ -243,7 +208,7 @@ void QNearFieldTagType1Private::progressToNextNdefWriteMessageState()
if (ndefMagicNumber != 0xe1) {
m_writeNdefMessageState = NotWritingNdefMessage;
- emit q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId);
+ Q_EMIT q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId);
m_writeNdefRequestId = QNearFieldTarget::RequestId();
break;
}
@@ -270,7 +235,7 @@ void QNearFieldTagType1Private::progressToNextNdefWriteMessageState()
break;
delete m_tlvReader;
- m_tlvReader = 0;
+ m_tlvReader = nullptr;
m_writeNdefMessageState = NdefWriteWritingTlv;
// fall through
@@ -279,11 +244,11 @@ void QNearFieldTagType1Private::progressToNextNdefWriteMessageState()
m_tlvWriter = new QTlvWriter(q);
// write old TLVs
- for (const Tlv &tlv : qAsConst(m_tlvs))
+ for (const Tlv &tlv : std::as_const(m_tlvs))
m_tlvWriter->writeTlv(tlv.first, tlv.second);
// write new NDEF message TLVs
- for (const QNdefMessage &message : qAsConst(m_ndefWriteMessages))
+ for (const QNdefMessage &message : std::as_const(m_ndefWriteMessages))
m_tlvWriter->writeTlv(0x03, message.toByteArray());
// write terminator TLV
@@ -299,17 +264,16 @@ void QNearFieldTagType1Private::progressToNextNdefWriteMessageState()
m_nextExpectedRequestId = QNearFieldTarget::RequestId();
m_writeNdefMessageState = NotWritingNdefMessage;
delete m_tlvWriter;
- m_tlvWriter = 0;
- emit q->ndefMessagesWritten();
- emit q->requestCompleted(m_writeNdefRequestId);
+ m_tlvWriter = nullptr;
+ Q_EMIT q->requestCompleted(m_writeNdefRequestId);
m_writeNdefRequestId = QNearFieldTarget::RequestId();
} else {
m_nextExpectedRequestId = m_tlvWriter->requestId();
if (!m_nextExpectedRequestId.isValid()) {
m_writeNdefMessageState = NotWritingNdefMessage;
delete m_tlvWriter;
- m_tlvWriter = 0;
- emit q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId);
+ m_tlvWriter = nullptr;
+ Q_EMIT q->error(QNearFieldTarget::NdefWriteError, m_writeNdefRequestId);
m_writeNdefRequestId = QNearFieldTarget::RequestId();
}
}
@@ -371,7 +335,7 @@ static QVariant decodeResponse(const QByteArray &command, const QByteArray &resp
if (writeBlockAddress != blockAddress)
return false;
- for (int i = 0; i < writeData.length(); ++i) {
+ for (int i = 0; i < writeData.size(); ++i) {
if ((writeData.at(i) & data.at(i)) != data.at(i))
return false;
}
@@ -387,7 +351,7 @@ static QVariant decodeResponse(const QByteArray &command, const QByteArray &resp
Constructs a new tag type 1 near field target with \a parent.
*/
QNearFieldTagType1::QNearFieldTagType1(QObject *parent)
-: QNearFieldTarget(parent), d_ptr(new QNearFieldTagType1Private(this))
+: QNearFieldTargetPrivate(parent), d_ptr(new QNearFieldTagType1Private(this))
{
}
@@ -404,7 +368,7 @@ QNearFieldTagType1::~QNearFieldTagType1()
*/
bool QNearFieldTagType1::hasNdefMessage()
{
- RequestId id = readAll();
+ QNearFieldTarget::RequestId id = readAll();
if (!waitForRequestCompleted(id))
return false;
@@ -435,7 +399,7 @@ QNearFieldTarget::RequestId QNearFieldTagType1::readNdefMessages()
{
Q_D(QNearFieldTagType1);
- d->m_readNdefRequestId = RequestId(new RequestIdPrivate);
+ d->m_readNdefRequestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate);
if (d->m_readNdefMessageState == QNearFieldTagType1Private::NotReadingNdefMessage) {
d->progressToNextNdefReadMessageState();
@@ -453,7 +417,7 @@ QNearFieldTarget::RequestId QNearFieldTagType1::writeNdefMessages(const QList<QN
{
Q_D(QNearFieldTagType1);
- d->m_writeNdefRequestId = RequestId(new RequestIdPrivate);
+ d->m_writeNdefRequestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate);
if (d->m_readNdefMessageState == QNearFieldTagType1Private::NotReadingNdefMessage &&
d->m_writeNdefMessageState == QNearFieldTagType1Private::NotWritingNdefMessage) {
@@ -471,7 +435,7 @@ QNearFieldTarget::RequestId QNearFieldTagType1::writeNdefMessages(const QList<QN
*/
quint8 QNearFieldTagType1::version()
{
- RequestId id = readByte(9);
+ QNearFieldTarget::RequestId id = readByte(9);
if (!waitForRequestCompleted(id))
return 0;
@@ -484,7 +448,7 @@ quint8 QNearFieldTagType1::version()
*/
int QNearFieldTagType1::memorySize()
{
- RequestId id = readByte(10);
+ QNearFieldTarget::RequestId id = readByte(10);
if (!waitForRequestCompleted(id))
return 0;
@@ -548,7 +512,7 @@ QNearFieldTarget::RequestId QNearFieldTagType1::readAll()
QNearFieldTarget::RequestId QNearFieldTagType1::readByte(quint8 address)
{
if (address & 0x80)
- return RequestId();
+ return QNearFieldTarget::RequestId();
QByteArray command;
command.append(char(0x01)); // READ
@@ -556,7 +520,7 @@ QNearFieldTarget::RequestId QNearFieldTagType1::readByte(quint8 address)
command.append(char(0x00)); // Data (unused)
command.append(uid().left(4)); // 4 bytes of UID
- RequestId id = sendCommand(command);
+ QNearFieldTarget::RequestId id = sendCommand(command);
Q_D(QNearFieldTagType1);
@@ -582,7 +546,7 @@ QNearFieldTarget::RequestId QNearFieldTagType1::writeByte(quint8 address, quint8
WriteMode mode)
{
if (address & 0x80)
- return RequestId();
+ return QNearFieldTarget::RequestId();
QByteArray command;
@@ -591,13 +555,13 @@ QNearFieldTarget::RequestId QNearFieldTagType1::writeByte(quint8 address, quint8
else if (mode == WriteOnly)
command.append(char(0x1a)); // WRITE-NE
else
- return RequestId();
+ return QNearFieldTarget::RequestId();
command.append(char(address)); // Address
command.append(char(data)); // Data
command.append(uid().left(4)); // 4 bytes of UID
- RequestId id = sendCommand(command);
+ QNearFieldTarget::RequestId id = sendCommand(command);
Q_D(QNearFieldTagType1);
@@ -618,7 +582,7 @@ QNearFieldTarget::RequestId QNearFieldTagType1::writeByte(quint8 address, quint8
QNearFieldTarget::RequestId QNearFieldTagType1::readSegment(quint8 segmentAddress)
{
if (segmentAddress & 0xf0)
- return RequestId();
+ return QNearFieldTarget::RequestId();
QByteArray command;
command.append(char(0x10)); // RSEG
@@ -626,7 +590,7 @@ QNearFieldTarget::RequestId QNearFieldTagType1::readSegment(quint8 segmentAddres
command.append(QByteArray(8, char(0x00))); // Data (unused)
command.append(uid().left(4)); // 4 bytes of UID
- RequestId id = sendCommand(command);
+ QNearFieldTarget::RequestId id = sendCommand(command);
Q_D(QNearFieldTagType1);
@@ -652,7 +616,7 @@ QNearFieldTarget::RequestId QNearFieldTagType1::readBlock(quint8 blockAddress)
command.append(QByteArray(8, char(0x00))); // Data (unused)
command.append(uid().left(4)); // 4 bytes of UID
- RequestId id = sendCommand(command);
+ QNearFieldTarget::RequestId id = sendCommand(command);
Q_D(QNearFieldTagType1);
@@ -678,8 +642,8 @@ QNearFieldTarget::RequestId QNearFieldTagType1::writeBlock(quint8 blockAddress,
const QByteArray &data,
WriteMode mode)
{
- if (data.length() != 8)
- return RequestId();
+ if (data.size() != 8)
+ return QNearFieldTarget::RequestId();
QByteArray command;
@@ -688,13 +652,13 @@ QNearFieldTarget::RequestId QNearFieldTagType1::writeBlock(quint8 blockAddress,
else if (mode == WriteOnly)
command.append(char(0x1b)); // WRITE-NE8
else
- return RequestId();
+ return QNearFieldTarget::RequestId();
command.append(char(blockAddress)); // Block address
command.append(data); // Data
command.append(uid().left(4)); // 4 bytes of UID
- RequestId id = sendCommand(command);
+ QNearFieldTarget::RequestId id = sendCommand(command);
Q_D(QNearFieldTagType1);
@@ -706,22 +670,19 @@ QNearFieldTarget::RequestId QNearFieldTagType1::writeBlock(quint8 blockAddress,
/*!
\reimp
*/
-bool QNearFieldTagType1::handleResponse(const QNearFieldTarget::RequestId &id,
- const QByteArray &response)
+void QNearFieldTagType1::setResponseForRequest(const QNearFieldTarget::RequestId &id,
+ const QVariant &response,
+ bool emitRequestCompleted)
{
Q_D(QNearFieldTagType1);
- bool handled;
-
if (d->m_pendingInternalCommands.contains(id)) {
const QByteArray command = d->m_pendingInternalCommands.take(id);
- QVariant decodedResponse = decodeResponse(command, response);
- setResponseForRequest(id, decodedResponse);
-
- handled = true;
+ QVariant decodedResponse = decodeResponse(command, response.toByteArray());
+ QNearFieldTargetPrivate::setResponseForRequest(id, decodedResponse, emitRequestCompleted);
} else {
- handled = QNearFieldTarget::handleResponse(id, response);
+ QNearFieldTargetPrivate::setResponseForRequest(id, response, emitRequestCompleted);
}
// continue reading / writing NDEF message
@@ -731,8 +692,6 @@ bool QNearFieldTagType1::handleResponse(const QNearFieldTarget::RequestId &id,
else if (d->m_writeNdefMessageState != QNearFieldTagType1Private::NotWritingNdefMessage)
d->progressToNextNdefWriteMessageState();
}
-
- return handled;
}
QT_END_NAMESPACE
diff --git a/tests/auto/nfccommons/qnearfieldtagtype1_p.h b/tests/auto/nfccommons/qnearfieldtagtype1_p.h
new file mode 100644
index 00000000..69e37c8c
--- /dev/null
+++ b/tests/auto/nfccommons/qnearfieldtagtype1_p.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QNEARFIELDTAGTYPE1_H
+#define QNEARFIELDTAGTYPE1_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 <QtNfc/private/qnearfieldtarget_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldTagType1Private;
+
+class QNearFieldTagType1 : public QNearFieldTargetPrivate
+{
+ Q_OBJECT
+
+ Q_DECLARE_PRIVATE(QNearFieldTagType1)
+
+public:
+ enum WriteMode {
+ EraseAndWrite,
+ WriteOnly
+ };
+ Q_ENUM(WriteMode)
+
+ explicit QNearFieldTagType1(QObject *parent = nullptr);
+ ~QNearFieldTagType1();
+
+ QNearFieldTarget::Type type() const override { return QNearFieldTarget::NfcTagType1; }
+
+ bool hasNdefMessage() override;
+ QNearFieldTarget::RequestId readNdefMessages() override;
+ QNearFieldTarget::RequestId writeNdefMessages(const QList<QNdefMessage> &messages) override;
+
+ quint8 version();
+ virtual int memorySize();
+
+ // DIGPROTO
+ virtual QNearFieldTarget::RequestId readIdentification();
+
+ // static memory functions
+ virtual QNearFieldTarget::RequestId readAll();
+ virtual QNearFieldTarget::RequestId readByte(quint8 address);
+ virtual QNearFieldTarget::RequestId writeByte(quint8 address, quint8 data, WriteMode mode = EraseAndWrite);
+
+ // dynamic memory functions
+ virtual QNearFieldTarget::RequestId readSegment(quint8 segmentAddress);
+ virtual QNearFieldTarget::RequestId readBlock(quint8 blockAddress);
+ virtual QNearFieldTarget::RequestId writeBlock(quint8 blockAddress, const QByteArray &data,
+ WriteMode mode = EraseAndWrite);
+
+protected:
+ void setResponseForRequest(const QNearFieldTarget::RequestId &id, const QVariant &response, bool emitRequestCompleted = true) override;
+
+private:
+ QNearFieldTagType1Private *d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNEARFIELDTAGTYPE1_H
diff --git a/src/nfc/qnearfieldtagtype2.cpp b/tests/auto/nfccommons/qnearfieldtagtype2.cpp
index 492dc5e3..fc416900 100644
--- a/src/nfc/qnearfieldtagtype2.cpp
+++ b/tests/auto/nfccommons/qnearfieldtagtype2.cpp
@@ -1,44 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 GPL-3.0-only
#include "qnearfieldtagtype2_p.h"
-#include "qnearfieldtarget_p.h"
+#include <QtNfc/private/qnearfieldtarget_p.h>
#include <QtCore/QVariant>
#include <QtCore/QCoreApplication>
@@ -98,7 +62,7 @@ static QVariant decodeResponse(const QByteArray &command, const QByteArray &resp
Constructs a new tag type 2 near field target with \a parent.
*/
QNearFieldTagType2::QNearFieldTagType2(QObject *parent)
-: QNearFieldTarget(parent), d_ptr(new QNearFieldTagType2Private)
+: QNearFieldTargetPrivate(parent), d_ptr(new QNearFieldTagType2Private)
{
}
@@ -124,7 +88,7 @@ bool QNearFieldTagType2::hasNdefMessage()
*/
QNearFieldTarget::RequestId QNearFieldTagType2::readNdefMessages()
{
- return RequestId();
+ return QNearFieldTarget::RequestId();
}
/*!
@@ -134,7 +98,7 @@ QNearFieldTarget::RequestId QNearFieldTagType2::writeNdefMessages(const QList<QN
{
Q_UNUSED(messages);
- return RequestId();
+ return QNearFieldTarget::RequestId();
}
/*!
@@ -144,12 +108,12 @@ quint8 QNearFieldTagType2::version()
{
Q_D(QNearFieldTagType2);
if (d->m_currentSector != 0) {
- RequestId id = selectSector(0);
+ QNearFieldTarget::RequestId id = selectSector(0);
if (!waitForRequestCompleted(id))
return 0;
}
- RequestId id = readBlock(0);
+ QNearFieldTarget::RequestId id = readBlock(0);
if (!waitForRequestCompleted(id))
return 0;
@@ -164,12 +128,12 @@ int QNearFieldTagType2::memorySize()
{
Q_D(QNearFieldTagType2);
if (d->m_currentSector != 0) {
- RequestId id = selectSector(0);
+ QNearFieldTarget::RequestId id = selectSector(0);
if (!waitForRequestCompleted(id))
return 0;
}
- RequestId id = readBlock(0);
+ QNearFieldTarget::RequestId id = readBlock(0);
if (!waitForRequestCompleted(id))
return 0;
@@ -207,15 +171,15 @@ QNearFieldTarget::RequestId QNearFieldTagType2::readBlock(quint8 blockAddress)
QNearFieldTarget::RequestId QNearFieldTagType2::writeBlock(quint8 blockAddress,
const QByteArray &data)
{
- if (data.length() != 4)
- return RequestId();
+ if (data.size() != 4)
+ return QNearFieldTarget::RequestId();
QByteArray command;
command.append(char(0xa2)); // WRITE
command.append(char(blockAddress)); // Block address
command.append(data); // Data
- RequestId id = sendCommand(command);
+ QNearFieldTarget::RequestId id = sendCommand(command);
Q_D(QNearFieldTagType2);
@@ -243,7 +207,7 @@ QNearFieldTarget::RequestId QNearFieldTagType2::selectSector(quint8 sector)
command.append(char(0xc2)); // SECTOR SELECT (Command Packet 1)
command.append(char(0xff));
- RequestId id = sendCommand(command);
+ QNearFieldTarget::RequestId id = sendCommand(command);
Q_D(QNearFieldTagType2);
@@ -261,15 +225,16 @@ QNearFieldTarget::RequestId QNearFieldTagType2::selectSector(quint8 sector)
/*!
\reimp
*/
-bool QNearFieldTagType2::handleResponse(const QNearFieldTarget::RequestId &id,
- const QByteArray &response)
+void QNearFieldTagType2::setResponseForRequest(const QNearFieldTarget::RequestId &id,
+ const QVariant &response,
+ bool emitRequestCompleted)
{
Q_D(QNearFieldTagType2);
if (d->m_pendingInternalCommands.contains(id)) {
const QByteArray command = d->m_pendingInternalCommands.take(id);
- QVariant decodedResponse = decodeResponse(command, response);
+ QVariant decodedResponse = decodeResponse(command, response.toByteArray());
if (quint8(command.at(0)) == 0xc2 && decodedResponse.toBool()) {
// SECTOR SELECT (Command Packet 2)
SectorSelectState &state = d->m_pendingSectorSelectCommands[id];
@@ -282,20 +247,22 @@ bool QNearFieldTagType2::handleResponse(const QNearFieldTarget::RequestId &id,
state.timerId = startTimer(1);
} else {
- setResponseForRequest(id, decodedResponse);
+ QNearFieldTargetPrivate::setResponseForRequest(id, decodedResponse, emitRequestCompleted);
}
- return true;
- } else if (d->m_pendingSectorSelectCommands.contains(id)) {
- if (!response.isEmpty()) {
+ return;
+ }
+
+ if (d->m_pendingSectorSelectCommands.contains(id)) {
+ if (!response.toByteArray().isEmpty()) {
d->m_pendingSectorSelectCommands.remove(id);
- setResponseForRequest(id, false);
+ QNearFieldTargetPrivate::setResponseForRequest(id, false, emitRequestCompleted);
- return true;
+ return;
}
}
- return QNearFieldTarget::handleResponse(id, response);
+ QNearFieldTargetPrivate::setResponseForRequest(id, response, emitRequestCompleted);
}
/*!
@@ -314,7 +281,7 @@ void QNearFieldTagType2::timerEvent(QTimerEvent *event)
if (state.timerId == event->timerId()) {
d->m_currentSector = state.sector;
- setResponseForRequest(i.key(), true);
+ QNearFieldTargetPrivate::setResponseForRequest(i.key(), true);
d->m_pendingSectorSelectCommands.erase(i);
break;
diff --git a/tests/auto/nfccommons/qnearfieldtagtype2_p.h b/tests/auto/nfccommons/qnearfieldtagtype2_p.h
new file mode 100644
index 00000000..65b9b7d1
--- /dev/null
+++ b/tests/auto/nfccommons/qnearfieldtagtype2_p.h
@@ -0,0 +1,58 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QNEARFIELDTAGTYPE2_H
+#define QNEARFIELDTAGTYPE2_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 <QtNfc/private/qnearfieldtarget_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldTagType2Private;
+
+class QNearFieldTagType2 : public QNearFieldTargetPrivate
+{
+ Q_OBJECT
+
+ Q_DECLARE_PRIVATE(QNearFieldTagType2)
+
+public:
+ explicit QNearFieldTagType2(QObject *parent = nullptr);
+ ~QNearFieldTagType2();
+
+ QNearFieldTarget::Type type() const override { return QNearFieldTarget::NfcTagType2; }
+
+ bool hasNdefMessage() override;
+ QNearFieldTarget::RequestId readNdefMessages() override;
+ QNearFieldTarget::RequestId writeNdefMessages(const QList<QNdefMessage> &messages) override;
+
+ quint8 version();
+ int memorySize();
+
+ virtual QNearFieldTarget::RequestId readBlock(quint8 blockAddress);
+ virtual QNearFieldTarget::RequestId writeBlock(quint8 blockAddress, const QByteArray &data);
+ virtual QNearFieldTarget::RequestId selectSector(quint8 sector);
+
+ void timerEvent(QTimerEvent *event) override;
+
+protected:
+ void setResponseForRequest(const QNearFieldTarget::RequestId &id, const QVariant &response, bool emitRequestCompleted = true) override;
+
+private:
+ QNearFieldTagType2Private *d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNEARFIELDTAGTYPE2_H
diff --git a/tests/auto/nfccommons/qnearfieldtarget_emulator.cpp b/tests/auto/nfccommons/qnearfieldtarget_emulator.cpp
new file mode 100644
index 00000000..776ba6f6
--- /dev/null
+++ b/tests/auto/nfccommons/qnearfieldtarget_emulator.cpp
@@ -0,0 +1,279 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qnearfieldtarget_emulator_p.h"
+#include <QtNfc/private/qnearfieldtarget_p.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QByteArrayView>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDateTime>
+#include <QtCore/QDirIterator>
+#include <QtCore/QMutex>
+#include <QtCore/QSettings>
+
+QT_BEGIN_NAMESPACE
+
+static QMutex tagMutex;
+static QMap<TagBase *, bool> tagMap;
+
+Q_GLOBAL_STATIC(TagActivator, globalTagActivator)
+
+TagType1::TagType1(TagBase *tag, QObject *parent)
+: QNearFieldTagType1(parent), tag(tag)
+{
+}
+
+TagType1::~TagType1()
+{
+}
+
+QByteArray TagType1::uid() const
+{
+ QMutexLocker locker(&tagMutex);
+
+ return tag->uid();
+}
+
+QNearFieldTarget::AccessMethods TagType1::accessMethods() const
+{
+ return QNearFieldTarget::NdefAccess | QNearFieldTarget::TagTypeSpecificAccess;
+}
+
+QNearFieldTarget::RequestId TagType1::sendCommand(const QByteArray &command)
+{
+ QMutexLocker locker(&tagMutex);
+
+ QNearFieldTarget::RequestId id(new QNearFieldTarget::RequestIdPrivate);
+
+ // tag not in proximity
+ if (!tagMap.value(tag)) {
+ reportError(QNearFieldTarget::TargetOutOfRangeError, id);
+ return id;
+ }
+
+ quint16 crc = qChecksum(QByteArrayView(command.constData(), command.size()), Qt::ChecksumItuV41);
+
+ QByteArray response = tag->processCommand(command + char(crc & 0xff) + char(crc >> 8));
+
+ if (response.isEmpty()) {
+ reportError(QNearFieldTarget::NoResponseError, id);
+ return id;
+ }
+
+ // check crc
+ if (qChecksum(QByteArrayView(response.constData(), response.size()), Qt::ChecksumItuV41) != 0) {
+ reportError(QNearFieldTarget::ChecksumMismatchError, id);
+ return id;
+ }
+
+ response.chop(2);
+
+ QMetaObject::invokeMethod(this, [this, id, response] {
+ this->setResponseForRequest(id, response);
+ }, Qt::QueuedConnection);
+
+ return id;
+}
+
+bool TagType1::waitForRequestCompleted(const QNearFieldTarget::RequestId &id, int msecs)
+{
+ QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
+
+ return QNearFieldTagType1::waitForRequestCompleted(id, msecs);
+}
+
+
+TagType2::TagType2(TagBase *tag, QObject *parent)
+: QNearFieldTagType2(parent), tag(tag)
+{
+}
+
+TagType2::~TagType2()
+{
+}
+
+QByteArray TagType2::uid() const
+{
+ QMutexLocker locker(&tagMutex);
+
+ return tag->uid();
+}
+
+QNearFieldTarget::AccessMethods TagType2::accessMethods() const
+{
+ return QNearFieldTarget::NdefAccess | QNearFieldTarget::TagTypeSpecificAccess;
+}
+
+QNearFieldTarget::RequestId TagType2::sendCommand(const QByteArray &command)
+{
+ QMutexLocker locker(&tagMutex);
+
+ QNearFieldTarget::RequestId id(new QNearFieldTarget::RequestIdPrivate);
+
+ // tag not in proximity
+ if (!tagMap.value(tag)) {
+ reportError(QNearFieldTarget::TargetOutOfRangeError, id);
+ return id;
+ }
+
+ quint16 crc = qChecksum(QByteArrayView(command.constData(), command.size()), Qt::ChecksumItuV41);
+
+ QByteArray response = tag->processCommand(command + char(crc & 0xff) + char(crc >> 8));
+
+ if (response.isEmpty())
+ return id;
+
+ if (response.size() > 1) {
+ // check crc
+ if (qChecksum(QByteArrayView(response.constData(), response.size()), Qt::ChecksumItuV41) != 0) {
+ reportError(QNearFieldTarget::ChecksumMismatchError, id);
+ return id;
+ }
+
+ response.chop(2);
+ }
+
+ QMetaObject::invokeMethod(this, [this, id, response] {
+ this->setResponseForRequest(id, response);
+ }, Qt::QueuedConnection);
+
+ return id;
+}
+
+bool TagType2::waitForRequestCompleted(const QNearFieldTarget::RequestId &id, int msecs)
+{
+ QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
+
+ return QNearFieldTagType2::waitForRequestCompleted(id, msecs);
+}
+
+TagActivator::TagActivator() : QObject()
+{
+ qRegisterMetaType<QNearFieldTarget::Error>();
+}
+
+TagActivator::~TagActivator()
+{
+ QMutexLocker locker(&tagMutex);
+ qDeleteAll(tagMap.keys());
+ tagMap.clear();
+}
+
+void TagActivator::initialize()
+{
+ QMutexLocker locker(&tagMutex);
+
+ if (!tagMap.isEmpty())
+ return;
+
+#ifndef BUILTIN_TESTDATA
+ QDirIterator nfcTargets(QDir::currentPath(), QStringList(QStringLiteral("*.nfc")), QDir::Files);
+#else
+ QDirIterator nfcTargets(":/nfcdata", QStringList(QStringLiteral("*.nfc")), QDir::Files);
+#endif
+ while (nfcTargets.hasNext()) {
+ const QString targetFilename = nfcTargets.next();
+
+ QSettings target(targetFilename, QSettings::IniFormat);
+
+ target.beginGroup(QStringLiteral("Target"));
+
+ const QString tagType = target.value(QStringLiteral("Type")).toString();
+
+ target.endGroup();
+
+ if (tagType == QLatin1String("TagType1")) {
+ NfcTagType1 *tag = new NfcTagType1;
+ tag->load(&target);
+
+ tagMap.insert(tag, false);
+ } else if (tagType == QLatin1String("TagType2")) {
+ NfcTagType2 *tag = new NfcTagType2;
+ tag->load(&target);
+
+ tagMap.insert(tag, false);
+ } else {
+ qWarning("Unknown tag type %s\n", qPrintable(tagType));
+ }
+ }
+
+ current = tagMap.end();
+}
+
+void TagActivator::reset()
+{
+ QMutexLocker locker(&tagMutex);
+
+ stopInternal();
+
+ qDeleteAll(tagMap.keys());
+ tagMap.clear();
+}
+
+void TagActivator::start()
+{
+ QMutexLocker locker(&tagMutex);
+ timerId = startTimer(1000);
+}
+
+void TagActivator::stop()
+{
+ QMutexLocker locker(&tagMutex);
+ stopInternal();
+}
+
+void TagActivator::stopInternal()
+{
+ if (timerId != -1) {
+ killTimer(timerId);
+ timerId = -1;
+ }
+}
+
+TagActivator *TagActivator::instance()
+{
+ return globalTagActivator();
+}
+
+void TagActivator::timerEvent(QTimerEvent *e)
+{
+ Q_UNUSED(e);
+
+ tagMutex.lock();
+
+ if (current != tagMap.end()) {
+ if (current.key()->lastAccessTime() + 1500 > QDateTime::currentMSecsSinceEpoch()) {
+ tagMutex.unlock();
+ return;
+ }
+
+ *current = false;
+
+ TagBase *tag = current.key();
+
+ tagMutex.unlock();
+ Q_EMIT tagDeactivated(tag);
+ tagMutex.lock();
+ }
+
+ if (current != tagMap.end())
+ ++current;
+
+ if (current == tagMap.end())
+ current = tagMap.begin();
+
+ if (current != tagMap.end()) {
+ *current = true;
+
+ TagBase *tag = current.key();
+
+ tagMutex.unlock();
+ Q_EMIT tagActivated(tag);
+ tagMutex.lock();
+ }
+
+ tagMutex.unlock();
+}
+
+QT_END_NAMESPACE
diff --git a/tests/auto/nfccommons/qnearfieldtarget_emulator_p.h b/tests/auto/nfccommons/qnearfieldtarget_emulator_p.h
new file mode 100644
index 00000000..4807ad20
--- /dev/null
+++ b/tests/auto/nfccommons/qnearfieldtarget_emulator_p.h
@@ -0,0 +1,96 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QNEARFIELDTARGET_EMULATOR_P_H
+#define QNEARFIELDTARGET_EMULATOR_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 "qnearfieldtagtype1_p.h"
+#include "qnearfieldtagtype2_p.h"
+#include "targetemulator_p.h"
+
+#include <QtCore/QMap>
+
+QT_BEGIN_NAMESPACE
+
+class TagType1 : public QNearFieldTagType1
+{
+ Q_OBJECT
+
+public:
+ TagType1(TagBase *tag, QObject *parent = nullptr);
+ ~TagType1();
+
+ QByteArray uid() const override;
+
+ QNearFieldTarget::AccessMethods accessMethods() const override;
+
+ QNearFieldTarget::RequestId sendCommand(const QByteArray &command) override;
+ bool waitForRequestCompleted(const QNearFieldTarget::RequestId &id, int msecs);
+
+private:
+ TagBase *tag;
+};
+
+class TagType2 : public QNearFieldTagType2
+{
+ Q_OBJECT
+
+public:
+ TagType2(TagBase *tag, QObject *parent = nullptr);
+ ~TagType2();
+
+ QByteArray uid() const override;
+
+ QNearFieldTarget::AccessMethods accessMethods() const override;
+
+ QNearFieldTarget::RequestId sendCommand(const QByteArray &command) override;
+ bool waitForRequestCompleted(const QNearFieldTarget::RequestId &id, int msecs);
+
+private:
+ TagBase *tag;
+};
+
+class TagActivator : public QObject
+{
+ Q_OBJECT
+
+public:
+ TagActivator();
+ ~TagActivator();
+
+ void initialize();
+ void reset();
+
+ void start();
+ void stop();
+
+ static TagActivator *instance();
+
+protected:
+ void timerEvent(QTimerEvent *e) override;
+
+signals:
+ void tagActivated(TagBase *tag);
+ void tagDeactivated(TagBase *tag);
+
+private:
+ void stopInternal();
+
+ QMap<TagBase *, bool>::Iterator current;
+ int timerId = -1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNEARFIELDTARGET_EMULATOR_P_H
diff --git a/src/nfc/qtlv.cpp b/tests/auto/nfccommons/qtlv.cpp
index 3168854c..f7dae52b 100644
--- a/src/nfc/qtlv.cpp
+++ b/tests/auto/nfccommons/qtlv.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 GPL-3.0-only
#include "qtlv_p.h"
@@ -88,7 +52,7 @@ QPair<int, int> qParseLockControlTlv(const QByteArray &tlvData)
return qMakePair(byteAddress, size);
}
-QTlvReader::QTlvReader(QNearFieldTarget *target)
+QTlvReader::QTlvReader(QNearFieldTargetPrivate *target)
: m_target(target), m_index(-1)
{
if (qobject_cast<QNearFieldTagType1 *>(m_target)) {
@@ -140,7 +104,7 @@ bool QTlvReader::atEnd() const
if (m_requestId.isValid())
return false;
- return (m_index == m_tlvData.length()) || (tag() == 0xfe);
+ return (m_index == m_tlvData.size()) || (tag() == 0xfe);
}
/*!
@@ -240,8 +204,8 @@ QByteArray QTlvReader::data()
bool QTlvReader::readMoreData(int sparseOffset)
{
- while (sparseOffset >= m_tlvData.length()) {
- int absOffset = absoluteOffset(m_tlvData.length());
+ while (sparseOffset >= m_tlvData.size()) {
+ int absOffset = absoluteOffset(m_tlvData.size());
QByteArray data;
@@ -272,7 +236,7 @@ bool QTlvReader::readMoreData(int sparseOffset)
}
}
- if (data.isEmpty() && sparseOffset >= m_tlvData.length())
+ if (data.isEmpty() && sparseOffset >= m_tlvData.size())
return false;
m_tlvData.append(data);
@@ -311,7 +275,7 @@ int QTlvReader::dataLength(int startOffset) const
}
-QTlvWriter::QTlvWriter(QNearFieldTarget *target)
+QTlvWriter::QTlvWriter(QNearFieldTargetPrivate *target)
: m_target(target), m_rawData(0), m_index(0), m_tagMemorySize(-1)
{
if (qobject_cast<QNearFieldTagType1 *>(m_target)) {
@@ -343,7 +307,7 @@ void QTlvWriter::writeTlv(quint8 tagType, const QByteArray &data)
m_buffer.append(tagType);
if (tagType != 0x00 && tagType != 0xfe) {
- int length = data.length();
+ int length = data.size();
if (length < 0xff) {
m_buffer.append(quint8(length));
} else {
@@ -389,7 +353,7 @@ bool QTlvWriter::process(bool all)
if (m_tagMemorySize == -1) {
if (m_rawData)
- m_tagMemorySize = m_rawData->length();
+ m_tagMemorySize = m_rawData->size();
else if (QNearFieldTagType1 *tag = qobject_cast<QNearFieldTagType1 *>(m_target)) {
if (m_requestId.isValid()) {
m_tagMemorySize = 8 * (tag->requestResponse(m_requestId).toUInt() + 1);
@@ -406,7 +370,7 @@ bool QTlvWriter::process(bool all)
if (spaceRemaining < 1)
return false;
- int length = qMin(spaceRemaining, m_buffer.length());
+ int length = qMin(spaceRemaining, m_buffer.size());
if (m_rawData) {
m_rawData->replace(m_index, length, m_buffer);
@@ -458,16 +422,16 @@ bool QTlvWriter::process(bool all)
int fillLength = qMin(nextBlockStart - m_index, spaceRemaining - bufferIndex);
- if (fillLength && (all || m_buffer.length() - bufferIndex >= fillLength) &&
- (m_buffer.length() != bufferIndex)) {
+ if (fillLength && (all || m_buffer.size() - bufferIndex >= fillLength) &&
+ (m_buffer.size() != bufferIndex)) {
// sufficient data available
if (m_requestId.isValid()) {
const QVariant v = tag->requestResponse(m_requestId);
- if (v.type() == QVariant::ByteArray) {
+ if (v.typeId() == QMetaType::QByteArray) {
// read in block
QByteArray block = v.toByteArray();
- int fill = qMin(fillLength, m_buffer.length() - bufferIndex);
+ int fill = qMin(fillLength, m_buffer.size() - bufferIndex);
for (int i = m_index - currentBlockStart; i < fill; ++i)
block[i] = m_buffer.at(bufferIndex++);
@@ -475,9 +439,9 @@ bool QTlvWriter::process(bool all)
// now write block
m_requestId = tag->writeBlock(currentBlock, block);
return false;
- } else if (v.type() == QVariant::Bool) {
+ } else if (v.typeId() == QMetaType::Bool) {
m_requestId = QNearFieldTarget::RequestId();
- int fill = qMin(fillLength, m_buffer.length() - bufferIndex);
+ int fill = qMin(fillLength, m_buffer.size() - bufferIndex);
bufferIndex = fill - (m_index - currentBlockStart);
// write complete
diff --git a/tests/auto/nfccommons/qtlv_p.h b/tests/auto/nfccommons/qtlv_p.h
new file mode 100644
index 00000000..58119ec9
--- /dev/null
+++ b/tests/auto/nfccommons/qtlv_p.h
@@ -0,0 +1,96 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QTLV_P_H
+#define QTLV_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 <QtNfc/qnearfieldtarget.h>
+#include <QtNfc/private/qnearfieldtarget_p.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QMap>
+#include <QtCore/QPair>
+
+QT_BEGIN_NAMESPACE
+
+class QNearFieldTarget;
+class QTlvReader
+{
+public:
+ explicit QTlvReader(QNearFieldTargetPrivate *target);
+ explicit QTlvReader(const QByteArray &data);
+
+ void addReservedMemory(int offset, int length);
+ int reservedMemorySize() const;
+
+ QNearFieldTarget::RequestId requestId() const;
+
+ bool atEnd() const;
+
+ bool readNext();
+
+ quint8 tag() const;
+ int length();
+ QByteArray data();
+
+private:
+ bool readMoreData(int sparseOffset);
+ int absoluteOffset(int sparseOffset) const;
+ int dataLength(int startOffset) const;
+
+ QNearFieldTargetPrivate *m_target;
+ QByteArray m_rawData;
+ QNearFieldTarget::RequestId m_requestId;
+
+ QByteArray m_tlvData;
+ int m_index;
+ QMap<int, int> m_reservedMemory;
+};
+
+class QTlvWriter
+{
+public:
+ explicit QTlvWriter(QNearFieldTargetPrivate *target);
+ explicit QTlvWriter(QByteArray *data);
+ ~QTlvWriter();
+
+ void addReservedMemory(int offset, int length);
+
+ void writeTlv(quint8 tag, const QByteArray &data = QByteArray());
+
+ bool process(bool all = false);
+
+ QNearFieldTarget::RequestId requestId() const;
+
+private:
+ int moveToNextAvailable();
+
+ QNearFieldTargetPrivate *m_target;
+ QByteArray *m_rawData;
+
+ int m_index;
+ int m_tagMemorySize;
+ QMap<int, int> m_reservedMemory;
+
+ QByteArray m_buffer;
+
+ QNearFieldTarget::RequestId m_requestId;
+};
+
+QPair<int, int> qParseReservedMemoryControlTlv(const QByteArray &tlvData);
+QPair<int, int> qParseLockControlTlv(const QByteArray &tlvData);
+
+QT_END_NAMESPACE
+
+#endif // QTLV_P_H
diff --git a/src/nfc/targetemulator.cpp b/tests/auto/nfccommons/targetemulator.cpp
index 4b347208..f19d460b 100644
--- a/src/nfc/targetemulator.cpp
+++ b/tests/auto/nfccommons/targetemulator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc 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 GPL-3.0-only
#include "targetemulator_p.h"
@@ -55,11 +19,6 @@ TagBase::~TagBase()
{
}
-static inline quint8 blockByteToAddress(quint8 block, quint8 byte)
-{
- return ((block & 0x0f) << 3) | (byte & 0x07);
-}
-
NfcTagType1::NfcTagType1()
: hr0(0x11), hr1(0x00), memory(120, '\0')
{
@@ -94,7 +53,7 @@ void NfcTagType1::load(QSettings *settings)
qWarning("Only NFC TagType1 v1.0 behavior is supported.");
quint8 tms = memory.at(10);
- if (memory.length() != 8 * (tms + 1))
+ if (memory.size() != 8 * (tms + 1))
qWarning("Static memory size does not match TMS value.");
quint8 rwa = memory.at(11);
@@ -119,9 +78,6 @@ void NfcTagType1::load(QSettings *settings)
;
}
- //quint16 lock = (quint8(memory[blockByteToAddress(0x0e, 1)]) << 8) |
- // quint8(memory[blockByteToAddress(0x0e, 0)]);
-
settings->endGroup();
}
@@ -146,7 +102,7 @@ QByteArray NfcTagType1::processCommand(const QByteArray &command)
bool tagType1 = (hr0 & 0xf0) == 0x10;
bool dynamic = (hr0 & 0x0f) != 0x01;
- if (command.length() == 9) {
+ if (command.size() == 9) {
// static memory model command
quint8 opcode = command.at(0);
quint8 address = command.at(1);
@@ -154,7 +110,7 @@ QByteArray NfcTagType1::processCommand(const QByteArray &command)
QByteArray uid = command.mid(3, 4);
// check checksum
- if (qChecksum(command.constData(), command.length(), Qt::ChecksumItuV41) != 0)
+ if (qChecksum(QByteArrayView(command.constData(), command.size()), Qt::ChecksumItuV41) != 0)
return QByteArray();
// check UID
@@ -215,7 +171,7 @@ QByteArray NfcTagType1::processCommand(const QByteArray &command)
response.append(memory.left(4));
break;
}
- } else if (tagType1 && dynamic && command.length() == 16) {
+ } else if (tagType1 && dynamic && command.size() == 16) {
// dynamic memory model command
quint8 opcode = command.at(0);
quint8 address = command.at(1);
@@ -223,7 +179,7 @@ QByteArray NfcTagType1::processCommand(const QByteArray &command)
QByteArray uid = command.mid(10, 4);
// check checksum
- if (qChecksum(command.constData(), command.length(), Qt::ChecksumItuV41) != 0)
+ if (qChecksum(QByteArrayView(command.constData(), command.size()), Qt::ChecksumItuV41) != 0)
return QByteArray();
// check UID
@@ -277,7 +233,7 @@ QByteArray NfcTagType1::processCommand(const QByteArray &command)
}
if (!response.isEmpty()) {
- quint16 crc = qChecksum(response.constData(), response.length(), Qt::ChecksumItuV41);
+ quint16 crc = qChecksum(QByteArrayView(response.constData(), response.size()), Qt::ChecksumItuV41);
response.append(quint8(crc & 0xff));
response.append(quint8(crc >> 8));
}
@@ -321,13 +277,13 @@ QByteArray NfcTagType2::processCommand(const QByteArray &command)
QByteArray response;
// check checksum
- if (qChecksum(command.constData(), command.length(), Qt::ChecksumItuV41) != 0)
+ if (qChecksum(QByteArrayView(command.constData(), command.size()), Qt::ChecksumItuV41) != 0)
return QByteArray();
if (expectPacket2) {
expectPacket2 = false;
quint8 sector = command.at(0);
- if (sector * 1024 > memory.length())
+ if (sector * 1024 > memory.size())
return NACK;
else {
currentSector = sector;
@@ -343,8 +299,8 @@ QByteArray NfcTagType2::processCommand(const QByteArray &command)
int absoluteBlock = currentSector * 256 + block;
response.append(memory.mid(absoluteBlock * 4, 16));
- if (response.length() != 16)
- response.append(QByteArray(16 - response.length(), '\0'));
+ if (response.size() != 16)
+ response.append(QByteArray(16 - response.size(), '\0'));
break;
}
@@ -363,7 +319,7 @@ QByteArray NfcTagType2::processCommand(const QByteArray &command)
return ACK;
}
case 0xc2: // SECTOR SELECT - Packet 1
- if (memory.length() > 1024) {
+ if (memory.size() > 1024) {
expectPacket2 = true;
return ACK;
}
@@ -378,7 +334,7 @@ QByteArray NfcTagType2::processCommand(const QByteArray &command)
}
if (!response.isEmpty()) {
- quint16 crc = qChecksum(response.constData(), response.length(), Qt::ChecksumItuV41);
+ quint16 crc = qChecksum(QByteArrayView(response.constData(), response.size()), Qt::ChecksumItuV41);
response.append(quint8(crc & 0xff));
response.append(quint8(crc >> 8));
}
diff --git a/tests/auto/nfccommons/targetemulator_p.h b/tests/auto/nfccommons/targetemulator_p.h
new file mode 100644
index 00000000..f77a0b39
--- /dev/null
+++ b/tests/auto/nfccommons/targetemulator_p.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef TARGETEMULATOR_P_H
+#define TARGETEMULATOR_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/QtGlobal>
+#include <QtCore/QByteArray>
+#include <QtNfc/qtnfcglobal.h>
+#include <QMetaType>
+
+QT_FORWARD_DECLARE_CLASS(QSettings)
+
+QT_BEGIN_NAMESPACE
+
+class TagBase
+{
+public:
+ TagBase();
+ virtual ~TagBase();
+
+ virtual void load(QSettings *settings) = 0;
+
+ virtual QByteArray processCommand(const QByteArray &command) = 0;
+
+ virtual QByteArray uid() const = 0;
+
+ qint64 lastAccessTime() const { return lastAccess; }
+
+protected:
+ mutable qint64 lastAccess;
+};
+
+class NfcTagType1 : public TagBase
+{
+public:
+ NfcTagType1();
+ ~NfcTagType1();
+
+ void load(QSettings *settings) override;
+
+ QByteArray processCommand(const QByteArray &command) override;
+
+ QByteArray uid() const override;
+
+private:
+ quint8 readData(quint8 block, quint8 byte);
+
+ quint8 hr0;
+ quint8 hr1;
+
+ QByteArray memory;
+};
+
+class NfcTagType2 : public TagBase
+{
+public:
+ NfcTagType2();
+ ~NfcTagType2();
+
+ void load(QSettings *settings) override;
+
+ QByteArray processCommand(const QByteArray &command) override;
+
+ QByteArray uid() const override;
+
+private:
+ QByteArray memory;
+ quint8 currentSector;
+ bool expectPacket2;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(TagBase *)
+
+#endif // TARGETEMULATOR_P_H
diff --git a/tests/auto/qbluetoothaddress/CMakeLists.txt b/tests/auto/qbluetoothaddress/CMakeLists.txt
new file mode 100644
index 00000000..0bf39eeb
--- /dev/null
+++ b/tests/auto/qbluetoothaddress/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qbluetoothaddress Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qbluetoothaddress LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qbluetoothaddress
+ SOURCES
+ tst_qbluetoothaddress.cpp
+ LIBRARIES
+ Qt::Bluetooth
+)
diff --git a/tests/auto/qbluetoothaddress/qbluetoothaddress.pro b/tests/auto/qbluetoothaddress/qbluetoothaddress.pro
deleted file mode 100644
index f87551e8..00000000
--- a/tests/auto/qbluetoothaddress/qbluetoothaddress.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-SOURCES += tst_qbluetoothaddress.cpp
-TARGET = tst_qbluetoothaddress
-CONFIG += testcase
-
-QT = core concurrent bluetooth testlib
-
diff --git a/tests/auto/qbluetoothaddress/tst_qbluetoothaddress.cpp b/tests/auto/qbluetoothaddress/tst_qbluetoothaddress.cpp
index 7be97b36..8e1c9039 100644
--- a/tests/auto/qbluetoothaddress/tst_qbluetoothaddress.cpp
+++ b/tests/auto/qbluetoothaddress/tst_qbluetoothaddress.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
diff --git a/tests/auto/qbluetoothdevicediscoveryagent/CMakeLists.txt b/tests/auto/qbluetoothdevicediscoveryagent/CMakeLists.txt
new file mode 100644
index 00000000..9a43e90d
--- /dev/null
+++ b/tests/auto/qbluetoothdevicediscoveryagent/CMakeLists.txt
@@ -0,0 +1,39 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qbluetoothdevicediscoveryagent Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qbluetoothdevicediscoveryagent LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qbluetoothdevicediscoveryagent
+ SOURCES
+ tst_qbluetoothdevicediscoveryagent.cpp
+ LIBRARIES
+ Qt::BluetoothPrivate
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qbluetoothdevicediscoveryagent CONDITION MACOS
+ LIBRARIES
+ Qt::Widgets
+)
+
+set_target_properties(tst_qbluetoothdevicediscoveryagent PROPERTIES
+ MACOSX_BUNDLE TRUE
+)
+
+if (APPLE AND NOT IOS)
+ # Ninja has trouble with relative paths, convert to absolute as a workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../shared ABSOLUTE)
+ set_target_properties(tst_qbluetoothdevicediscoveryagent PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.macos.plist"
+ )
+endif()
diff --git a/tests/auto/qbluetoothdevicediscoveryagent/qbluetoothdevicediscoveryagent.pro b/tests/auto/qbluetoothdevicediscoveryagent/qbluetoothdevicediscoveryagent.pro
deleted file mode 100644
index 900bb5e9..00000000
--- a/tests/auto/qbluetoothdevicediscoveryagent/qbluetoothdevicediscoveryagent.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-SOURCES += tst_qbluetoothdevicediscoveryagent.cpp
-TARGET=tst_qbluetoothdevicediscoveryagent
-CONFIG += testcase
-
-QT = core concurrent bluetooth-private testlib
-osx:QT += widgets
diff --git a/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp b/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp
index cbce5042..d866ec57 100644
--- a/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp
+++ b/tests/auto/qbluetoothdevicediscoveryagent/tst_qbluetoothdevicediscoveryagent.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -33,11 +8,20 @@
#include <QList>
#include <QLoggingCategory>
+#include "../../shared/bttestutil_p.h"
#include <private/qtbluetoothglobal_p.h>
#include <qbluetoothaddress.h>
#include <qbluetoothdevicediscoveryagent.h>
#include <qbluetoothlocaldevice.h>
+#if QT_CONFIG(permissions)
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qpermissions.h>
+#include <QtCore/qnamespace.h>
+#endif // permissions
+
+#include <memory>
+
QT_USE_NAMESPACE
/*
@@ -55,6 +39,11 @@ const int MaxScanTime = 5 * 60 * 1000; // 5 minutes in ms
//Bluez needs at least 10s for a device discovery to be cancelled
const int MaxWaitForCancelTime = 15 * 1000; // 15 seconds in ms
+#ifdef Q_OS_ANDROID
+// Android is sometimes unable to cancel immediately
+const int WaitBeforeStopTime = 200;
+#endif
+
class tst_QBluetoothDeviceDiscoveryAgent : public QObject
{
Q_OBJECT
@@ -70,85 +59,52 @@ public slots:
private slots:
void initTestCase();
- void tst_properties();
-
void tst_invalidBtAddress();
void tst_startStopDeviceDiscoveries();
- void tst_deviceDiscovery_data();
void tst_deviceDiscovery();
void tst_discoveryTimeout();
void tst_discoveryMethods();
private:
- int noOfLocalDevices;
- bool isBluez5Runtime = false;
+ qsizetype noOfLocalDevices;
+ using DiscoveryAgentPtr = std::unique_ptr<QBluetoothDeviceDiscoveryAgent>;
+#if QT_CONFIG(permissions)
+ Qt::PermissionStatus permissionStatus = Qt::PermissionStatus::Undetermined;
+#endif
};
tst_QBluetoothDeviceDiscoveryAgent::tst_QBluetoothDeviceDiscoveryAgent()
{
QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
qRegisterMetaType<QBluetoothDeviceDiscoveryAgent::Error>();
-}
-
-tst_QBluetoothDeviceDiscoveryAgent::~tst_QBluetoothDeviceDiscoveryAgent()
-{
-}
-
-#if QT_CONFIG(bluez)
-// This section was adopted from tst_qloggingcategory.cpp
-QString logMessage;
-
-QByteArray qMyMessageFormatString(QtMsgType type, const QMessageLogContext &context,
- const QString &str)
-{
- QByteArray message;
- message.append(context.category);
- switch (type) {
- case QtDebugMsg: message.append(".debug"); break;
- case QtInfoMsg: message.append(".info"); break;
- case QtWarningMsg: message.append(".warning"); break;
- case QtCriticalMsg:message.append(".critical"); break;
- case QtFatalMsg: message.append(".fatal"); break;
+#if QT_CONFIG(permissions)
+ permissionStatus = qApp->checkPermission(QBluetoothPermission{});
+
+ const bool ciRun = qEnvironmentVariable("QTEST_ENVIRONMENT").split(' ').contains("ci");
+ if (!ciRun && permissionStatus == Qt::PermissionStatus::Undetermined) {
+ QTestEventLoop loop;
+ qApp->requestPermission(QBluetoothPermission{}, [this, &loop](const QPermission &permission){
+ permissionStatus = permission.status();
+ loop.exitLoop();
+ });
+ if (permissionStatus == Qt::PermissionStatus::Undetermined)
+ loop.enterLoopMSecs(30000);
}
- message.append(": ");
- message.append(qPrintable(str));
-
- return message.simplified();
+#endif // QT_CONFIG(permissions)
}
-static void myCustomMessageHandler(QtMsgType type,
- const QMessageLogContext &context,
- const QString &msg)
+tst_QBluetoothDeviceDiscoveryAgent::~tst_QBluetoothDeviceDiscoveryAgent()
{
- logMessage = qMyMessageFormatString(type, context, msg);
}
-#endif
-
-
void tst_QBluetoothDeviceDiscoveryAgent::initTestCase()
{
qRegisterMetaType<QBluetoothDeviceInfo>();
- qRegisterMetaType<QBluetoothDeviceDiscoveryAgent::InquiryType>();
-
-#if QT_CONFIG(bluez)
- // To distinguish Bluez 4 and 5 we peek into the debug output
- // of first Bluetooth ctor. It executes a runtime test and prints the result
- // as logging output. This avoids more complex runtime detection logic within this unit test.
- QtMessageHandler oldMessageHandler;
- oldMessageHandler = qInstallMessageHandler(myCustomMessageHandler);
-
- noOfLocalDevices = QBluetoothLocalDevice::allDevices().count();
- qInstallMessageHandler(oldMessageHandler);
- isBluez5Runtime = logMessage.contains(QStringLiteral("Bluez 5"));
- if (isBluez5Runtime)
- qDebug() << "BlueZ 5 runtime detected.";
-#else
- noOfLocalDevices = QBluetoothLocalDevice::allDevices().count();
-#endif
+
+ noOfLocalDevices = QBluetoothLocalDevice::allDevices().size();
if (!noOfLocalDevices)
return;
@@ -160,11 +116,11 @@ void tst_QBluetoothDeviceDiscoveryAgent::initTestCase()
QVERIFY(hostModeSpy.isEmpty());
device->powerOn();
int connectTime = 5000; // ms
- while (hostModeSpy.count() < 1 && connectTime > 0) {
+ while (hostModeSpy.isEmpty() && connectTime > 0) {
QTest::qWait(500);
connectTime -= 500;
}
- QVERIFY(hostModeSpy.count() > 0);
+ QVERIFY(!hostModeSpy.isEmpty());
}
QBluetoothLocalDevice::HostMode hostMode= device->hostMode();
QVERIFY(hostMode == QBluetoothLocalDevice::HostConnectable
@@ -173,33 +129,26 @@ void tst_QBluetoothDeviceDiscoveryAgent::initTestCase()
delete device;
}
-void tst_QBluetoothDeviceDiscoveryAgent::tst_properties()
-{
- QBluetoothDeviceDiscoveryAgent discoveryAgent;
-
- QCOMPARE(discoveryAgent.inquiryType(), QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry);
- discoveryAgent.setInquiryType(QBluetoothDeviceDiscoveryAgent::LimitedInquiry);
- QCOMPARE(discoveryAgent.inquiryType(), QBluetoothDeviceDiscoveryAgent::LimitedInquiry);
- discoveryAgent.setInquiryType(QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry);
- QCOMPARE(discoveryAgent.inquiryType(), QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry);
-}
-
void tst_QBluetoothDeviceDiscoveryAgent::tst_invalidBtAddress()
{
- QBluetoothDeviceDiscoveryAgent *discoveryAgent = new QBluetoothDeviceDiscoveryAgent(QBluetoothAddress("11:11:11:11:11:11"));
+ DiscoveryAgentPtr discoveryAgent(new QBluetoothDeviceDiscoveryAgent(
+ QBluetoothAddress(QStringLiteral("11:11:11:11:11:11"))));
QCOMPARE(discoveryAgent->error(), QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError);
discoveryAgent->start();
QCOMPARE(discoveryAgent->isActive(), false);
- delete discoveryAgent;
- discoveryAgent = new QBluetoothDeviceDiscoveryAgent(QBluetoothAddress());
+#if QT_CONFIG(permissions)
+ if (permissionStatus != Qt::PermissionStatus::Granted)
+ return;
+#endif
+
+ discoveryAgent.reset(new QBluetoothDeviceDiscoveryAgent(QBluetoothAddress()));
QCOMPARE(discoveryAgent->error(), QBluetoothDeviceDiscoveryAgent::NoError);
- if (QBluetoothLocalDevice::allDevices().count() > 0) {
+ if (!QBluetoothLocalDevice::allDevices().isEmpty()) {
discoveryAgent->start();
QCOMPARE(discoveryAgent->isActive(), true);
}
- delete discoveryAgent;
}
void tst_QBluetoothDeviceDiscoveryAgent::deviceDiscoveryDebug(const QBluetoothDeviceInfo &info)
@@ -209,7 +158,9 @@ void tst_QBluetoothDeviceDiscoveryAgent::deviceDiscoveryDebug(const QBluetoothDe
void tst_QBluetoothDeviceDiscoveryAgent::tst_startStopDeviceDiscoveries()
{
- QBluetoothDeviceDiscoveryAgent::InquiryType inquiryType = QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry;
+ if (androidBluetoothEmulator())
+ QSKIP("Skipping test on Android 12+ emulator, CI can timeout waiting for user input");
+
QBluetoothDeviceDiscoveryAgent discoveryAgent;
QVERIFY(discoveryAgent.error() == discoveryAgent.NoError);
@@ -219,14 +170,22 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_startStopDeviceDiscoveries()
QSignalSpy finishedSpy(&discoveryAgent, SIGNAL(finished()));
QSignalSpy cancelSpy(&discoveryAgent, SIGNAL(canceled()));
- QSignalSpy errorSpy(&discoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)));
+ QSignalSpy errorSpy(&discoveryAgent,
+ SIGNAL(errorOccurred(QBluetoothDeviceDiscoveryAgent::Error)));
// Starting case 1: start-stop, expecting cancel signal
- discoveryAgent.setInquiryType(inquiryType);
// we should have no errors at this point.
QVERIFY(errorSpy.isEmpty());
discoveryAgent.start();
+#if QT_CONFIG(permissions)
+ if (permissionStatus != Qt::PermissionStatus::Granted) {
+ // If bluetooth is OFF, the permission does not get checked (e.g. on Darwin),
+ // but not to depend on the order in which errors generated, we
+ // do not compare error value with MissionPermissionsError here.
+ return;
+ }
+#endif
if (errorSpy.isEmpty()) {
QVERIFY(discoveryAgent.isActive());
@@ -240,19 +199,27 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_startStopDeviceDiscoveries()
QSKIP("No local Bluetooth device available. Skipping remaining part of test.");
}
// cancel current request.
+#ifdef Q_OS_ANDROID
+ // Android sometimes can't cancel immediately (~on the same millisecond),
+ // but instead a "pending cancel" happens, which means the discovery will be
+ // canceled at a later point in time. When this happens the Android backend
+ // also emits an immediate errorOccurred(). While this seems to be as intended,
+ // as a result many parts of this test function may fail (not always).
+ //
+ // In this test function we wait some milliseconds between start() and stop() to
+ // bypass this behavior difference. This is to avoid complex iffery (Android itself
+ // can behave differently every time) and ifdeffery (Q_OS_ANDROID) in the test
+ QTest::qWait(WaitBeforeStopTime);
+#endif
discoveryAgent.stop();
// Wait for up to MaxWaitForCancelTime for the cancel to finish
- int waitTime = MaxWaitForCancelTime;
- while (cancelSpy.count() == 0 && waitTime > 0) {
- QTest::qWait(100);
- waitTime-=100;
- }
+ QTRY_VERIFY_WITH_TIMEOUT(!cancelSpy.isEmpty(), MaxWaitForCancelTime);
// we should not be active anymore
QVERIFY(!discoveryAgent.isActive());
QVERIFY(errorSpy.isEmpty());
- QCOMPARE(cancelSpy.count(), 1);
+ QCOMPARE(cancelSpy.size(), 1);
cancelSpy.clear();
// Starting case 2: start-start-stop, expecting cancel signal
discoveryAgent.start();
@@ -264,19 +231,19 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_startStopDeviceDiscoveries()
QVERIFY(discoveryAgent.isActive());
QVERIFY(errorSpy.isEmpty());
// stop
+#ifdef Q_OS_ANDROID
+ QTest::qWait(WaitBeforeStopTime);
+#endif
discoveryAgent.stop();
// Wait for up to MaxWaitForCancelTime for the cancel to finish
- waitTime = MaxWaitForCancelTime;
- while (cancelSpy.count() == 0 && waitTime > 0) {
- QTest::qWait(100);
- waitTime-=100;
- }
+ QTRY_VERIFY_WITH_TIMEOUT(!cancelSpy.isEmpty(), MaxWaitForCancelTime);
// we should not be active anymore
QVERIFY(!discoveryAgent.isActive());
QVERIFY(errorSpy.isEmpty());
- QVERIFY(cancelSpy.count() == 1);
+
+ QCOMPARE(cancelSpy.size(), 1);
cancelSpy.clear();
// Starting case 3: stop
@@ -285,7 +252,7 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_startStopDeviceDiscoveries()
QVERIFY(errorSpy.isEmpty());
// Don't expect finished signal and no error
- QVERIFY(finishedSpy.count() == 0);
+ QVERIFY(finishedSpy.isEmpty());
QVERIFY(discoveryAgent.error() == discoveryAgent.NoError);
QVERIFY(discoveryAgent.errorString().isEmpty());
@@ -306,9 +273,12 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_startStopDeviceDiscoveries()
QVERIFY(discoveryAgent.isActive());
QVERIFY(errorSpy.isEmpty());
// cancel current request.
+#ifdef Q_OS_ANDROID
+ QTest::qWait(WaitBeforeStopTime);
+#endif
discoveryAgent.stop();
//should only have triggered cancel() if stop didn't involve the event loop
- if (cancelSpy.count() == 1) immediateSignal = true;
+ if (cancelSpy.size() == 1) immediateSignal = true;
// start a new one
discoveryAgent.start();
@@ -316,25 +286,25 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_startStopDeviceDiscoveries()
QVERIFY(discoveryAgent.isActive());
QVERIFY(errorSpy.isEmpty());
// stop
+#ifdef Q_OS_ANDROID
+ QTest::qWait(WaitBeforeStopTime);
+#endif
discoveryAgent.stop();
if (immediateSignal)
- QVERIFY(cancelSpy.count() == 2);
+ QCOMPARE(cancelSpy.size(), 2);
// Wait for up to MaxWaitForCancelTime for the cancel to finish
- waitTime = MaxWaitForCancelTime;
- while (cancelSpy.count() == 0 && waitTime > 0) {
- QTest::qWait(100);
- waitTime-=100;
- }
+ QTRY_VERIFY_WITH_TIMEOUT(!cancelSpy.isEmpty(), MaxWaitForCancelTime);
+
// we should not be active anymore
QVERIFY(!discoveryAgent.isActive());
QVERIFY(errorSpy.isEmpty());
- // should only have 1 cancel
+ // should only have 1 cancel
if (immediateSignal)
- QVERIFY(cancelSpy.count() == 2);
+ QCOMPARE(cancelSpy.size(), 2);
else
- QVERIFY(cancelSpy.count() == 1);
+ QCOMPARE(cancelSpy.size(), 1);
cancelSpy.clear();
// Starting case 5: start-stop-start: expecting finished signal & no cancel
@@ -342,6 +312,9 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_startStopDeviceDiscoveries()
QVERIFY(discoveryAgent.isActive());
QVERIFY(errorSpy.isEmpty());
// cancel current request.
+#ifdef Q_OS_ANDROID
+ QTest::qWait(WaitBeforeStopTime);
+#endif
discoveryAgent.stop();
// start a new one
discoveryAgent.start();
@@ -349,18 +322,14 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_startStopDeviceDiscoveries()
QVERIFY(discoveryAgent.isActive());
QVERIFY(errorSpy.isEmpty());
- // Wait for up to MaxScanTime for the cancel to finish
- waitTime = MaxScanTime;
- while (finishedSpy.count() == 0 && waitTime > 0) {
- QTest::qWait(1000);
- waitTime-=1000;
- }
+ // Wait for up to MaxScanTime for the scan to finish
+ QTRY_VERIFY_WITH_TIMEOUT(!finishedSpy.isEmpty(), MaxScanTime);
// we should not be active anymore
QVERIFY(!discoveryAgent.isActive());
QVERIFY(errorSpy.isEmpty());
// should only have 1 cancel
- QVERIFY(finishedSpy.count() == 1);
+ QCOMPARE(finishedSpy.size(), 1);
// On OS X, stop is synchronous (signal will be emitted immediately).
if (!immediateSignal)
@@ -372,32 +341,13 @@ void tst_QBluetoothDeviceDiscoveryAgent::finished()
qDebug() << "Finished called";
}
-void tst_QBluetoothDeviceDiscoveryAgent::tst_deviceDiscovery_data()
-{
- QTest::addColumn<QBluetoothDeviceDiscoveryAgent::InquiryType>("inquiryType");
-
- QTest::newRow("general unlimited inquiry") << QBluetoothDeviceDiscoveryAgent::GeneralUnlimitedInquiry;
- QTest::newRow("limited inquiry") << QBluetoothDeviceDiscoveryAgent::LimitedInquiry;
-}
-
void tst_QBluetoothDeviceDiscoveryAgent::tst_deviceDiscovery()
{
{
- QFETCH(QBluetoothDeviceDiscoveryAgent::InquiryType, inquiryType);
-
//Run test in case of multiple Bluetooth adapters
QBluetoothLocalDevice localDevice;
//We will use default adapter if there is no other adapter
QBluetoothAddress address = localDevice.address();
- int numberOfAdapters = (localDevice.allDevices()).size();
- QList<QBluetoothAddress> addresses;
- if (numberOfAdapters > 1) {
-
- for (int i=0; i < numberOfAdapters; i++) {
- addresses.append(((QBluetoothHostInfo)localDevice.allDevices().at(i)).address());
- }
- address = (QBluetoothAddress)addresses.at(0);
- }
QBluetoothDeviceDiscoveryAgent discoveryAgent(address);
QVERIFY(discoveryAgent.error() == discoveryAgent.NoError);
@@ -407,15 +357,20 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_deviceDiscovery()
QVERIFY(discoveryAgent.discoveredDevices().isEmpty());
QSignalSpy finishedSpy(&discoveryAgent, SIGNAL(finished()));
- QSignalSpy errorSpy(&discoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)));
+ QSignalSpy errorSpy(&discoveryAgent,
+ SIGNAL(errorOccurred(QBluetoothDeviceDiscoveryAgent::Error)));
QSignalSpy discoveredSpy(&discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)));
// connect(&discoveryAgent, SIGNAL(finished()), this, SLOT(finished()));
// connect(&discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
// this, SLOT(deviceDiscoveryDebug(QBluetoothDeviceInfo)));
- discoveryAgent.setInquiryType(inquiryType);
discoveryAgent.start();
+
if (!errorSpy.isEmpty()) {
+#if QT_CONFIG(permissions)
+ if (permissionStatus == Qt::PermissionStatus::Granted)
+#endif
+
QCOMPARE(noOfLocalDevices, 0);
QVERIFY(!discoveryAgent.isActive());
QSKIP("No local Bluetooth device available. Skipping remaining part of test.");
@@ -425,7 +380,7 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_deviceDiscovery()
// Wait for up to MaxScanTime for the scan to finish
int scanTime = MaxScanTime;
- while (finishedSpy.count() == 0 && scanTime > 0) {
+ while (finishedSpy.isEmpty() && scanTime > 0) {
QTest::qWait(15000);
scanTime -= 15000;
}
@@ -437,16 +392,19 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_deviceDiscovery()
QVERIFY(!discoveryAgent.isActive());
qDebug() << "Scan time left:" << scanTime;
// Expect finished signal with no error
- QVERIFY(finishedSpy.count() == 1);
+ QVERIFY(finishedSpy.size() == 1);
QVERIFY(errorSpy.isEmpty());
QVERIFY(discoveryAgent.error() == discoveryAgent.NoError);
QVERIFY(discoveryAgent.errorString().isEmpty());
// verify that the list is as big as the signals received.
- QVERIFY(discoveredSpy.count() == discoveryAgent.discoveredDevices().length());
+ // discoveredSpy might have more events as some devices are found multiple times,
+ // leading to messages like
+ // "Almost Duplicate "88:C6:26:F5:3E:E2" "88-C6-26-F5-3E-E2" - replacing in place"
+ QVERIFY(discoveredSpy.size() >= discoveryAgent.discoveredDevices().size());
// verify that there really was some devices in the array
- const QString remote = qgetenv("BT_TEST_DEVICE");
+ const QString remote = qEnvironmentVariable("BT_TEST_DEVICE");
QBluetoothAddress remoteDevice;
if (!remote.isEmpty()) {
remoteDevice = QBluetoothAddress(remote);
@@ -456,31 +414,13 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_deviceDiscovery()
}
if (!remoteDevice.isNull())
- QVERIFY(discoveredSpy.count() > 0);
- int counter = 0;
+ QVERIFY(!discoveredSpy.isEmpty());
// All returned QBluetoothDeviceInfo should be valid.
while (!discoveredSpy.isEmpty()) {
const QBluetoothDeviceInfo info =
qvariant_cast<QBluetoothDeviceInfo>(discoveredSpy.takeFirst().at(0));
QVERIFY(info.isValid());
- qDebug() << "Discovered device:" << info.address().toString() << info.name();
-
- if (numberOfAdapters > 1) {
- for (int i= 1; i < numberOfAdapters; i++) {
- if (info.address().toString() == addresses[i].toString())
- counter++;
- }
- }
}
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) || QT_CONFIG(winrt_bt)
- //On iOS/WinRT, we do not have access to the local device/adapter, numberOfAdapters is 0,
- //so we skip this test at all.
- QSKIP("iOS/WinRT: no local Bluetooth device available. Skipping remaining part of test.");
-#endif
-
- //For multiple Bluetooth adapter do the check only for GeneralUnlimitedInquiry.
- if (!(inquiryType == QBluetoothDeviceDiscoveryAgent::LimitedInquiry))
- QVERIFY((numberOfAdapters-1) == counter);
}
}
@@ -490,24 +430,13 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_discoveryTimeout()
QBluetoothDeviceDiscoveryAgent agent;
// check default values
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) || defined(Q_OS_ANDROID) || QT_CONFIG(winrt_bt)
- QCOMPARE(agent.lowEnergyDiscoveryTimeout(), 25000);
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) || defined(Q_OS_ANDROID) || QT_CONFIG(winrt_bt) \
+ || QT_CONFIG(bluez)
+ QCOMPARE(agent.lowEnergyDiscoveryTimeout(), 40000);
agent.setLowEnergyDiscoveryTimeout(-1); // negative ignored
- QCOMPARE(agent.lowEnergyDiscoveryTimeout(), 25000);
+ QCOMPARE(agent.lowEnergyDiscoveryTimeout(), 40000);
agent.setLowEnergyDiscoveryTimeout(20000);
QCOMPARE(agent.lowEnergyDiscoveryTimeout(), 20000);
-#elif QT_CONFIG(bluez)
- if (isBluez5Runtime) {
- QCOMPARE(agent.lowEnergyDiscoveryTimeout(), 20000);
- agent.setLowEnergyDiscoveryTimeout(-1); // negative ignored
- QCOMPARE(agent.lowEnergyDiscoveryTimeout(), 20000);
- agent.setLowEnergyDiscoveryTimeout(25000);
- QCOMPARE(agent.lowEnergyDiscoveryTimeout(), 25000);
- } else {
- QCOMPARE(agent.lowEnergyDiscoveryTimeout(), -1);
- agent.setLowEnergyDiscoveryTimeout(20000); // feature not supported -> ignored
- QCOMPARE(agent.lowEnergyDiscoveryTimeout(), -1);
- }
#else
QCOMPARE(agent.lowEnergyDiscoveryTimeout(), -1);
agent.setLowEnergyDiscoveryTimeout(20000); // feature not supported -> ignored
@@ -517,6 +446,9 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_discoveryTimeout()
void tst_QBluetoothDeviceDiscoveryAgent::tst_discoveryMethods()
{
+ if (androidBluetoothEmulator())
+ QSKIP("Skipping test on Android 12+ emulator, CI can timeout waiting for user input");
+
const QBluetoothLocalDevice localDevice;
if (localDevice.allDevices().size() != 1) {
// On iOS it returns 0 but we still have working BT.
@@ -545,7 +477,7 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_discoveryMethods()
QBluetoothDeviceDiscoveryAgent agent;
QSignalSpy finishedSpy(&agent, SIGNAL(finished()));
- QSignalSpy errorSpy(&agent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)));
+ QSignalSpy errorSpy(&agent, SIGNAL(errorOccurred(QBluetoothDeviceDiscoveryAgent::Error)));
QSignalSpy discoveredSpy(&agent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)));
// NoMethod - should just immediately return:
@@ -568,10 +500,15 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_discoveryMethods()
// Start discovery, probably both Classic and LE methods:
agent.start(supportedMethods);
+#if QT_CONFIG(permissions)
+ if (permissionStatus != Qt::PermissionStatus::Granted) {
+ QCOMPARE(agent.error(), QBluetoothDeviceDiscoveryAgent::MissingPermissionsError);
+ QSKIP("The remaining test requires the Bluetooth permission granted");
+ }
+#endif
QVERIFY(agent.isActive());
QVERIFY(errorSpy.isEmpty());
-
#define RUN_DISCOVERY(maxTimeout, step, condition) \
for (int scanTime = maxTimeout; (condition) && scanTime > 0; scanTime -= step) \
QTest::qWait(step);
@@ -589,7 +526,7 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_discoveryMethods()
QVERIFY(supportedMethods == QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
QCOMPARE(agent.error(), QBluetoothDeviceDiscoveryAgent::UnsupportedDiscoveryMethod);
} else {
- QVERIFY(finishedSpy.count() == 1);
+ QVERIFY(finishedSpy.size() == 1);
QVERIFY(agent.error() == QBluetoothDeviceDiscoveryAgent::NoError);
QVERIFY(agent.errorString().isEmpty());
@@ -597,7 +534,9 @@ void tst_QBluetoothDeviceDiscoveryAgent::tst_discoveryMethods()
const QBluetoothDeviceInfo info =
qvariant_cast<QBluetoothDeviceInfo>(discoveredSpy.takeFirst().at(0));
QVERIFY(info.isValid());
- QVERIFY(info.coreConfigurations() & expectedConfiguration);
+ // on Android we do find devices with unknown configuration
+ if (info.coreConfigurations() != QBluetoothDeviceInfo::UnknownCoreConfiguration)
+ QVERIFY(info.coreConfigurations() & expectedConfiguration);
}
}
diff --git a/tests/auto/qbluetoothdeviceinfo/CMakeLists.txt b/tests/auto/qbluetoothdeviceinfo/CMakeLists.txt
new file mode 100644
index 00000000..3b775bfd
--- /dev/null
+++ b/tests/auto/qbluetoothdeviceinfo/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qbluetoothdeviceinfo Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qbluetoothdeviceinfo LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qbluetoothdeviceinfo
+ SOURCES
+ tst_qbluetoothdeviceinfo.cpp
+ LIBRARIES
+ Qt::Bluetooth
+)
diff --git a/tests/auto/qbluetoothdeviceinfo/qbluetoothdeviceinfo.pro b/tests/auto/qbluetoothdeviceinfo/qbluetoothdeviceinfo.pro
deleted file mode 100644
index a12da314..00000000
--- a/tests/auto/qbluetoothdeviceinfo/qbluetoothdeviceinfo.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-SOURCES += tst_qbluetoothdeviceinfo.cpp
-TARGET=tst_qbluetoothdeviceinfo
-CONFIG += testcase
-
-QT = core concurrent bluetooth testlib
diff --git a/tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp b/tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp
index fba65fa1..87487893 100644
--- a/tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp
+++ b/tests/auto/qbluetoothdeviceinfo/tst_qbluetoothdeviceinfo.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -449,15 +424,15 @@ void tst_QBluetoothDeviceInfo::tst_serviceUuids()
QBluetoothDeviceInfo deviceInfo;
QBluetoothDeviceInfo copyInfo = deviceInfo;
- QVector<QBluetoothUuid> servicesList;
- servicesList.append(QBluetoothUuid::L2cap);
- servicesList.append(QBluetoothUuid::Rfcomm);
- QVERIFY(servicesList.count() > 0);
+ QList<QBluetoothUuid> servicesList;
+ servicesList.append(QBluetoothUuid::ProtocolUuid::L2cap);
+ servicesList.append(QBluetoothUuid::ProtocolUuid::Rfcomm);
+ QVERIFY(!servicesList.isEmpty());
deviceInfo.setServiceUuids(servicesList);
- QVERIFY(deviceInfo.serviceUuids().count() > 0);
- deviceInfo.setServiceUuids(QVector<QBluetoothUuid>());
- QCOMPARE(deviceInfo.serviceUuids().count(), 0);
+ QVERIFY(!deviceInfo.serviceUuids().isEmpty());
+ deviceInfo.setServiceUuids(QList<QBluetoothUuid>());
+ QCOMPARE(deviceInfo.serviceUuids().size(), 0);
}
void tst_QBluetoothDeviceInfo::tst_cached()
@@ -528,8 +503,8 @@ void tst_QBluetoothDeviceInfo::tst_manufacturerData()
QVERIFY(!info.setManufacturerData(manufacturerAVM, QByteArray::fromHex("ABCD")));
QCOMPARE(info.manufacturerData(manufacturerAVM), QByteArray::fromHex("ABCD"));
auto temp = info.manufacturerData();
- QCOMPARE(temp.keys().count(), 1);
- QCOMPARE(temp.values().count(), 1);
+ QCOMPARE(temp.keys().size(), 1);
+ QCOMPARE(temp.values().size(), 1);
QCOMPARE(temp.values(), QList<QByteArray>() << QByteArray::fromHex("ABCD"));
QVERIFY(info.setManufacturerData(manufacturerAVM, QByteArray::fromHex("CDEF")));
@@ -537,8 +512,8 @@ void tst_QBluetoothDeviceInfo::tst_manufacturerData()
QVERIFY(!info.setManufacturerData(manufacturerAVM, QByteArray::fromHex("CDEF")));
temp = info.manufacturerData();
- QCOMPARE(temp.keys().count(), 2);
- QCOMPARE(temp.values().count(), 2);
+ QCOMPARE(temp.keys().size(), 2);
+ QCOMPARE(temp.values().size(), 2);
auto list = temp.values();
QCOMPARE(QSet<QByteArray> (list.begin(), list.end()),
diff --git a/tests/auto/qbluetoothhostinfo/CMakeLists.txt b/tests/auto/qbluetoothhostinfo/CMakeLists.txt
new file mode 100644
index 00000000..7ab4e9cb
--- /dev/null
+++ b/tests/auto/qbluetoothhostinfo/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qbluetoothhostinfo Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qbluetoothhostinfo LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qbluetoothhostinfo
+ SOURCES
+ tst_qbluetoothhostinfo.cpp
+ LIBRARIES
+ Qt::Bluetooth
+)
diff --git a/tests/auto/qbluetoothhostinfo/qbluetoothhostinfo.pro b/tests/auto/qbluetoothhostinfo/qbluetoothhostinfo.pro
deleted file mode 100644
index 58776a65..00000000
--- a/tests/auto/qbluetoothhostinfo/qbluetoothhostinfo.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-SOURCES += tst_qbluetoothhostinfo.cpp
-TARGET = tst_qbluetoothhostinfo
-CONFIG += testcase
-
-QT = core concurrent bluetooth testlib
-
diff --git a/tests/auto/qbluetoothhostinfo/tst_qbluetoothhostinfo.cpp b/tests/auto/qbluetoothhostinfo/tst_qbluetoothhostinfo.cpp
index d971caf4..ce03564f 100644
--- a/tests/auto/qbluetoothhostinfo/tst_qbluetoothhostinfo.cpp
+++ b/tests/auto/qbluetoothhostinfo/tst_qbluetoothhostinfo.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
diff --git a/tests/auto/qbluetoothlocaldevice/CMakeLists.txt b/tests/auto/qbluetoothlocaldevice/CMakeLists.txt
new file mode 100644
index 00000000..6b38e25e
--- /dev/null
+++ b/tests/auto/qbluetoothlocaldevice/CMakeLists.txt
@@ -0,0 +1,27 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qbluetoothlocaldevice Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qbluetoothlocaldevice LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qbluetoothlocaldevice
+ SOURCES
+ tst_qbluetoothlocaldevice.cpp
+ LIBRARIES
+ Qt::BluetoothPrivate
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qbluetoothlocaldevice CONDITION MACOS
+ LIBRARIES
+ Qt::Widgets
+)
diff --git a/tests/auto/qbluetoothlocaldevice/qbluetoothlocaldevice.pro b/tests/auto/qbluetoothlocaldevice/qbluetoothlocaldevice.pro
deleted file mode 100644
index 1c4da732..00000000
--- a/tests/auto/qbluetoothlocaldevice/qbluetoothlocaldevice.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-SOURCES += tst_qbluetoothlocaldevice.cpp
-TARGET=tst_qbluetoothlocaldevice
-CONFIG += testcase
-
-QT = core concurrent bluetooth-private testlib
-osx:QT += widgets
diff --git a/tests/auto/qbluetoothlocaldevice/tst_qbluetoothlocaldevice.cpp b/tests/auto/qbluetoothlocaldevice/tst_qbluetoothlocaldevice.cpp
index af7f0354..b434cbff 100644
--- a/tests/auto/qbluetoothlocaldevice/tst_qbluetoothlocaldevice.cpp
+++ b/tests/auto/qbluetoothlocaldevice/tst_qbluetoothlocaldevice.cpp
@@ -1,35 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
#include <QVariant>
+#include "../../shared/bttestutil_p.h"
#include <private/qtbluetoothglobal_p.h>
#include <qbluetoothaddress.h>
@@ -67,15 +43,19 @@ private slots:
void tst_pairingStatus();
void tst_pairDevice_data();
void tst_pairDevice();
+ void tst_connectedDevices();
private:
QBluetoothAddress remoteDevice;
- bool expectRemoteDevice;
+ qsizetype numDevices = 0;
+ bool expectRemoteDevice = false;
};
tst_QBluetoothLocalDevice::tst_QBluetoothLocalDevice()
- : expectRemoteDevice(false)
{
+ if (androidBluetoothEmulator())
+ return;
+ numDevices = QBluetoothLocalDevice::allDevices().size();
const QString remote = qgetenv("BT_TEST_DEVICE");
if (!remote.isEmpty()) {
remoteDevice = QBluetoothAddress(remote);
@@ -84,13 +64,6 @@ tst_QBluetoothLocalDevice::tst_QBluetoothLocalDevice()
} else {
qWarning() << "Not using any remote device for testing. Set BT_TEST_DEVICE env to run manual tests involving a remote device";
}
-
- // start with host powered off
- QBluetoothLocalDevice *device = new QBluetoothLocalDevice();
- device->setHostMode(QBluetoothLocalDevice::HostPoweredOff);
- delete device;
- // wait for the device to switch bluetooth mode.
- QTest::qWait(1000);
}
tst_QBluetoothLocalDevice::~tst_QBluetoothLocalDevice()
@@ -107,70 +80,101 @@ void tst_QBluetoothLocalDevice::initTestCase()
void tst_QBluetoothLocalDevice::tst_powerOn()
{
-#ifdef Q_OS_OSX
+ if (androidBluetoothEmulator())
+ QSKIP("Skipping test on Android 12+ emulator, CI can timeout waiting for user input");
+#ifdef Q_OS_MACOS
QSKIP("Not possible on OS X");
#endif
-#ifdef Q_OS_WIN
- QSKIP("Not possible on Windows");
-#endif
+ if (numDevices == 0)
+ QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
+ if (localDevice.hostMode() != QBluetoothLocalDevice::HostPoweredOff) {
+ // Ensure device is OFF so we can test switching it ON
+ localDevice.setHostMode(QBluetoothLocalDevice::HostPoweredOff);
+ // On Android user may need to authorize the transition, hence a longer timeout
+ QTRY_VERIFY_WITH_TIMEOUT(localDevice.hostMode()
+ == QBluetoothLocalDevice::HostPoweredOff, 15000);
+ // Allow possible mode-change signal(s) to arrive (QTRY_COMPARE polls the
+ // host mode in a loop, and thus may return before the host mode change signal)
+ QTest::qWait(1000);
+ }
QSignalSpy hostModeSpy(&localDevice, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)));
// there should be no changes yet
QVERIFY(hostModeSpy.isValid());
QVERIFY(hostModeSpy.isEmpty());
- if (!QBluetoothLocalDevice::allDevices().count())
- QSKIP("Skipping test due to missing Bluetooth device");
-
localDevice.powerOn();
- // async, wait for it
- QTRY_VERIFY(hostModeSpy.count() > 0);
- QBluetoothLocalDevice::HostMode hostMode= localDevice.hostMode();
- // we should not be powered off
- QVERIFY(hostMode == QBluetoothLocalDevice::HostConnectable
- || hostMode == QBluetoothLocalDevice::HostDiscoverable);
+ // On Android user may need to authorize the transition => longer timeout.
+ QTRY_VERIFY_WITH_TIMEOUT(!hostModeSpy.isEmpty(), 15000);
+ QVERIFY(localDevice.hostMode()
+ != QBluetoothLocalDevice::HostPoweredOff);
}
void tst_QBluetoothLocalDevice::tst_powerOff()
{
-#ifdef Q_OS_OSX
+ if (androidBluetoothEmulator())
+ QSKIP("Skipping test on Android 12+ emulator, CI can timeout waiting for user input");
+#ifdef Q_OS_MACOS
QSKIP("Not possible on OS X");
#endif
-#ifdef Q_OS_WIN
- QSKIP("Not possible on Windows");
-#endif
-
- if (!QBluetoothLocalDevice::allDevices().count())
+ if (numDevices == 0)
QSKIP("Skipping test due to missing Bluetooth device");
- {
- QBluetoothLocalDevice *device = new QBluetoothLocalDevice();
- device->powerOn();
- delete device;
- // wait for the device to switch bluetooth mode.
+ QBluetoothLocalDevice localDevice;
+ if (localDevice.hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
+ // Ensure device is ON so we can test switching it OFF
+ localDevice.powerOn();
+ // On Android user may need to authorize the transition => longer timeout.
+ QTRY_VERIFY_WITH_TIMEOUT(localDevice.hostMode()
+ != QBluetoothLocalDevice::HostPoweredOff, 15000);
+ // Allow possible mode-change signal(s) to arrive (QTRY_COMPARE polls the
+ // host mode in a loop, and thus may return before the host mode change signal)
QTest::qWait(1000);
}
- QBluetoothLocalDevice localDevice;
+
QSignalSpy hostModeSpy(&localDevice, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)));
// there should be no changes yet
QVERIFY(hostModeSpy.isValid());
QVERIFY(hostModeSpy.isEmpty());
localDevice.setHostMode(QBluetoothLocalDevice::HostPoweredOff);
- // async, wait for it
- QTRY_VERIFY(hostModeSpy.count() > 0);
- // we should not be powered off
- QVERIFY(localDevice.hostMode() == QBluetoothLocalDevice::HostPoweredOff);
-
+ // On Android user may need to authorize the transition => longer timeout.
+ QTRY_VERIFY_WITH_TIMEOUT(!hostModeSpy.isEmpty(), 15000);
+ QVERIFY(localDevice.hostMode()
+ == QBluetoothLocalDevice::HostPoweredOff);
}
void tst_QBluetoothLocalDevice::tst_hostModes_data()
{
QTest::addColumn<QBluetoothLocalDevice::HostMode>("hostModeExpected");
QTest::addColumn<bool>("expectSignal");
-
+#if defined(Q_OS_WIN)
+ // On Windows local device does not support HostDiscoverable as a separate mode
+ QTest::newRow("HostPoweredOff1") << QBluetoothLocalDevice::HostPoweredOff << false;
+ QTest::newRow("HostConnectable1") << QBluetoothLocalDevice::HostConnectable << true;
+ QTest::newRow("HostConnectable2") << QBluetoothLocalDevice::HostConnectable << false;
+ QTest::newRow("HostPoweredOff3") << QBluetoothLocalDevice::HostPoweredOff << true;
+ QTest::newRow("HostPoweredOff3") << QBluetoothLocalDevice::HostPoweredOff << false;
+ return;
+#elif defined(Q_OS_ANDROID)
+ if (QNativeInterface::QAndroidApplication::sdkVersion() >= 31) {
+ // On Android-12 (API Level 31+) it seems the device's bluetooth visibility setting
+ // defines if we enter "HostDiscoverable" (visible true) or "HostConnectable"
+ // (visible false). Here we assume that the visibility setting is true. For lower
+ // Android versions the default testdata rows are fine
+ qDebug() << "On this Android version the bluetooth visibility setting is assumed true";
+ QTest::newRow("HostDiscoverable1") << QBluetoothLocalDevice::HostDiscoverable << true;
+ QTest::newRow("HostPoweredOff1") << QBluetoothLocalDevice::HostPoweredOff << true;
+ QTest::newRow("HostPoweredOff2") << QBluetoothLocalDevice::HostPoweredOff << false;
+ QTest::newRow("HostDiscoverable2") << QBluetoothLocalDevice::HostDiscoverable << true;
+ QTest::newRow("HostPoweredOff3") << QBluetoothLocalDevice::HostPoweredOff << true;
+ QTest::newRow("HostDiscoverable3") << QBluetoothLocalDevice::HostDiscoverable << true;
+ QTest::newRow("HostDiscoverable4") << QBluetoothLocalDevice::HostDiscoverable << false;
+ return;
+ }
+#endif
QTest::newRow("HostDiscoverable1") << QBluetoothLocalDevice::HostDiscoverable << true;
QTest::newRow("HostPoweredOff1") << QBluetoothLocalDevice::HostPoweredOff << true;
QTest::newRow("HostPoweredOff2") << QBluetoothLocalDevice::HostPoweredOff << false;
@@ -186,50 +190,66 @@ void tst_QBluetoothLocalDevice::tst_hostModes_data()
void tst_QBluetoothLocalDevice::tst_hostModes()
{
-#ifdef Q_OS_OSX
+ if (androidBluetoothEmulator())
+ QSKIP("Skipping test on Android 12+ emulator, CI can timeout waiting for user input");
+#ifdef Q_OS_MACOS
QSKIP("Not possible on OS X");
#endif
-#ifdef Q_OS_WIN
- QSKIP("Not possible on Windows");
-#endif
-
QFETCH(QBluetoothLocalDevice::HostMode, hostModeExpected);
QFETCH(bool, expectSignal);
- if (!QBluetoothLocalDevice::allDevices().count())
+ if (numDevices == 0)
QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
- QSignalSpy hostModeSpy(&localDevice, SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)));
+
+ static bool firstIteration = true;
+ if (firstIteration) {
+ // On the first iteration establish a known hostmode so that the test
+ // function can reliably test changes to it
+ firstIteration = false;
+ if (localDevice.hostMode() != QBluetoothLocalDevice::HostPoweredOff) {
+ localDevice.setHostMode(QBluetoothLocalDevice::HostPoweredOff);
+ // On Android user may need to authorize the transition => longer timeout.
+ QTRY_VERIFY_WITH_TIMEOUT(localDevice.hostMode()
+ == QBluetoothLocalDevice::HostPoweredOff, 15000);
+ // Allow possible mode-change signal(s) to arrive (QTRY_COMPARE polls the
+ // host mode in a loop, and thus may return before the host mode change signal).
+ QTest::qWait(1000);
+ }
+ }
+
+ QSignalSpy hostModeSpy(&localDevice,
+ SIGNAL(hostModeStateChanged(QBluetoothLocalDevice::HostMode)));
// there should be no changes yet
QVERIFY(hostModeSpy.isValid());
QVERIFY(hostModeSpy.isEmpty());
- QTest::qWait(1000);
+ // Switch the bluetooth mode and verify it changes
localDevice.setHostMode(hostModeExpected);
- // wait for the device to switch bluetooth mode.
+ // Manual interaction may be needed (for example on Android you may
+ // need to authorize a permission) => hence a longer timeout.
+ // If you see a fail on Android here, please see the comment in _data()
+ QTRY_COMPARE_WITH_TIMEOUT(localDevice.hostMode(), hostModeExpected, 15000);
+ // Allow possible mode-change signal(s) to arrive (QTRY_COMPARE polls the
+ // host mode in a loop, and thus may return before the host mode change signal).
QTest::qWait(1000);
- if (hostModeExpected != localDevice.hostMode()) {
- QTRY_VERIFY(hostModeSpy.count() > 0);
- }
- // test the actual signal values.
- if (expectSignal)
- QVERIFY(hostModeSpy.count() > 0);
- else
- QVERIFY(hostModeSpy.count() == 0);
+ // Verify that signals are as expected
if (expectSignal) {
- QList<QVariant> arguments = hostModeSpy.takeLast();
- QBluetoothLocalDevice::HostMode hostMode = qvariant_cast<QBluetoothLocalDevice::HostMode>(arguments.at(0));
- QCOMPARE(hostModeExpected, hostMode);
+ QVERIFY(hostModeSpy.size() > 0);
+ // Verify that the last signal contained the right mode
+ auto arguments = hostModeSpy.takeLast();
+ auto hostMode = qvariant_cast<QBluetoothLocalDevice::HostMode>(arguments.at(0));
+ QCOMPARE(hostMode, hostModeExpected);
+ } else {
+ QCOMPARE(hostModeSpy.size(), 0);
}
- // test actual
- QCOMPARE(hostModeExpected, localDevice.hostMode());
}
void tst_QBluetoothLocalDevice::tst_address()
{
- if (!QBluetoothLocalDevice::allDevices().count())
+ if (numDevices == 0)
QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
@@ -238,7 +258,7 @@ void tst_QBluetoothLocalDevice::tst_address()
}
void tst_QBluetoothLocalDevice::tst_name()
{
- if (!QBluetoothLocalDevice::allDevices().count())
+ if (numDevices == 0)
QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
@@ -246,11 +266,13 @@ void tst_QBluetoothLocalDevice::tst_name()
}
void tst_QBluetoothLocalDevice::tst_isValid()
{
+ if (androidBluetoothEmulator())
+ QSKIP("Skipping test on Android 12+ emulator, CI can timeout waiting for user input");
#if defined(Q_OS_MACOS) || QT_CONFIG(winrt_bt)
// On OS X we can have a valid device (device.isValid() == true),
// that has neither a name nor a valid address - this happens
// if a Bluetooth adapter is OFF.
- if (!QBluetoothLocalDevice::allDevices().count())
+ if (numDevices == 0)
QSKIP("Skipping test due to missing Bluetooth device");
#endif
@@ -258,10 +280,10 @@ void tst_QBluetoothLocalDevice::tst_isValid()
QBluetoothAddress invalidAddress("FF:FF:FF:FF:FF:FF");
const QList<QBluetoothHostInfo> devices = QBluetoothLocalDevice::allDevices();
- if (devices.count()) {
+ if (!devices.isEmpty()) {
QVERIFY(localDevice.isValid());
bool defaultFound = false;
- for (int i = 0; i<devices.count(); i++) {
+ for (qsizetype i = 0; i < devices.size(); ++i) {
QVERIFY(devices.at(i).address() != invalidAddress);
if (devices.at(i).address() == localDevice.address() ) {
defaultFound = true;
@@ -280,14 +302,8 @@ void tst_QBluetoothLocalDevice::tst_isValid()
QVERIFY(!invalidLocalDevice.isValid());
QCOMPARE(invalidLocalDevice.address(), QBluetoothAddress());
QCOMPARE(invalidLocalDevice.name(), QString());
-#if !QT_CONFIG(winrt_bt)
QCOMPARE(invalidLocalDevice.pairingStatus(QBluetoothAddress()), QBluetoothLocalDevice::Unpaired );
QCOMPARE(invalidLocalDevice.hostMode(), QBluetoothLocalDevice::HostPoweredOff);
-#else
- // When QTBUG-62294 is fixed, the pairingStatus part is consistent across platforms
- QCOMPARE(invalidLocalDevice.pairingStatus(QBluetoothAddress()), QBluetoothLocalDevice::Paired);
- QCOMPARE(invalidLocalDevice.hostMode(), QBluetoothLocalDevice::HostConnectable);
-#endif
}
void tst_QBluetoothLocalDevice::tst_allDevices()
@@ -296,7 +312,7 @@ void tst_QBluetoothLocalDevice::tst_allDevices()
}
void tst_QBluetoothLocalDevice::tst_construction()
{
- if (!QBluetoothLocalDevice::allDevices().count())
+ if (numDevices == 0)
QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
@@ -325,49 +341,56 @@ void tst_QBluetoothLocalDevice::tst_pairDevice_data()
<< QBluetoothLocalDevice::Unpaired << 1000 << true;
if (!remoteDevice.isNull()) {
+ // Unpairing is quick but pairing level upgrade requires manual interaction
+ // on both devices. Therefore the timeouts are higher for the changes
+ // which require manual interaction.
QTest::newRow("UnParing Test device 1") << QBluetoothAddress(remoteDevice)
- << QBluetoothLocalDevice::Unpaired << 1000 << false;
+ << QBluetoothLocalDevice::Unpaired << 5000 << false;
//Bluez5 may have to do a device search which can take up to 20s
QTest::newRow("Pairing Test Device") << QBluetoothAddress(remoteDevice)
- << QBluetoothLocalDevice::Paired << 21000 << false;
+ << QBluetoothLocalDevice::Paired << 30000 << false;
QTest::newRow("Pairing upgrade for Authorization") << QBluetoothAddress(remoteDevice)
- << QBluetoothLocalDevice::AuthorizedPaired << 1000 << false;
+ << QBluetoothLocalDevice::AuthorizedPaired << 5000 << false;
QTest::newRow("Unpairing Test device 2") << QBluetoothAddress(remoteDevice)
- << QBluetoothLocalDevice::Unpaired << 1000 << false;
+ << QBluetoothLocalDevice::Unpaired << 5000 << false;
QTest::newRow("Authorized Pairing") << QBluetoothAddress(remoteDevice)
- << QBluetoothLocalDevice::AuthorizedPaired << 10000 << false;
+ << QBluetoothLocalDevice::AuthorizedPaired << 30000 << false;
QTest::newRow("Pairing Test Device after Authorization Pairing") << QBluetoothAddress(remoteDevice)
- << QBluetoothLocalDevice::Paired << 1000 << false;
+ << QBluetoothLocalDevice::Paired << 5000 << false;
+
QTest::newRow("Pairing Test Device after Authorization2") << QBluetoothAddress(remoteDevice)
- << QBluetoothLocalDevice::Paired << 1000 << false; //same again
+ << QBluetoothLocalDevice::Paired << 5000 << false; //same again
QTest::newRow("Unpairing Test device 3") << QBluetoothAddress(remoteDevice)
- << QBluetoothLocalDevice::Unpaired << 1000 << false;
+ << QBluetoothLocalDevice::Unpaired << 5000 << false;
QTest::newRow("UnParing Test device 4") << QBluetoothAddress(remoteDevice)
- << QBluetoothLocalDevice::Unpaired << 1000 << false;
+ << QBluetoothLocalDevice::Unpaired << 5000 << false;
}
}
void tst_QBluetoothLocalDevice::tst_pairDevice()
{
-#ifdef Q_OS_WIN
- QSKIP("Programmatic pairing not supported on Windows");
+ if (androidBluetoothEmulator())
+ QSKIP("Skipping test on Android 12+ emulator, CI can timeout waiting for user input");
+#if defined(Q_OS_MACOS)
+ QSKIP("The pair device test fails on macOS");
#endif
-
QFETCH(QBluetoothAddress, deviceAddress);
QFETCH(QBluetoothLocalDevice::Pairing, pairingExpected);
QFETCH(int, pairingWaitTime);
QFETCH(bool, expectErrorSignal);
- if (!QBluetoothLocalDevice::allDevices().count())
+ if (numDevices == 0)
QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
//powerOn if not already
- localDevice.powerOn();
- QVERIFY(localDevice.hostMode() != QBluetoothLocalDevice::HostPoweredOff);
+ if (localDevice.hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
+ localDevice.powerOn();
+ QTRY_VERIFY(localDevice.hostMode() != QBluetoothLocalDevice::HostPoweredOff);
+ }
QSignalSpy pairingSpy(&localDevice, SIGNAL(pairingFinished(QBluetoothAddress,QBluetoothLocalDevice::Pairing)) );
- QSignalSpy errorSpy(&localDevice, SIGNAL(error(QBluetoothLocalDevice::Error)));
+ QSignalSpy errorSpy(&localDevice, SIGNAL(errorOccurred(QBluetoothLocalDevice::Error)));
// there should be no signals yet
QVERIFY(pairingSpy.isValid());
QVERIFY(pairingSpy.isEmpty());
@@ -377,17 +400,18 @@ void tst_QBluetoothLocalDevice::tst_pairDevice()
QVERIFY(localDevice.isValid());
localDevice.requestPairing(deviceAddress, pairingExpected);
- // async, wait for it
- QTest::qWait(pairingWaitTime);
+ // The above function triggers async interaction with the user on two machines.
+ // Responding takes time. Let's adjust the subsequent timeout dyncamically based on
+ // the need of the operation
if (expectErrorSignal) {
- QTRY_VERIFY(!errorSpy.isEmpty());
+ QTRY_VERIFY_WITH_TIMEOUT(!errorSpy.isEmpty(), pairingWaitTime);
QVERIFY(pairingSpy.isEmpty());
QList<QVariant> arguments = errorSpy.first();
QBluetoothLocalDevice::Error e = qvariant_cast<QBluetoothLocalDevice::Error>(arguments.at(0));
QCOMPARE(e, QBluetoothLocalDevice::PairingError);
} else {
- QTRY_VERIFY(!pairingSpy.isEmpty());
+ QTRY_VERIFY_WITH_TIMEOUT(!pairingSpy.isEmpty(), pairingWaitTime);
QVERIFY(errorSpy.isEmpty());
// test the actual signal values.
@@ -395,11 +419,75 @@ void tst_QBluetoothLocalDevice::tst_pairDevice()
QBluetoothAddress address = qvariant_cast<QBluetoothAddress>(arguments.at(0));
QBluetoothLocalDevice::Pairing pairingResult = qvariant_cast<QBluetoothLocalDevice::Pairing>(arguments.at(1));
QCOMPARE(deviceAddress, address);
- QCOMPARE(pairingExpected, pairingResult);
+ // Verify that the local device pairing status and the signal value match
+ QCOMPARE(pairingResult, localDevice.pairingStatus(deviceAddress));
+#ifndef Q_OS_WIN
+ // On Windows the resulting pairing mode may differ from test's "expected" as the
+ // decision is up to Windows.
+#ifdef Q_OS_ANDROID
+ // On Android we always use "Paired"
+ if (pairingExpected == QBluetoothLocalDevice::AuthorizedPaired)
+ pairingExpected = QBluetoothLocalDevice::Paired;
+#endif
+ QCOMPARE(pairingResult, pairingExpected);
+ QCOMPARE(localDevice.pairingStatus(deviceAddress), pairingExpected);
+#endif
}
+}
+
+void tst_QBluetoothLocalDevice::tst_connectedDevices()
+{
+#if defined(Q_OS_MACOS)
+ QSKIP("The connectedDevices test fails on macOS");
+#endif
+ if (numDevices == 0)
+ QSKIP("Skipping test due to missing Bluetooth device");
+ if (remoteDevice.isNull())
+ QSKIP("This test only makes sense with remote device");
- if (!expectErrorSignal)
- QCOMPARE(pairingExpected, localDevice.pairingStatus(deviceAddress));
+ QBluetoothLocalDevice localDevice;
+ // powerOn if not already
+ if (localDevice.hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
+ localDevice.powerOn();
+ QTRY_VERIFY(localDevice.hostMode() != QBluetoothLocalDevice::HostPoweredOff);
+ }
+
+ QSignalSpy pairingSpy(&localDevice, &QBluetoothLocalDevice::pairingFinished);
+
+ // Make sure that the remote device is not paired
+ localDevice.requestPairing(remoteDevice, QBluetoothLocalDevice::Unpaired);
+ QTRY_VERIFY(!pairingSpy.isEmpty());
+
+ QList<QBluetoothAddress> connectedDevices = localDevice.connectedDevices();
+ QVERIFY(!connectedDevices.contains(remoteDevice));
+
+ QSignalSpy deviceConnectedSpy(&localDevice, &QBluetoothLocalDevice::deviceConnected);
+ QSignalSpy deviceDisconnectedSpy(&localDevice, &QBluetoothLocalDevice::deviceDisconnected);
+
+ // Now pair with the device. We should have a deviceConnected signal.
+ pairingSpy.clear();
+ localDevice.requestPairing(remoteDevice, QBluetoothLocalDevice::Paired);
+ // Manual confirmation for pairing might be required
+ QTRY_VERIFY_WITH_TIMEOUT(!pairingSpy.isEmpty(), 30000);
+ QTRY_VERIFY(!deviceConnectedSpy.isEmpty());
+ QList<QVariant> arguments = deviceConnectedSpy.takeFirst();
+ auto address = arguments.at(0).value<QBluetoothAddress>();
+ QCOMPARE(address, remoteDevice);
+
+ connectedDevices = localDevice.connectedDevices();
+ QVERIFY(connectedDevices.contains(remoteDevice));
+
+ // Unpair again. We should have a deviceDisconnected signal.
+ pairingSpy.clear();
+ localDevice.requestPairing(remoteDevice, QBluetoothLocalDevice::Unpaired);
+ QTRY_VERIFY(!pairingSpy.isEmpty());
+ QTRY_VERIFY(!deviceDisconnectedSpy.isEmpty());
+ arguments = deviceDisconnectedSpy.takeFirst();
+ address = arguments.at(0).value<QBluetoothAddress>();
+ QCOMPARE(address, remoteDevice);
+
+ connectedDevices = localDevice.connectedDevices();
+ QVERIFY(!connectedDevices.contains(remoteDevice));
}
void tst_QBluetoothLocalDevice::tst_pairingStatus_data()
@@ -407,16 +495,9 @@ void tst_QBluetoothLocalDevice::tst_pairingStatus_data()
QTest::addColumn<QBluetoothAddress>("deviceAddress");
QTest::addColumn<QBluetoothLocalDevice::Pairing>("pairingExpected");
-#if !QT_CONFIG(winrt_bt)
QTest::newRow("UnPaired Device: DUMMY") << QBluetoothAddress("11:00:00:00:00:00")
<< QBluetoothLocalDevice::Unpaired;
QTest::newRow("Invalid device") << QBluetoothAddress() << QBluetoothLocalDevice::Unpaired;
-#else
- // Remove special case when QTBUG-62294 is fixed
- QTest::newRow("UnPaired Device: DUMMY") << QBluetoothAddress("11:00:00:00:00:00")
- << QBluetoothLocalDevice::Paired;
- QTest::newRow("Invalid device") << QBluetoothAddress() << QBluetoothLocalDevice::Paired;
-#endif
//valid devices are already tested by tst_pairDevice()
}
@@ -425,7 +506,7 @@ void tst_QBluetoothLocalDevice::tst_pairingStatus()
QFETCH(QBluetoothAddress, deviceAddress);
QFETCH(QBluetoothLocalDevice::Pairing, pairingExpected);
- if (!QBluetoothLocalDevice::allDevices().count())
+ if (numDevices == 0)
QSKIP("Skipping test due to missing Bluetooth device");
QBluetoothLocalDevice localDevice;
diff --git a/tests/auto/qbluetoothserver/CMakeLists.txt b/tests/auto/qbluetoothserver/CMakeLists.txt
new file mode 100644
index 00000000..f1e29b00
--- /dev/null
+++ b/tests/auto/qbluetoothserver/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qbluetoothserver Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qbluetoothserver LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qbluetoothserver
+ SOURCES
+ tst_qbluetoothserver.cpp
+ LIBRARIES
+ Qt::BluetoothPrivate
+)
+
+#### Keys ignored in scope 1:.:.:qbluetoothserver.pro:<TRUE>:
+# OTHER_FILES = "README.txt"
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qbluetoothserver CONDITION MACOS
+ LIBRARIES
+ Qt::Widgets
+)
diff --git a/tests/auto/qbluetoothserver/qbluetoothserver.pro b/tests/auto/qbluetoothserver/qbluetoothserver.pro
deleted file mode 100644
index 7d7eb66b..00000000
--- a/tests/auto/qbluetoothserver/qbluetoothserver.pro
+++ /dev/null
@@ -1,10 +0,0 @@
-SOURCES += tst_qbluetoothserver.cpp
-TARGET = tst_qbluetoothserver
-CONFIG += testcase
-
-QT = core concurrent bluetooth-private testlib
-osx:QT += widgets
-
-OTHER_FILES += \
- README.txt
-
diff --git a/tests/auto/qbluetoothserver/tst_qbluetoothserver.cpp b/tests/auto/qbluetoothserver/tst_qbluetoothserver.cpp
index 4564cf4d..ed56d49a 100644
--- a/tests/auto/qbluetoothserver/tst_qbluetoothserver.cpp
+++ b/tests/auto/qbluetoothserver/tst_qbluetoothserver.cpp
@@ -1,35 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QDebug>
+#include "../../shared/bttestutil_p.h"
#include <private/qtbluetoothglobal_p.h>
#include <qbluetoothserver.h>
#include <qbluetoothsocket.h>
@@ -37,14 +13,8 @@
QT_USE_NAMESPACE
-//same uuid as tests/bttestui
-#define TEST_SERVICE_UUID "e8e10f95-1a70-4b27-9ccf-02010264e9c8"
-
Q_DECLARE_METATYPE(QBluetooth::SecurityFlags)
-// Max time to wait for connection
-static const int MaxConnectTime = 60 * 1000; // 1 minute in ms
-
class tst_QBluetoothServer : public QObject
{
Q_OBJECT
@@ -65,7 +35,7 @@ private slots:
void setHostMode(const QBluetoothAddress &localAdapter, QBluetoothLocalDevice::HostMode newHostMode);
private:
- QBluetoothLocalDevice localDevice;
+ QBluetoothLocalDevice *localDevice = nullptr;
QBluetoothLocalDevice::HostMode initialHostMode;
};
@@ -105,7 +75,7 @@ void tst_QBluetoothServer::setHostMode(const QBluetoothAddress &localAdapter,
}
int connectTime = 5000; // ms
- while (hostModeSpy.count() < 1 && connectTime > 0) {
+ while (hostModeSpy.isEmpty() && connectTime > 0) {
QTest::qWait(500);
connectTime -= 500;
}
@@ -113,30 +83,34 @@ void tst_QBluetoothServer::setHostMode(const QBluetoothAddress &localAdapter,
void tst_QBluetoothServer::initTestCase()
{
+ if (androidBluetoothEmulator())
+ QSKIP("Skipping test on Android 12+ emulator, CI can timeout waiting for user input");
qRegisterMetaType<QBluetooth::SecurityFlags>();
qRegisterMetaType<QBluetoothServer::Error>();
+ localDevice = new QBluetoothLocalDevice(this);
+
QBluetoothLocalDevice device;
if (!device.isValid())
return;
initialHostMode = device.hostMode();
-#ifdef Q_OS_OSX
+#ifdef Q_OS_MACOS
if (initialHostMode == QBluetoothLocalDevice::HostPoweredOff)
return;
#endif
setHostMode(device.address(), QBluetoothLocalDevice::HostConnectable);
- QBluetoothLocalDevice::HostMode hostMode= localDevice.hostMode();
+ QBluetoothLocalDevice::HostMode hostMode= localDevice->hostMode();
QVERIFY(hostMode != QBluetoothLocalDevice::HostPoweredOff);
}
void tst_QBluetoothServer::cleanupTestCase()
{
- QBluetoothLocalDevice device;
- setHostMode(device.address(), initialHostMode);
+ if (localDevice)
+ setHostMode(localDevice->address(), initialHostMode);
}
void tst_QBluetoothServer::tst_construction()
@@ -176,7 +150,7 @@ void tst_QBluetoothServer::tst_receive()
QFETCH(QBluetoothLocalDevice::HostMode, hostmode);
QBluetoothLocalDevice localDev;
-#ifdef Q_OS_OSX
+#ifdef Q_OS_MACOS
if (localDev.hostMode() == QBluetoothLocalDevice::HostPoweredOff)
QSKIP("On OS X this test requires Bluetooth adapter ON");
#endif
@@ -189,23 +163,27 @@ void tst_QBluetoothServer::tst_receive()
setHostMode(address, hostmode);
if (hostmode == QBluetoothLocalDevice::HostPoweredOff) {
-#if !defined(Q_OS_OSX) && !QT_CONFIG(winrt_bt)
- QCOMPARE(localDevice.hostMode(), hostmode);
+#if !defined(Q_OS_MACOS) && !QT_CONFIG(winrt_bt)
+ QCOMPARE(localDevice->hostMode(), hostmode);
#endif
} else {
- QVERIFY(localDevice.hostMode() != QBluetoothLocalDevice::HostPoweredOff);
+ QVERIFY(localDevice->hostMode() != QBluetoothLocalDevice::HostPoweredOff);
}
}
QBluetoothServer server(QBluetoothServiceInfo::RfcommProtocol);
- QSignalSpy errorSpy(&server, SIGNAL(error(QBluetoothServer::Error)));
+ QSignalSpy errorSpy(&server, SIGNAL(errorOccurred(QBluetoothServer::Error)));
bool result = server.listen(address, 20); // port == 20
QTest::qWait(1000);
if (!result) {
+#ifndef Q_OS_ANDROID
+ // Disable address check on Android as an actual device always returns
+ // a valid address, while the emulator doesn't
QCOMPARE(server.serverAddress(), QBluetoothAddress());
+#endif
QCOMPARE(server.serverPort(), quint16(0));
- QVERIFY(errorSpy.count() > 0);
+ QVERIFY(!errorSpy.isEmpty());
QVERIFY(!server.isListening());
if (!localDeviceAvailable) {
QVERIFY(server.error() != QBluetoothServer::NoError);
@@ -219,7 +197,7 @@ void tst_QBluetoothServer::tst_receive()
QVERIFY(result);
#if !QT_CONFIG(winrt_bt)
- QVERIFY(QBluetoothLocalDevice::allDevices().count());
+ QVERIFY(!QBluetoothLocalDevice::allDevices().isEmpty());
#endif
QCOMPARE(server.error(), QBluetoothServer::NoError);
QCOMPARE(server.serverAddress(), address);
diff --git a/tests/auto/qbluetoothservicediscoveryagent/CMakeLists.txt b/tests/auto/qbluetoothservicediscoveryagent/CMakeLists.txt
new file mode 100644
index 00000000..76cd4697
--- /dev/null
+++ b/tests/auto/qbluetoothservicediscoveryagent/CMakeLists.txt
@@ -0,0 +1,39 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qbluetoothservicediscoveryagent Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qbluetoothservicediscoveryagent LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qbluetoothservicediscoveryagent
+ SOURCES
+ tst_qbluetoothservicediscoveryagent.cpp
+ LIBRARIES
+ Qt::Bluetooth
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qbluetoothservicediscoveryagent CONDITION MACOS
+ LIBRARIES
+ Qt::Widgets
+)
+
+set_target_properties(tst_qbluetoothservicediscoveryagent PROPERTIES
+ MACOSX_BUNDLE TRUE
+)
+
+if (APPLE AND NOT IOS)
+ # Ninja has trouble with relative paths, convert to absolute as a workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../shared ABSOLUTE)
+ set_target_properties(tst_qbluetoothservicediscoveryagent PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.macos.plist"
+ )
+endif()
diff --git a/tests/auto/qbluetoothservicediscoveryagent/qbluetoothservicediscoveryagent.pro b/tests/auto/qbluetoothservicediscoveryagent/qbluetoothservicediscoveryagent.pro
deleted file mode 100644
index 7d4eba6f..00000000
--- a/tests/auto/qbluetoothservicediscoveryagent/qbluetoothservicediscoveryagent.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-SOURCES += tst_qbluetoothservicediscoveryagent.cpp
-TARGET = tst_qbluetoothservicediscoveryagent
-CONFIG += testcase
-
-QT = core concurrent bluetooth testlib
-osx:QT += widgets
-
diff --git a/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp b/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp
index 94a065bc..04382467 100644
--- a/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp
+++ b/tests/auto/qbluetoothservicediscoveryagent/tst_qbluetoothservicediscoveryagent.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -32,6 +7,7 @@
#include <QLoggingCategory>
#include <QVariant>
#include <QList>
+#include "../../shared/bttestutil_p.h"
#include <qbluetoothaddress.h>
#include <qbluetoothdevicediscoveryagent.h>
@@ -64,6 +40,7 @@ private slots:
void tst_invalidBtAddress();
void tst_serviceDiscovery_data();
void tst_serviceDiscovery();
+ void tst_serviceDiscoveryStop();
void tst_serviceDiscoveryAdapters();
private:
@@ -74,9 +51,10 @@ private:
tst_QBluetoothServiceDiscoveryAgent::tst_QBluetoothServiceDiscoveryAgent()
{
QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
-
+ if (androidBluetoothEmulator())
+ return;
// start Bluetooth if not started
-#ifndef Q_OS_OSX
+#ifndef Q_OS_MACOS
QBluetoothLocalDevice *device = new QBluetoothLocalDevice();
localDeviceAvailable = device->isValid();
if (localDeviceAvailable) {
@@ -114,36 +92,59 @@ void tst_QBluetoothServiceDiscoveryAgent::serviceError(const QBluetoothServiceDi
void tst_QBluetoothServiceDiscoveryAgent::initTestCase()
{
+ if (androidBluetoothEmulator())
+ QSKIP("Skipping test on Android 12+ emulator, CI can timeout waiting for user input");
+
if (localDeviceAvailable) {
QBluetoothDeviceDiscoveryAgent discoveryAgent;
QSignalSpy finishedSpy(&discoveryAgent, SIGNAL(finished()));
- QSignalSpy errorSpy(&discoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)));
+ QSignalSpy errorSpy(&discoveryAgent,
+ SIGNAL(errorOccurred(QBluetoothDeviceDiscoveryAgent::Error)));
QSignalSpy discoveredSpy(&discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)));
- // connect(&discoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
- // this, SLOT(deviceDiscoveryDebug(QBluetoothDeviceInfo)));
- discoveryAgent.start();
+ discoveryAgent.start(QBluetoothDeviceDiscoveryAgent::ClassicMethod);
// Wait for up to MaxScanTime for the scan to finish
int scanTime = MaxScanTime;
- while (finishedSpy.count() == 0 && scanTime > 0) {
+ while (finishedSpy.isEmpty() && scanTime > 0) {
QTest::qWait(1000);
scanTime -= 1000;
}
- // qDebug() << "Scan time left:" << scanTime;
// Expect finished signal with no error
- QVERIFY(finishedSpy.count() == 1);
+ QVERIFY(finishedSpy.size() == 1);
QVERIFY(errorSpy.isEmpty());
devices = discoveryAgent.discoveredDevices();
}
}
+void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscoveryStop()
+{
+ if (!localDeviceAvailable)
+ QSKIP("This test requires Bluetooth adapter in powered ON state");
+
+ QBluetoothServiceDiscoveryAgent discoveryAgent;
+ QSignalSpy finishedSpy(&discoveryAgent, SIGNAL(finished()));
+ QSignalSpy canceledSpy(&discoveryAgent, SIGNAL(canceled()));
+
+ // Verify we get the correct signals on start-stop
+ discoveryAgent.start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
+ QVERIFY(discoveryAgent.isActive());
+ discoveryAgent.stop();
+ QTRY_COMPARE(canceledSpy.size(), 1);
+ QVERIFY(!discoveryAgent.isActive());
+ // Wait a bit to see that there are no latent signals
+ QTest::qWait(200);
+ QCOMPARE(canceledSpy.size(), 1);
+ QCOMPARE(finishedSpy.size(), 0);
+}
+
+
void tst_QBluetoothServiceDiscoveryAgent::tst_invalidBtAddress()
{
-#ifdef Q_OS_OSX
+#ifdef Q_OS_MACOS
if (!localDeviceAvailable)
QSKIP("On OS X this test requires Bluetooth adapter in powered ON state");
#endif
@@ -156,7 +157,7 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_invalidBtAddress()
discoveryAgent = new QBluetoothServiceDiscoveryAgent(QBluetoothAddress());
QCOMPARE(discoveryAgent->error(), QBluetoothServiceDiscoveryAgent::NoError);
- if (QBluetoothLocalDevice::allDevices().count() > 0) {
+ if (!QBluetoothLocalDevice::allDevices().isEmpty()) {
discoveryAgent->start();
QCOMPARE(discoveryAgent->isActive(), true);
}
@@ -175,6 +176,7 @@ void tst_QBluetoothServiceDiscoveryAgent::serviceDiscoveryDebug(const QBluetooth
qDebug() << "\tRFCOMM server channel:" << info.serverChannel();
}
+#if 0
static void dumpAttributeVariant(const QVariant &var, const QString indent)
{
if (!var.isValid()) {
@@ -182,17 +184,17 @@ static void dumpAttributeVariant(const QVariant &var, const QString indent)
return;
}
- if (var.userType() == qMetaTypeId<QBluetoothServiceInfo::Sequence>()) {
+ if (var.typeId() == qMetaTypeId<QBluetoothServiceInfo::Sequence>()) {
qDebug("%sSequence", indent.toLocal8Bit().constData());
const QBluetoothServiceInfo::Sequence *sequence = static_cast<const QBluetoothServiceInfo::Sequence *>(var.data());
for (const QVariant &v : *sequence)
dumpAttributeVariant(v, indent + '\t');
- } else if (var.userType() == qMetaTypeId<QBluetoothServiceInfo::Alternative>()) {
+ } else if (var.typeId() == qMetaTypeId<QBluetoothServiceInfo::Alternative>()) {
qDebug("%sAlternative", indent.toLocal8Bit().constData());
const QBluetoothServiceInfo::Alternative *alternative = static_cast<const QBluetoothServiceInfo::Alternative *>(var.data());
for (const QVariant &v : *alternative)
dumpAttributeVariant(v, indent + '\t');
- } else if (var.userType() == qMetaTypeId<QBluetoothUuid>()) {
+ } else if (var.typeId() == qMetaTypeId<QBluetoothUuid>()) {
QBluetoothUuid uuid = var.value<QBluetoothUuid>();
switch (uuid.minimumSize()) {
case 0:
@@ -205,27 +207,27 @@ static void dumpAttributeVariant(const QVariant &var, const QString indent)
qDebug("%suuid %08x", indent.toLocal8Bit().constData(), uuid.toUInt32());
break;
case 16: {
- qDebug("%suuid %s", indent.toLocal8Bit().constData(), QByteArray(reinterpret_cast<const char *>(uuid.toUInt128().data), 16).toHex().constData());
+ qDebug("%suuid %s", indent.toLocal8Bit().constData(), uuid.toByteArray(QUuid::Id128).constData());
break;
}
default:
qDebug("%suuid ???", indent.toLocal8Bit().constData());
}
} else {
- switch (var.userType()) {
- case QVariant::UInt:
+ switch (var.typeId()) {
+ case QMetaType::UInt:
qDebug("%suint %u", indent.toLocal8Bit().constData(), var.toUInt());
break;
- case QVariant::Int:
+ case QMetaType::Int:
qDebug("%sint %d", indent.toLocal8Bit().constData(), var.toInt());
break;
- case QVariant::String:
+ case QMetaType::QString:
qDebug("%sstring %s", indent.toLocal8Bit().constData(), var.toString().toLocal8Bit().constData());
break;
- case QVariant::Bool:
+ case QMetaType::Bool:
qDebug("%sbool %d", indent.toLocal8Bit().constData(), var.toBool());
break;
- case QVariant::Url:
+ case QMetaType::QUrl:
qDebug("%surl %s", indent.toLocal8Bit().constData(), var.toUrl().toString().toLocal8Bit().constData());
break;
default:
@@ -241,6 +243,7 @@ static inline void dumpServiceInfoAttributes(const QBluetoothServiceInfo &info)
dumpAttributeVariant(info.attribute(id), QString("\t"));
}
}
+#endif
void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery_data()
@@ -254,15 +257,15 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery_data()
// Only need to test the first 5 live devices
int max = 5;
- for (const QBluetoothDeviceInfo &info : qAsConst(devices)) {
+ for (const QBluetoothDeviceInfo &info : std::as_const(devices)) {
if (info.isCached())
continue;
QTest::newRow("default filter") << info << QList<QBluetoothUuid>()
<< QBluetoothServiceDiscoveryAgent::NoError;
if (!--max)
break;
- //QTest::newRow("public browse group") << info << (QList<QBluetoothUuid>() << QBluetoothUuid::PublicBrowseGroup);
- //QTest::newRow("l2cap") << info << (QList<QBluetoothUuid>() << QBluetoothUuid::L2cap);
+ //QTest::newRow("public browse group") << info << (QList<QBluetoothUuid>() << QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup);
+ //QTest::newRow("l2cap") << info << (QList<QBluetoothUuid>() << QBluetoothUuid::ProtocolUuid::L2cap);
}
QTest::newRow("all devices") << QBluetoothDeviceInfo() << QList<QBluetoothUuid>()
<< QBluetoothServiceDiscoveryAgent::NoError;
@@ -271,28 +274,28 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery_data()
void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscoveryAdapters()
{
QBluetoothLocalDevice localDevice;
- int numberOfAdapters = (localDevice.allDevices()).size();
- if (numberOfAdapters>1) {
+ const QList<QBluetoothHostInfo> adapters = localDevice.allDevices();
+ if (adapters.size() > 1) {
if (devices.isEmpty())
QSKIP("This test requires an in-range bluetooth device");
- QList<QBluetoothAddress> addresses;
+ QVarLengthArray<QBluetoothAddress> addresses;
- for (int i=0; i<numberOfAdapters; i++) {
- addresses.append(((QBluetoothHostInfo)localDevice.allDevices().at(i)).address());
+ for (const auto &adapter : adapters) {
+ addresses.append(adapter.address());
}
QBluetoothServer server(QBluetoothServiceInfo::RfcommProtocol);
- QBluetoothUuid uuid(QBluetoothUuid::Ftp);
+ QBluetoothUuid uuid(QBluetoothUuid::ProtocolUuid::Ftp);
server.listen(addresses[0]);
QBluetoothServiceInfo serviceInfo;
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceName, "serviceName");
QBluetoothServiceInfo::Sequence publicBrowse;
- publicBrowse << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup));
+ publicBrowse << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup));
serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, publicBrowse);
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,
@@ -302,11 +305,11 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscoveryAdapters()
QBluetoothServiceInfo::Sequence protocolDescriptorList;
QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::L2cap));
protocolDescriptorList.append(QVariant::fromValue(protocol));
protocol.clear();
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm))
<< QVariant::fromValue(quint8(server.serverPort()));
protocolDescriptorList.append(QVariant::fromValue(protocol));
@@ -329,22 +332,20 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscoveryAdapters()
discoveryAgent.start();
int scanTime = MaxScanTime;
- while (finishedSpy.count() == 0 && scanTime > 0) {
+ while (finishedSpy.isEmpty() && scanTime > 0) {
QTest::qWait(1000);
scanTime -= 1000;
}
- QList<QBluetoothServiceInfo> discServices = discoveryAgent.discoveredServices();
+ const QList<QBluetoothServiceInfo> discServices = discoveryAgent.discoveredServices();
QVERIFY(!discServices.empty());
- int counter = 0;
- for (int i = 0; i<discServices.size(); i++)
- {
- QBluetoothServiceInfo service((QBluetoothServiceInfo)discServices.at(i));
+ qsizetype counter = 0;
+ for (const QBluetoothServiceInfo &service : discServices) {
if (uuid == service.serviceUuid())
counter++;
}
- QVERIFY(counter == 1);
+ QCOMPARE(counter, 1);
}
}
@@ -352,9 +353,6 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscoveryAdapters()
void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery()
{
- // Not all devices respond to SDP, so allow for a failure
- static int expected_failures = 0;
-
if (devices.isEmpty())
QSKIP("This test requires an in-range bluetooth device");
@@ -363,7 +361,7 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery()
QFETCH(QBluetoothServiceDiscoveryAgent::Error, serviceDiscoveryError);
QBluetoothLocalDevice localDevice;
- qDebug() << "Scanning address" << deviceInfo.address().toString();
+ qDebug() << "Scanning address" << deviceInfo.address().toString() << deviceInfo.name();
QBluetoothServiceDiscoveryAgent discoveryAgent(localDevice.address());
bool setAddress = discoveryAgent.setRemoteAddress(deviceInfo.address());
@@ -380,12 +378,11 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery()
QVERIFY(discoveryAgent.uuidFilter() == uuidFilter);
QSignalSpy finishedSpy(&discoveryAgent, SIGNAL(finished()));
- QSignalSpy errorSpy(&discoveryAgent, SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error)));
+ QSignalSpy errorSpy(&discoveryAgent,
+ SIGNAL(errorOccurred(QBluetoothServiceDiscoveryAgent::Error)));
QSignalSpy discoveredSpy(&discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)));
-// connect(&discoveryAgent, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)),
-// this, SLOT(serviceDiscoveryDebug(QBluetoothServiceInfo)));
- connect(&discoveryAgent, SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error)),
- this, SLOT(serviceError(QBluetoothServiceDiscoveryAgent::Error)));
+ connect(&discoveryAgent, SIGNAL(errorOccurred(QBluetoothServiceDiscoveryAgent::Error)), this,
+ SLOT(serviceError(QBluetoothServiceDiscoveryAgent::Error)));
discoveryAgent.start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
@@ -396,13 +393,13 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery()
QVERIFY(discoveryAgent.isActive() || !finishedSpy.isEmpty());
// Wait for up to MaxScanTime for the scan to finish
- int scanTime = MaxScanTime;
- while (finishedSpy.count() == 0 && scanTime > 0) {
+ int scanTime = 20000;
+ while (finishedSpy.isEmpty() && scanTime > 0) {
QTest::qWait(1000);
scanTime -= 1000;
}
- if (discoveryAgent.error() && expected_failures++ < 2){
+ if (discoveryAgent.error()) {
qDebug() << "Device failed to respond to SDP, skipping device" << discoveryAgent.error() << discoveryAgent.errorString();
return;
}
@@ -411,12 +408,14 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery()
QVERIFY(discoveryAgent.errorString() == QString());
// Expect finished signal with no error
- QVERIFY(finishedSpy.count() == 1);
+ if (scanTime)
+ QVERIFY(finishedSpy.size() == 1);
+
QVERIFY(errorSpy.isEmpty());
- //if (discoveryAgent.discoveredServices().count() && expected_failures++ <2){
- if (discoveredSpy.isEmpty() && expected_failures++ < 2){
- qDebug() << "Device failed to return any results, skipping device" << discoveryAgent.discoveredServices().count();
+ //if (!discoveryAgent.discoveredServices().isEmpty() && expected_failures++ <2){
+ if (discoveredSpy.isEmpty()) {
+ qDebug() << "Device failed to return any results, skipping device" << discoveryAgent.discoveredServices().size();
return;
}
@@ -451,9 +450,9 @@ void tst_QBluetoothServiceDiscoveryAgent::tst_serviceDiscovery()
}
if (servicesFound)
- QVERIFY(discoveryAgent.discoveredServices().count() != 0);
+ QVERIFY(!discoveryAgent.discoveredServices().isEmpty());
discoveryAgent.clear();
- QVERIFY(discoveryAgent.discoveredServices().count() == 0);
+ QVERIFY(discoveryAgent.discoveredServices().isEmpty());
discoveryAgent.stop();
QVERIFY(!discoveryAgent.isActive());
diff --git a/tests/auto/qbluetoothserviceinfo/CMakeLists.txt b/tests/auto/qbluetoothserviceinfo/CMakeLists.txt
new file mode 100644
index 00000000..6974a03a
--- /dev/null
+++ b/tests/auto/qbluetoothserviceinfo/CMakeLists.txt
@@ -0,0 +1,32 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qbluetoothserviceinfo Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qbluetoothserviceinfo LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qbluetoothserviceinfo
+ SOURCES
+ tst_qbluetoothserviceinfo.cpp
+ LIBRARIES
+ Qt::Bluetooth
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qbluetoothserviceinfo CONDITION MACOS
+ LIBRARIES
+ Qt::Widgets
+)
+
+qt_internal_extend_target(tst_qbluetoothserviceinfo CONDITION ANDROID AND NOT ANDROID_EMBEDDED
+ DEFINES
+ QT_ANDROID_BLUETOOTH
+)
diff --git a/tests/auto/qbluetoothserviceinfo/qbluetoothserviceinfo.pro b/tests/auto/qbluetoothserviceinfo/qbluetoothserviceinfo.pro
deleted file mode 100644
index 6a072784..00000000
--- a/tests/auto/qbluetoothserviceinfo/qbluetoothserviceinfo.pro
+++ /dev/null
@@ -1,11 +0,0 @@
-SOURCES += tst_qbluetoothserviceinfo.cpp
-TARGET = tst_qbluetoothserviceinfo
-CONFIG += testcase
-
-QT = core concurrent bluetooth testlib
-osx:QT += widgets
-
-
-android:!android-embedded {
- DEFINES += QT_ANDROID_BLUETOOTH
-}
diff --git a/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp b/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp
index f89802d2..11d1dd48 100644
--- a/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp
+++ b/tests/auto/qbluetoothserviceinfo/tst_qbluetoothserviceinfo.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QUuid>
@@ -38,6 +13,8 @@
#include <qbluetoothuuid.h>
#include <QtBluetooth/QBluetoothServer>
+#include <QtCore/qoperatingsystemversion.h>
+
QT_USE_NAMESPACE
Q_DECLARE_METATYPE(QBluetoothUuid::ProtocolUuid)
@@ -78,10 +55,6 @@ void tst_QBluetoothServiceInfo::initTestCase()
qRegisterMetaType<QBluetoothUuid::ProtocolUuid>();
qRegisterMetaType<QUuid>();
qRegisterMetaType<QBluetoothServiceInfo::Protocol>();
- // start Bluetooth if not started
- QBluetoothLocalDevice *device = new QBluetoothLocalDevice();
- device->powerOn();
- delete device;
}
void tst_QBluetoothServiceInfo::tst_construction()
@@ -93,31 +66,31 @@ void tst_QBluetoothServiceInfo::tst_construction()
QList<QBluetoothUuid::ProtocolUuid> protUuids;
//list taken from qbluetoothuuid.h
- protUuids << QBluetoothUuid::Sdp;
- protUuids << QBluetoothUuid::Udp;
- protUuids << QBluetoothUuid::Rfcomm;
- protUuids << QBluetoothUuid::Tcp;
- protUuids << QBluetoothUuid::TcsBin;
- protUuids << QBluetoothUuid::TcsAt;
- protUuids << QBluetoothUuid::Att;
- protUuids << QBluetoothUuid::Obex;
- protUuids << QBluetoothUuid::Ip;
- protUuids << QBluetoothUuid::Ftp;
- protUuids << QBluetoothUuid::Http;
- protUuids << QBluetoothUuid::Wsp;
- protUuids << QBluetoothUuid::Bnep;
- protUuids << QBluetoothUuid::Upnp;
- protUuids << QBluetoothUuid::Hidp;
- protUuids << QBluetoothUuid::HardcopyControlChannel;
- protUuids << QBluetoothUuid::HardcopyDataChannel;
- protUuids << QBluetoothUuid::HardcopyNotification;
- protUuids << QBluetoothUuid::Avctp;
- protUuids << QBluetoothUuid::Avdtp;
- protUuids << QBluetoothUuid::Cmtp;
- protUuids << QBluetoothUuid::UdiCPlain;
- protUuids << QBluetoothUuid::McapControlChannel;
- protUuids << QBluetoothUuid::McapDataChannel;
- protUuids << QBluetoothUuid::L2cap;
+ protUuids << QBluetoothUuid::ProtocolUuid::Sdp;
+ protUuids << QBluetoothUuid::ProtocolUuid::Udp;
+ protUuids << QBluetoothUuid::ProtocolUuid::Rfcomm;
+ protUuids << QBluetoothUuid::ProtocolUuid::Tcp;
+ protUuids << QBluetoothUuid::ProtocolUuid::TcsBin;
+ protUuids << QBluetoothUuid::ProtocolUuid::TcsAt;
+ protUuids << QBluetoothUuid::ProtocolUuid::Att;
+ protUuids << QBluetoothUuid::ProtocolUuid::Obex;
+ protUuids << QBluetoothUuid::ProtocolUuid::Ip;
+ protUuids << QBluetoothUuid::ProtocolUuid::Ftp;
+ protUuids << QBluetoothUuid::ProtocolUuid::Http;
+ protUuids << QBluetoothUuid::ProtocolUuid::Wsp;
+ protUuids << QBluetoothUuid::ProtocolUuid::Bnep;
+ protUuids << QBluetoothUuid::ProtocolUuid::Upnp;
+ protUuids << QBluetoothUuid::ProtocolUuid::Hidp;
+ protUuids << QBluetoothUuid::ProtocolUuid::HardcopyControlChannel;
+ protUuids << QBluetoothUuid::ProtocolUuid::HardcopyDataChannel;
+ protUuids << QBluetoothUuid::ProtocolUuid::HardcopyNotification;
+ protUuids << QBluetoothUuid::ProtocolUuid::Avctp;
+ protUuids << QBluetoothUuid::ProtocolUuid::Avdtp;
+ protUuids << QBluetoothUuid::ProtocolUuid::Cmtp;
+ protUuids << QBluetoothUuid::ProtocolUuid::UdiCPlain;
+ protUuids << QBluetoothUuid::ProtocolUuid::McapControlChannel;
+ protUuids << QBluetoothUuid::ProtocolUuid::McapDataChannel;
+ protUuids << QBluetoothUuid::ProtocolUuid::L2cap;
{
QBluetoothServiceInfo serviceInfo;
@@ -129,13 +102,13 @@ void tst_QBluetoothServiceInfo::tst_construction()
QCOMPARE(serviceInfo.serviceDescription(), QString());
QCOMPARE(serviceInfo.serviceProvider(), QString());
QCOMPARE(serviceInfo.serviceUuid(), QBluetoothUuid());
- QCOMPARE(serviceInfo.serviceClassUuids().count(), 0);
- QCOMPARE(serviceInfo.attributes().count(), 0);
+ QCOMPARE(serviceInfo.serviceClassUuids().size(), 0);
+ QCOMPARE(serviceInfo.attributes().size(), 0);
QCOMPARE(serviceInfo.serverChannel(), -1);
QCOMPARE(serviceInfo.protocolServiceMultiplexer(), -1);
- for (QBluetoothUuid::ProtocolUuid u : qAsConst(protUuids))
- QCOMPARE(serviceInfo.protocolDescriptor(u).count(), 0);
+ for (QBluetoothUuid::ProtocolUuid u : std::as_const(protUuids))
+ QCOMPARE(serviceInfo.protocolDescriptor(u).size(), 0);
}
{
@@ -168,10 +141,10 @@ void tst_QBluetoothServiceInfo::tst_construction()
QCOMPARE(copyInfo.device().address(), alternatedeviceInfo.address());
QCOMPARE(serviceInfo.device().address(), alternatedeviceInfo.address());
- for (QBluetoothUuid::ProtocolUuid u : qAsConst(protUuids))
- QCOMPARE(serviceInfo.protocolDescriptor(u).count(), 0);
- for (QBluetoothUuid::ProtocolUuid u : qAsConst(protUuids))
- QCOMPARE(copyInfo.protocolDescriptor(u).count(), 0);
+ for (QBluetoothUuid::ProtocolUuid u : std::as_const(protUuids))
+ QCOMPARE(serviceInfo.protocolDescriptor(u).size(), 0);
+ for (QBluetoothUuid::ProtocolUuid u : std::as_const(protUuids))
+ QCOMPARE(copyInfo.protocolDescriptor(u).size(), 0);
}
}
@@ -187,12 +160,17 @@ void tst_QBluetoothServiceInfo::tst_assignment_data()
#if defined(QT_ANDROID_BLUETOOTH) || defined(Q_OS_WIN)
l2cpSupported = false;
#endif
+
+#if defined(Q_OS_MACOS)
+ l2cpSupported = QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMonterey;
+#endif
+
QTest::newRow("assignment_data_l2cp")
<< QUuid(0x67c8770b, 0x44f1, 0x410a, 0xab, 0x9a, 0xf9, 0xb5, 0x44, 0x6f, 0x13, 0xee)
- << QBluetoothUuid::L2cap << QBluetoothServiceInfo::L2capProtocol << l2cpSupported;
+ << QBluetoothUuid::ProtocolUuid::L2cap << QBluetoothServiceInfo::L2capProtocol << l2cpSupported;
QTest::newRow("assignment_data_rfcomm")
<< QUuid(0x67c8770b, 0x44f1, 0x410a, 0xab, 0x9a, 0xf9, 0xb5, 0x44, 0x6f, 0x13, 0xee)
- << QBluetoothUuid::Rfcomm << QBluetoothServiceInfo::RfcommProtocol << true;
+ << QBluetoothUuid::ProtocolUuid::Rfcomm << QBluetoothServiceInfo::RfcommProtocol << true;
}
@@ -279,7 +257,7 @@ void tst_QBluetoothServiceInfo::tst_assignment()
copyInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, QBluetoothUuid(uuid));
QVERIFY(copyInfo.contains(QBluetoothServiceInfo::ProtocolDescriptorList));
QVERIFY(copyInfo.isComplete());
- QVERIFY(copyInfo.attributes().count() > 0);
+ QVERIFY(!copyInfo.attributes().isEmpty());
copyInfo.removeAttribute(QBluetoothServiceInfo::ProtocolDescriptorList);
QVERIFY(!copyInfo.contains(QBluetoothServiceInfo::ProtocolDescriptorList));
@@ -319,11 +297,22 @@ void tst_QBluetoothServiceInfo::tst_assignment()
QVERIFY(!copyInfo.isValid());
copyInfo = serviceInfo;
- copyInfo.setServiceUuid(QBluetoothUuid::SerialPort);
+ copyInfo.setServiceUuid(QBluetoothUuid::ServiceClassUuid::SerialPort);
QVERIFY(!copyInfo.isRegistered());
- if (!QBluetoothLocalDevice::allDevices().count()) {
- QSKIP("Skipping test due to missing Bluetooth device");
+ // start Bluetooth if not started
+ QBluetoothLocalDevice device;
+ if (device.isValid()) {
+ device.powerOn();
+ int waitPowerOnMs = 1000;
+ while (device.hostMode() == QBluetoothLocalDevice::HostPoweredOff && waitPowerOnMs) {
+ QTest::qWait(100);
+ waitPowerOnMs -= 100;
+ }
+ }
+
+ if (device.hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
+ QSKIP("Skipping test due to missing or powered OFF Bluetooth device");
} else if (protocolSupported) {
QBluetoothServer server(serviceInfoProtocol);
QVERIFY(server.listen());
@@ -332,7 +321,7 @@ void tst_QBluetoothServiceInfo::tst_assignment()
QBluetoothServiceInfo::Sequence protocolDescriptorList;
QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::L2cap));
if (serviceInfoProtocol == QBluetoothServiceInfo::L2capProtocol) {
protocol << QVariant::fromValue(server.serverPort());
@@ -340,7 +329,7 @@ void tst_QBluetoothServiceInfo::tst_assignment()
} else if (serviceInfoProtocol == QBluetoothServiceInfo::RfcommProtocol) {
protocolDescriptorList.append(QVariant::fromValue(protocol));
protocol.clear();
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm))
<< QVariant::fromValue(quint8(server.serverPort()));
protocolDescriptorList.append(QVariant::fromValue(protocol));
}
@@ -348,6 +337,19 @@ void tst_QBluetoothServiceInfo::tst_assignment()
serviceInfo.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList,
protocolDescriptorList);
+#if defined(Q_OS_MACOS)
+ // bluetoothd on Monterey does not want to register a record if there is no
+ // ServiceClassIDList provided.
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMonterey) {
+ // Nothing seems to help with L2CAP though:
+ if (serviceInfoProtocol == QBluetoothServiceInfo::RfcommProtocol) {
+ QBluetoothServiceInfo::Sequence classIds;
+ classIds << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
+ copyInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classIds);
+ }
+ }
+#endif // Q_OS_MACOS
+
QVERIFY(copyInfo.registerService());
QVERIFY(copyInfo.isRegistered());
QVERIFY(serviceInfo.isRegistered());
@@ -369,22 +371,22 @@ void tst_QBluetoothServiceInfo::tst_assignment()
void tst_QBluetoothServiceInfo::tst_serviceClassUuids()
{
QBluetoothServiceInfo info;
- QCOMPARE(info.serviceClassUuids().count(), 0);
+ QCOMPARE(info.serviceClassUuids().size(), 0);
QBluetoothServiceInfo::Sequence classIds;
- classIds << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
- QCOMPARE(classIds.count(), 1);
+ classIds << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
+ QCOMPARE(classIds.size(), 1);
QBluetoothUuid uuid(QString("e8e10f95-1a70-4b27-9ccf-02010264e9c8"));
classIds.prepend(QVariant::fromValue(uuid));
- QCOMPARE(classIds.count(), 2);
+ QCOMPARE(classIds.size(), 2);
QCOMPARE(classIds.at(0).value<QBluetoothUuid>(), uuid);
info.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classIds);
QList<QBluetoothUuid> svclids = info.serviceClassUuids();
- QCOMPARE(svclids.count(), 2);
+ QCOMPARE(svclids.size(), 2);
QCOMPARE(svclids.at(0), uuid);
- QCOMPARE(svclids.at(1), QBluetoothUuid(QBluetoothUuid::SerialPort));
+ QCOMPARE(svclids.at(1), QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
}
static QByteArray debugOutput;
diff --git a/tests/auto/qbluetoothsocket/CMakeLists.txt b/tests/auto/qbluetoothsocket/CMakeLists.txt
new file mode 100644
index 00000000..59b6a8f2
--- /dev/null
+++ b/tests/auto/qbluetoothsocket/CMakeLists.txt
@@ -0,0 +1,39 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qbluetoothsocket Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qbluetoothsocket LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qbluetoothsocket
+ SOURCES
+ tst_qbluetoothsocket.cpp
+ LIBRARIES
+ Qt::BluetoothPrivate
+ Qt::Network
+)
+
+#### Keys ignored in scope 1:.:.:qbluetoothsocket.pro:<TRUE>:
+# OTHER_FILES = "README.txt"
+# testcase.timeout = "250"
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qbluetoothsocket CONDITION MACOS
+ DEFINES
+ QT_OSX_BLUETOOTH
+ LIBRARIES
+ Qt::Widgets
+)
+
+qt_internal_extend_target(tst_qbluetoothsocket CONDITION ANDROID AND NOT ANDROID_EMBEDDED
+ DEFINES
+ QT_ANDROID_BLUETOOTH
+)
diff --git a/tests/auto/qbluetoothsocket/qbluetoothsocket.pro b/tests/auto/qbluetoothsocket/qbluetoothsocket.pro
deleted file mode 100644
index 83bc417c..00000000
--- a/tests/auto/qbluetoothsocket/qbluetoothsocket.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-SOURCES += tst_qbluetoothsocket.cpp
-TARGET = tst_qbluetoothsocket
-CONFIG += testcase
-testcase.timeout = 250 # this test is slow
-
-QT = core concurrent network bluetooth-private testlib
-osx:QT += widgets
-
-OTHER_FILES += \
- README.txt
-
-osx {
- DEFINES += QT_OSX_BLUETOOTH
-} else:android:!android-embedded {
- DEFINES += QT_ANDROID_BLUETOOTH
-}
diff --git a/tests/auto/qbluetoothsocket/tst_qbluetoothsocket.cpp b/tests/auto/qbluetoothsocket/tst_qbluetoothsocket.cpp
index 05bc1a0f..d88e64e7 100644
--- a/tests/auto/qbluetoothsocket/tst_qbluetoothsocket.cpp
+++ b/tests/auto/qbluetoothsocket/tst_qbluetoothsocket.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -35,6 +10,9 @@
#include <qbluetoothserviceinfo.h>
#include <qbluetoothservicediscoveryagent.h>
#include <qbluetoothlocaldevice.h>
+#if QT_CONFIG(bluez)
+#include <QtBluetooth/private/bluez5_helper_p.h>
+#endif
QT_USE_NAMESPACE
@@ -115,7 +93,7 @@ void tst_QBluetoothSocket::initTestCase()
{
// setup Bluetooth env
const QList<QBluetoothHostInfo> foundDevices = QBluetoothLocalDevice::allDevices();
- if (!foundDevices.count()) {
+ if (foundDevices.isEmpty()) {
qWarning() << "Missing local device";
return;
} else {
@@ -136,13 +114,14 @@ void tst_QBluetoothSocket::initTestCase()
// Go find the server
QBluetoothServiceDiscoveryAgent *sda = new QBluetoothServiceDiscoveryAgent(this);
connect(sda, SIGNAL(serviceDiscovered(QBluetoothServiceInfo)), this, SLOT(serviceDiscovered(QBluetoothServiceInfo)));
- connect(sda, SIGNAL(error(QBluetoothServiceDiscoveryAgent::Error)), this, SLOT(error(QBluetoothServiceDiscoveryAgent::Error)));
+ connect(sda, SIGNAL(errorOccurred(QBluetoothServiceDiscoveryAgent::Error)), this,
+ SLOT(error(QBluetoothServiceDiscoveryAgent::Error)));
connect(sda, SIGNAL(finished()), this, SLOT(finished()));
qDebug() << "Starting discovery";
sda->setUuidFilter(QBluetoothUuid(QString(TEST_SERVICE_UUID)));
- sda->start(QBluetoothServiceDiscoveryAgent::MinimalDiscovery);
+ sda->start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
for (int connectTime = MaxConnectTime; !done_discovery && connectTime > 0; connectTime -= 1000)
QTest::qWait(1000);
@@ -196,12 +175,12 @@ void tst_QBluetoothSocket::tst_construction()
QBluetoothSocket socket;
QCOMPARE(socket.socketType(), QBluetoothServiceInfo::UnknownProtocol);
- QCOMPARE(socket.error(), QBluetoothSocket::NoSocketError);
+ QCOMPARE(socket.error(), QBluetoothSocket::SocketError::NoSocketError);
QCOMPARE(socket.errorString(), QString());
QCOMPARE(socket.peerAddress(), QBluetoothAddress());
QCOMPARE(socket.peerName(), QString());
QCOMPARE(socket.peerPort(), quint16(0));
- QCOMPARE(socket.state(), QBluetoothSocket::UnconnectedState);
+ QCOMPARE(socket.state(), QBluetoothSocket::SocketState::UnconnectedState);
QCOMPARE(socket.socketDescriptor(), -1);
QCOMPARE(socket.bytesAvailable(), 0);
QCOMPARE(socket.bytesToWrite(), 0);
@@ -240,11 +219,11 @@ void tst_QBluetoothSocket::tst_serviceConnection()
QSignalSpy stateSpy(&socket, SIGNAL(stateChanged(QBluetoothSocket::SocketState)));
QCOMPARE(socket.socketType(), QBluetoothServiceInfo::UnknownProtocol);
- QCOMPARE(socket.state(), QBluetoothSocket::UnconnectedState);
+ QCOMPARE(socket.state(), QBluetoothSocket::SocketState::UnconnectedState);
/* Connection */
QSignalSpy connectedSpy(&socket, SIGNAL(connected()));
- QSignalSpy errorSpy(&socket, SIGNAL(error(QBluetoothSocket::SocketError)));
+ QSignalSpy errorSpy(&socket, SIGNAL(errorOccurred(QBluetoothSocket::SocketError)));
QCOMPARE(socket.openMode(), QIODevice::NotOpen);
QCOMPARE(socket.isWritable(), false);
@@ -253,26 +232,26 @@ void tst_QBluetoothSocket::tst_serviceConnection()
socket.connectToService(remoteServiceInfo);
- QCOMPARE(stateSpy.count(), 1);
- QCOMPARE(stateSpy.takeFirst().at(0).value<QBluetoothSocket::SocketState>(), QBluetoothSocket::ConnectingState);
- QCOMPARE(socket.state(), QBluetoothSocket::ConnectingState);
+ QCOMPARE(stateSpy.size(), 1);
+ QCOMPARE(stateSpy.takeFirst().at(0).value<QBluetoothSocket::SocketState>(), QBluetoothSocket::SocketState::ConnectingState);
+ QCOMPARE(socket.state(), QBluetoothSocket::SocketState::ConnectingState);
stateSpy.clear();
int connectTime = MaxConnectTime;
- while (connectedSpy.count() == 0 && errorSpy.count() == 0 && connectTime > 0) {
+ while (connectedSpy.isEmpty() && errorSpy.isEmpty() && connectTime > 0) {
QTest::qWait(1000);
connectTime -= 1000;
}
- if (errorSpy.count() != 0) {
+ if (!errorSpy.isEmpty()) {
qDebug() << errorSpy.takeFirst().at(0).toInt();
QSKIP("Connection error");
}
- QCOMPARE(connectedSpy.count(), 1);
- QCOMPARE(stateSpy.count(), 1);
- QCOMPARE(stateSpy.takeFirst().at(0).value<QBluetoothSocket::SocketState>(), QBluetoothSocket::ConnectedState);
- QCOMPARE(socket.state(), QBluetoothSocket::ConnectedState);
+ QCOMPARE(connectedSpy.size(), 1);
+ QCOMPARE(stateSpy.size(), 1);
+ QCOMPARE(stateSpy.takeFirst().at(0).value<QBluetoothSocket::SocketState>(), QBluetoothSocket::SocketState::ConnectedState);
+ QCOMPARE(socket.state(), QBluetoothSocket::SocketState::ConnectedState);
QCOMPARE(socket.isWritable(), true);
QCOMPARE(socket.isReadable(), true);
@@ -283,7 +262,13 @@ void tst_QBluetoothSocket::tst_serviceConnection()
//check the peer & local info
QCOMPARE(socket.localAddress(), localDevice.address());
QCOMPARE(socket.localName(), localDevice.name());
+#ifdef Q_OS_WIN
+ // On Windows the socket peer name (aka remotehost display name) seems to be
+ // formed from the BT address and not necessarily the remoteDevice name
+ QVERIFY(!socket.peerName().isEmpty());
+#else
QCOMPARE(socket.peerName(), remoteDevice.name());
+#endif
QCOMPARE(socket.peerAddress(), remoteDevice.address());
/* Disconnection */
@@ -295,18 +280,18 @@ void tst_QBluetoothSocket::tst_serviceConnection()
QCOMPARE(socket.isOpen(), false);
QCOMPARE(socket.openMode(), QIODevice::NotOpen);
- QVERIFY(stateSpy.count() >= 1);
- QCOMPARE(stateSpy.takeFirst().at(0).value<QBluetoothSocket::SocketState>(), QBluetoothSocket::ClosingState);
+ QVERIFY(!stateSpy.isEmpty());
+ QCOMPARE(stateSpy.takeFirst().at(0).value<QBluetoothSocket::SocketState>(), QBluetoothSocket::SocketState::ClosingState);
int disconnectTime = MaxConnectTime;
- while (disconnectedSpy.count() == 0 && disconnectTime > 0) {
+ while (disconnectedSpy.isEmpty() && disconnectTime > 0) {
QTest::qWait(1000);
disconnectTime -= 1000;
}
- QCOMPARE(disconnectedSpy.count(), 1);
- QCOMPARE(stateSpy.count(), 1);
- QCOMPARE(stateSpy.takeFirst().at(0).value<QBluetoothSocket::SocketState>(), QBluetoothSocket::UnconnectedState);
+ QCOMPARE(disconnectedSpy.size(), 1);
+ QCOMPARE(stateSpy.size(), 1);
+ QCOMPARE(stateSpy.takeFirst().at(0).value<QBluetoothSocket::SocketState>(), QBluetoothSocket::SocketState::UnconnectedState);
// The remote service needs time to close the connection and resume listening
QTest::qSleep(100);
@@ -337,7 +322,7 @@ void tst_QBluetoothSocket::tst_clientCommunication()
QSignalSpy stateSpy(&socket, SIGNAL(stateChanged(QBluetoothSocket::SocketState)));
QCOMPARE(socket.socketType(), QBluetoothServiceInfo::RfcommProtocol);
- QCOMPARE(socket.state(), QBluetoothSocket::UnconnectedState);
+ QCOMPARE(socket.state(), QBluetoothSocket::SocketState::UnconnectedState);
/* Connection */
QSignalSpy connectedSpy(&socket, SIGNAL(connected()));
@@ -348,14 +333,14 @@ void tst_QBluetoothSocket::tst_clientCommunication()
QCOMPARE(socket.openMode(), QIODevice::NotOpen);
socket.connectToService(remoteServiceInfo);
- QCOMPARE(stateSpy.count(), 1);
- QCOMPARE(qvariant_cast<QBluetoothSocket::SocketState>(stateSpy.takeFirst().at(0)), QBluetoothSocket::ConnectingState);
- QCOMPARE(socket.state(), QBluetoothSocket::ConnectingState);
+ QCOMPARE(stateSpy.size(), 1);
+ QCOMPARE(qvariant_cast<QBluetoothSocket::SocketState>(stateSpy.takeFirst().at(0)), QBluetoothSocket::SocketState::ConnectingState);
+ QCOMPARE(socket.state(), QBluetoothSocket::SocketState::ConnectingState);
stateSpy.clear();
int connectTime = MaxConnectTime;
- while (connectedSpy.count() == 0 && connectTime > 0) {
+ while (connectedSpy.isEmpty() && connectTime > 0) {
QTest::qWait(1000);
connectTime -= 1000;
}
@@ -364,10 +349,10 @@ void tst_QBluetoothSocket::tst_clientCommunication()
QCOMPARE(socket.isReadable(), true);
QCOMPARE(socket.isOpen(), true);
- QCOMPARE(connectedSpy.count(), 1);
- QCOMPARE(stateSpy.count(), 1);
- QCOMPARE(qvariant_cast<QBluetoothSocket::SocketState>(stateSpy.takeFirst().at(0)), QBluetoothSocket::ConnectedState);
- QCOMPARE(socket.state(), QBluetoothSocket::ConnectedState);
+ QCOMPARE(connectedSpy.size(), 1);
+ QCOMPARE(stateSpy.size(), 1);
+ QCOMPARE(qvariant_cast<QBluetoothSocket::SocketState>(stateSpy.takeFirst().at(0)), QBluetoothSocket::SocketState::ConnectedState);
+ QCOMPARE(socket.state(), QBluetoothSocket::SocketState::ConnectedState);
stateSpy.clear();
@@ -377,7 +362,7 @@ void tst_QBluetoothSocket::tst_clientCommunication()
{
/* Send line by line with event loop */
- for (const QString &line : qAsConst(data)) {
+ for (const QString &line : std::as_const(data)) {
QSignalSpy readyReadSpy(&socket, SIGNAL(readyRead()));
QSignalSpy bytesWrittenSpy(&socket, SIGNAL(bytesWritten(qint64)));
@@ -386,31 +371,31 @@ void tst_QBluetoothSocket::tst_clientCommunication()
if (socket.openMode() & QIODevice::Unbuffered)
QCOMPARE(socket.bytesToWrite(), qint64(0));
else
- QCOMPARE(socket.bytesToWrite(), qint64(line.length()));
+ QCOMPARE(socket.bytesToWrite(), qint64(line.size()));
- QCOMPARE(dataWritten, qint64(line.length()));
+ QCOMPARE(dataWritten, qint64(line.size()));
int readWriteTime = MaxReadWriteTime;
- while ((bytesWrittenSpy.count() == 0 || readyReadSpy.count() == 0) && readWriteTime > 0) {
+ while ((bytesWrittenSpy.isEmpty() || readyReadSpy.isEmpty()) && readWriteTime > 0) {
QTest::qWait(1000);
readWriteTime -= 1000;
}
- QCOMPARE(bytesWrittenSpy.count(), 1);
- QCOMPARE(bytesWrittenSpy.at(0).at(0).toLongLong(), qint64(line.length()));
+ QCOMPARE(bytesWrittenSpy.size(), 1);
+ QCOMPARE(bytesWrittenSpy.at(0).at(0).toLongLong(), qint64(line.size()));
readWriteTime = MaxReadWriteTime;
- while ((readyReadSpy.count() == 0) && readWriteTime > 0) {
+ while (readyReadSpy.isEmpty() && readWriteTime > 0) {
QTest::qWait(1000);
readWriteTime -= 1000;
}
- QCOMPARE(readyReadSpy.count(), 1);
+ QCOMPARE(readyReadSpy.size(), 1);
if (socket.openMode() & QIODevice::Unbuffered)
- QVERIFY(socket.bytesAvailable() <= qint64(line.length()));
+ QVERIFY(socket.bytesAvailable() <= qint64(line.size()));
else
- QCOMPARE(socket.bytesAvailable(), qint64(line.length()));
+ QCOMPARE(socket.bytesAvailable(), qint64(line.size()));
QVERIFY(socket.canReadLine());
@@ -435,24 +420,24 @@ void tst_QBluetoothSocket::tst_clientCommunication()
if (socket.openMode() & QIODevice::Unbuffered)
QCOMPARE(socket.bytesToWrite(), qint64(0));
else
- QCOMPARE(socket.bytesToWrite(), qint64(joined.length()));
+ QCOMPARE(socket.bytesToWrite(), qint64(joined.size()));
- QCOMPARE(dataWritten, qint64(joined.length()));
+ QCOMPARE(dataWritten, qint64(joined.size()));
int readWriteTime = MaxReadWriteTime;
- while ((bytesWrittenSpy.count() == 0 || readyReadSpy.count() == 0) && readWriteTime > 0) {
+ while ((bytesWrittenSpy.isEmpty() || readyReadSpy.isEmpty()) && readWriteTime > 0) {
QTest::qWait(1000);
readWriteTime -= 1000;
}
- QCOMPARE(bytesWrittenSpy.count(), 1);
- QCOMPARE(bytesWrittenSpy.at(0).at(0).toLongLong(), qint64(joined.length()));
- QVERIFY(readyReadSpy.count() > 0);
+ QCOMPARE(bytesWrittenSpy.size(), 1);
+ QCOMPARE(bytesWrittenSpy.at(0).at(0).toLongLong(), qint64(joined.size()));
+ QVERIFY(!readyReadSpy.isEmpty());
if (socket.openMode() & QIODevice::Unbuffered)
- QVERIFY(socket.bytesAvailable() <= qint64(joined.length()));
+ QVERIFY(socket.bytesAvailable() <= qint64(joined.size()));
else
- QCOMPARE(socket.bytesAvailable(), qint64(joined.length()));
+ QCOMPARE(socket.bytesAvailable(), qint64(joined.size()));
QVERIFY(socket.canReadLine());
@@ -472,15 +457,15 @@ void tst_QBluetoothSocket::tst_clientCommunication()
QCOMPARE(socket.openMode(), QIODevice::NotOpen);
int disconnectTime = MaxConnectTime;
- while (disconnectedSpy.count() == 0 && disconnectTime > 0) {
+ while (disconnectedSpy.isEmpty() && disconnectTime > 0) {
QTest::qWait(1000);
disconnectTime -= 1000;
}
- QCOMPARE(disconnectedSpy.count(), 1);
- QCOMPARE(stateSpy.count(), 2);
- QCOMPARE(qvariant_cast<QBluetoothSocket::SocketState>(stateSpy.takeFirst().at(0)), QBluetoothSocket::ClosingState);
- QCOMPARE(qvariant_cast<QBluetoothSocket::SocketState>(stateSpy.takeFirst().at(0)), QBluetoothSocket::UnconnectedState);
+ QCOMPARE(disconnectedSpy.size(), 1);
+ QCOMPARE(stateSpy.size(), 2);
+ QCOMPARE(qvariant_cast<QBluetoothSocket::SocketState>(stateSpy.takeFirst().at(0)), QBluetoothSocket::SocketState::ClosingState);
+ QCOMPARE(qvariant_cast<QBluetoothSocket::SocketState>(stateSpy.takeFirst().at(0)), QBluetoothSocket::SocketState::UnconnectedState);
// The remote service needs time to close the connection and resume listening
QTest::qSleep(100);
@@ -489,11 +474,11 @@ void tst_QBluetoothSocket::tst_clientCommunication()
void tst_QBluetoothSocket::tst_error()
{
QBluetoothSocket socket;
- QSignalSpy errorSpy(&socket, SIGNAL(error(QBluetoothSocket::SocketError)));
- QCOMPARE(errorSpy.count(), 0);
+ QSignalSpy errorSpy(&socket, SIGNAL(errorOccurred(QBluetoothSocket::SocketError)));
+ QCOMPARE(errorSpy.size(), 0);
const QBluetoothSocket::SocketError e = socket.error();
- QVERIFY(e == QBluetoothSocket::NoSocketError);
+ QVERIFY(e == QBluetoothSocket::SocketError::NoSocketError);
QVERIFY(socket.errorString() == QString());
}
@@ -503,21 +488,27 @@ void tst_QBluetoothSocket::tst_preferredSecurityFlags()
QBluetoothSocket socket;
//test default values
-#if defined(QT_ANDROID_BLUETOOTH) | defined(QT_OSX_BLUETOOTH)
- QCOMPARE(socket.preferredSecurityFlags(), QBluetooth::Secure);
+#if defined(QT_ANDROID_BLUETOOTH) || defined(QT_OSX_BLUETOOTH)
+ QCOMPARE(socket.preferredSecurityFlags(), QBluetooth::Security::Secure);
#elif QT_CONFIG(bluez)
- QCOMPARE(socket.preferredSecurityFlags(), QBluetooth::Authorization);
+ // The bluezdbus socket uses "NoSecurity" by default, whereas the non-dbus bluez
+ // socket uses "Authorization" by default
+ if (bluetoothdVersion() >= QVersionNumber(5, 46))
+ QCOMPARE(socket.preferredSecurityFlags(), QBluetooth::Security::NoSecurity);
+ else
+ QCOMPARE(socket.preferredSecurityFlags(), QBluetooth::Security::Authorization);
#else
- QCOMPARE(socket.preferredSecurityFlags(), QBluetooth::NoSecurity);
+ QCOMPARE(socket.preferredSecurityFlags(), QBluetooth::Security::NoSecurity);
#endif
- socket.setPreferredSecurityFlags(QBluetooth::Authentication|QBluetooth::Encryption);
+ socket.setPreferredSecurityFlags(QBluetooth::Security::Authentication
+ | QBluetooth::Security::Encryption);
#if defined(QT_OSX_BLUETOOTH)
- QCOMPARE(socket.preferredSecurityFlags(), QBluetooth::Secure);
+ QCOMPARE(socket.preferredSecurityFlags(), QBluetooth::Security::Secure);
#else
QCOMPARE(socket.preferredSecurityFlags(),
- QBluetooth::Encryption|QBluetooth::Authentication);
+ QBluetooth::Security::Encryption | QBluetooth::Security::Authentication);
#endif
}
@@ -531,19 +522,19 @@ void tst_QBluetoothSocket::tst_unsupportedProtocolError()
// UnsupportedProtocolError.
QBluetoothSocket socket;
QCOMPARE(socket.socketType(), QBluetoothServiceInfo::UnknownProtocol);
- QVERIFY(socket.error() == QBluetoothSocket::NoSocketError);
+ QVERIFY(socket.error() == QBluetoothSocket::SocketError::NoSocketError);
QVERIFY(socket.errorString() == QString());
- QSignalSpy errorSpy(&socket, SIGNAL(error(QBluetoothSocket::SocketError)));
+ QSignalSpy errorSpy(&socket, SIGNAL(errorOccurred(QBluetoothSocket::SocketError)));
// 1. Stop early with 'UnsupportedProtocolError'.
QBluetoothServiceInfo dummyServiceInfo;
socket.connectToService(dummyServiceInfo, QIODevice::ReadWrite);
QTRY_COMPARE_WITH_TIMEOUT(errorSpy.size(), 1, 1000);
QCOMPARE(errorSpy.size(), 1);
- QCOMPARE(errorSpy.takeFirst().at(0).toInt(), int(QBluetoothSocket::UnsupportedProtocolError));
+ QCOMPARE(errorSpy.takeFirst().at(0).toInt(), int(QBluetoothSocket::SocketError::UnsupportedProtocolError));
QVERIFY(socket.errorString().size() != 0);
- QCOMPARE(socket.state(), QBluetoothSocket::UnconnectedState);
+ QCOMPARE(socket.state(), QBluetoothSocket::SocketState::UnconnectedState);
errorSpy.clear();
@@ -551,9 +542,20 @@ void tst_QBluetoothSocket::tst_unsupportedProtocolError()
socket.connectToService(QBluetoothAddress(), 1, QIODevice::ReadWrite);
QTRY_COMPARE_WITH_TIMEOUT(errorSpy.size(), 1, 1000);
QCOMPARE(errorSpy.size(), 1);
- QCOMPARE(errorSpy.takeFirst().at(0).toInt(), int(QBluetoothSocket::UnsupportedProtocolError));
+#if QT_CONFIG(bluez)
+ // Bluez dbus socket does not support connecting to port and gives different error code
+ if (bluetoothdVersion() >= QVersionNumber(5, 46)) {
+ QCOMPARE(errorSpy.takeFirst().at(0).toInt(),
+ int(QBluetoothSocket::SocketError::ServiceNotFoundError));
+ } else {
+ QCOMPARE(errorSpy.takeFirst().at(0).toInt(),
+ int(QBluetoothSocket::SocketError::UnsupportedProtocolError));
+ }
+#else
+ QCOMPARE(errorSpy.takeFirst().at(0).toInt(), int(QBluetoothSocket::SocketError::UnsupportedProtocolError));
+#endif
QVERIFY(socket.errorString().size() != 0);
- QCOMPARE(socket.state(), QBluetoothSocket::UnconnectedState);
+ QCOMPARE(socket.state(), QBluetoothSocket::SocketState::UnconnectedState);
errorSpy.clear();
@@ -561,9 +563,9 @@ void tst_QBluetoothSocket::tst_unsupportedProtocolError()
socket.connectToService(QBluetoothAddress(), QBluetoothUuid(), QIODevice::ReadWrite);
QTRY_COMPARE_WITH_TIMEOUT(errorSpy.size(), 1, 1000);
QCOMPARE(errorSpy.size(), 1);
- QCOMPARE(errorSpy.takeFirst().at(0).toInt(), int(QBluetoothSocket::UnsupportedProtocolError));
+ QCOMPARE(errorSpy.takeFirst().at(0).toInt(), int(QBluetoothSocket::SocketError::UnsupportedProtocolError));
QVERIFY(socket.errorString().size() != 0);
- QCOMPARE(socket.state(), QBluetoothSocket::UnconnectedState);
+ QCOMPARE(socket.state(), QBluetoothSocket::SocketState::UnconnectedState);
}
QTEST_MAIN(tst_QBluetoothSocket)
diff --git a/tests/auto/qbluetoothtransfermanager/qbluetoothtransfermanager.pro b/tests/auto/qbluetoothtransfermanager/qbluetoothtransfermanager.pro
deleted file mode 100644
index 8e0d22a5..00000000
--- a/tests/auto/qbluetoothtransfermanager/qbluetoothtransfermanager.pro
+++ /dev/null
@@ -1,8 +0,0 @@
-SOURCES += tst_qbluetoothtransfermanager.cpp
-TARGET=tst_qbluetoothtransfermanager
-CONFIG += testcase
-testcase.timeout = 250 # this test is slow
-
-QT = core concurrent bluetooth testlib
-
-TESTDATA += *.txt
diff --git a/tests/auto/qbluetoothtransfermanager/testfile.txt b/tests/auto/qbluetoothtransfermanager/testfile.txt
deleted file mode 100644
index 630a0118..00000000
--- a/tests/auto/qbluetoothtransfermanager/testfile.txt
+++ /dev/null
@@ -1 +0,0 @@
-This is a small test file to be transmitted by tst_bluetoothtransfermanager.
diff --git a/tests/auto/qbluetoothtransfermanager/tst_qbluetoothtransfermanager.cpp b/tests/auto/qbluetoothtransfermanager/tst_qbluetoothtransfermanager.cpp
deleted file mode 100644
index 6b0481a5..00000000
--- a/tests/auto/qbluetoothtransfermanager/tst_qbluetoothtransfermanager.cpp
+++ /dev/null
@@ -1,360 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
-
-#include <QDebug>
-#include <QMap>
-#include <QTextStream>
-
-#include <qbluetoothtransferrequest.h>
-#include <qbluetoothtransfermanager.h>
-#include <qbluetoothtransferreply.h>
-#include <qbluetoothaddress.h>
-#include <qbluetoothlocaldevice.h>
-
-#include <qbluetoothdeviceinfo.h>
-#include <qbluetoothserviceinfo.h>
-#include <qbluetoothservicediscoveryagent.h>
-
-/*
- * Some tests require a Bluetooth device within the vincinity of the test
- * machine executing this test. The tests require manual interaction
- * as pairing and file transfer requests must be accepted.
- * The remote device's address must be passed
- * via the BT_TEST_DEVICE env variable. The remote device must be
- * discoverable and the object push service must be accessible. Any
- **/
-
-QT_USE_NAMESPACE
-
-typedef QMap<QBluetoothTransferRequest::Attribute,QVariant> tst_QBluetoothTransferManager_QParameterMap;
-Q_DECLARE_METATYPE(tst_QBluetoothTransferManager_QParameterMap)
-
-static const int MaxConnectTime = 60 * 1000; // 1 minute in ms
-
-class tst_QBluetoothTransferManager : public QObject
-{
- Q_OBJECT
-
-public:
- tst_QBluetoothTransferManager();
- ~tst_QBluetoothTransferManager();
-
-private slots:
- void initTestCase();
-
- void tst_construction();
-
- void tst_request_data();
- void tst_request();
-
- void tst_sendFile_data();
- void tst_sendFile();
-
- void tst_sendBuffer_data();
- void tst_sendBuffer();
-
- void tst_sendNullPointer();
-private:
- QBluetoothAddress remoteAddress;
-};
-
-tst_QBluetoothTransferManager::tst_QBluetoothTransferManager()
-{
-}
-
-tst_QBluetoothTransferManager::~tst_QBluetoothTransferManager()
-{
-}
-
-void tst_QBluetoothTransferManager::initTestCase()
-{
- const QString remote = qgetenv("BT_TEST_DEVICE");
- if (!remote.isEmpty()) {
- remoteAddress = QBluetoothAddress(remote);
- QVERIFY(!remoteAddress.isNull());
- qWarning() << "Using remote device " << remote << " for testing. Ensure that the device is discoverable for pairing requests";
- } else {
- qWarning() << "Not using any remote device for testing. Set BT_TEST_DEVICE env to run manual tests involving a remote device";
- QSKIP("Remote upload test not possible. Set BT_TEST_DEVICE");
- }
-
- if (!QBluetoothLocalDevice::allDevices().count())
- QSKIP("Skipping test due to missing Bluetooth device");
-
- // start Bluetooth if not started
- QBluetoothLocalDevice *device = new QBluetoothLocalDevice();
- device->powerOn();
- delete device;
-}
-
-void tst_QBluetoothTransferManager::tst_construction()
-{
- QBluetoothTransferManager *manager = new QBluetoothTransferManager();
-
- QVERIFY(manager);
- delete manager;
-}
-
-void tst_QBluetoothTransferManager::tst_request_data()
-{
- QTest::addColumn<QBluetoothAddress>("address");
- QTest::addColumn<QMap<QBluetoothTransferRequest::Attribute, QVariant> >("parameters");
-
- QMap<QBluetoothTransferRequest::Attribute, QVariant> inparameters;
- inparameters.insert(QBluetoothTransferRequest::DescriptionAttribute, "Description");
- inparameters.insert(QBluetoothTransferRequest::LengthAttribute, QVariant(1024));
- inparameters.insert(QBluetoothTransferRequest::TypeAttribute, "OPP");
- inparameters.insert(QBluetoothTransferRequest::NameAttribute, "name");
- inparameters.insert(QBluetoothTransferRequest::TimeAttribute, QDateTime::currentDateTime());
-
- QTest::newRow("TESTDATA") << QBluetoothAddress("00:11:22:33:44:55:66") << inparameters;
-}
-
-void tst_QBluetoothTransferManager::tst_request()
-{
- QFETCH(QBluetoothAddress, address);
- QFETCH(tst_QBluetoothTransferManager_QParameterMap, parameters);
-
- QBluetoothTransferRequest transferRequest(address);
- const QList<QBluetoothTransferRequest::Attribute> attributes = parameters.keys();
- for (QBluetoothTransferRequest::Attribute key : attributes)
- QCOMPARE(transferRequest.attribute(key), QVariant());
-
- for (QBluetoothTransferRequest::Attribute key : attributes)
- transferRequest.setAttribute((QBluetoothTransferRequest::Attribute)key, parameters[key]);
-
- QCOMPARE(transferRequest.address(), address);
- for (QBluetoothTransferRequest::Attribute key : attributes)
- QCOMPARE(transferRequest.attribute(key), parameters[key]);
-
- //test copy constructor
- QBluetoothTransferRequest constructorCopy = transferRequest;
- QVERIFY(constructorCopy == transferRequest);
- QVERIFY(!(constructorCopy != transferRequest));
- QCOMPARE(constructorCopy.address(), address);
- for (QBluetoothTransferRequest::Attribute key : attributes)
- QCOMPARE(constructorCopy.attribute(key), parameters[key]);
-
- //test assignment operator
- QBluetoothTransferRequest request;
- QVERIFY(request.address().isNull());
- for (QBluetoothTransferRequest::Attribute key : attributes)
- QCOMPARE(request.attribute(key), QVariant());
- request = transferRequest;
- QCOMPARE(request.address(), address);
- for (QBluetoothTransferRequest::Attribute key : attributes)
- QCOMPARE(request.attribute(key), parameters[key]);
-
- //test that it's a true and independent copy
- constructorCopy.setAttribute(QBluetoothTransferRequest::DescriptionAttribute, "newDescription");
- request.setAttribute(QBluetoothTransferRequest::TypeAttribute, "FTP");
-
- QCOMPARE(constructorCopy.attribute(QBluetoothTransferRequest::DescriptionAttribute).toString(),QString("newDescription"));
- QCOMPARE(request.attribute(QBluetoothTransferRequest::DescriptionAttribute).toString(),QString("Description"));
- QCOMPARE(transferRequest.attribute(QBluetoothTransferRequest::DescriptionAttribute).toString(),QString("Description"));
-
- QCOMPARE(constructorCopy.attribute(QBluetoothTransferRequest::TypeAttribute).toString(),QString("OPP"));
- QCOMPARE(request.attribute(QBluetoothTransferRequest::TypeAttribute).toString(),QString("FTP"));
- QCOMPARE(transferRequest.attribute(QBluetoothTransferRequest::TypeAttribute).toString(),QString("OPP"));
-}
-
-void tst_QBluetoothTransferManager::tst_sendFile_data()
-{
- QTest::addColumn<QBluetoothAddress>("deviceAddress");
- QTest::addColumn<bool>("expectSuccess");
- QTest::addColumn<bool>("isInvalidFile");
-
- QTest::newRow("Push to remote test device") << remoteAddress << true << false;
- QTest::newRow("Push of non-existing file") << remoteAddress << false << true;
- QTest::newRow("Push to invalid address") << QBluetoothAddress() << false << false;
- QTest::newRow("Push to non-existend device") << QBluetoothAddress("11:22:33:44:55:66") << false << false;
-
-}
-
-void tst_QBluetoothTransferManager::tst_sendFile()
-{
- QFETCH(QBluetoothAddress, deviceAddress);
- QFETCH(bool, expectSuccess);
- QFETCH(bool, isInvalidFile);
-
- QBluetoothLocalDevice dev;
- if (expectSuccess) {
- dev.requestPairing(deviceAddress, QBluetoothLocalDevice::Paired);
- QTest::qWait(5000);
- QCOMPARE(dev.pairingStatus(deviceAddress), QBluetoothLocalDevice::Paired);
- }
-
- QBluetoothTransferRequest request(deviceAddress);
- QCOMPARE(request.address(), deviceAddress);
-
- QBluetoothTransferManager manager;
- QString fileHandle;
- if (!isInvalidFile) {
- fileHandle = QFINDTESTDATA("testfile.txt");
- QVERIFY(!fileHandle.isEmpty());
- } else {
- fileHandle = ("arbitraryFileName.txt"); //file doesn't exist
- }
- QFile f(fileHandle);
- QCOMPARE(f.exists(), !isInvalidFile);
-
-
- qDebug() << "Transferring file to " << deviceAddress.toString();
- if (expectSuccess)
- qDebug() << "Please accept Object push request on remote device";
- QBluetoothTransferReply* reply = manager.put(request, &f);
- QSignalSpy finishedSpy(reply, SIGNAL(finished(QBluetoothTransferReply*)));
- QSignalSpy progressSpy(reply, SIGNAL(transferProgress(qint64,qint64)));
- QSignalSpy errorSpy(reply, SIGNAL(error(QBluetoothTransferReply::TransferError)));
-
- QCOMPARE(reply->request(), request);
- QVERIFY(reply->manager() == &manager);
- QVERIFY(!reply->isFinished());
- QVERIFY(reply->isRunning());
-
- const int maxWaitTime = 20 * 1000; //20s
- for (int time = 0;
- time<maxWaitTime && (finishedSpy.count()==0);
- time+=1000) {
- QTest::qWait(1000); //if interval
- }
-
- QVERIFY(finishedSpy.count()>0);
- if (expectSuccess) {
- QVERIFY(progressSpy.count()>0);
- QCOMPARE(reply->error(), QBluetoothTransferReply::NoError);
- QCOMPARE(reply->errorString(), QString());
- QVERIFY(errorSpy.isEmpty());
- } else {
- QVERIFY(progressSpy.count() == 0);
- if (isInvalidFile)
- QVERIFY(reply->error() == QBluetoothTransferReply::FileNotFoundError);
- else
- QVERIFY(reply->error() != QBluetoothTransferReply::NoError);
- QVERIFY(!reply->errorString().isEmpty());
- QCOMPARE(errorSpy.count(), 1);
- }
-
- QVERIFY(reply->isFinished());
- QVERIFY(!reply->isRunning());
-}
-
-void tst_QBluetoothTransferManager::tst_sendBuffer_data()
-{
-
- QTest::addColumn<QBluetoothAddress>("deviceAddress");
- QTest::addColumn<bool>("expectSuccess");
- QTest::addColumn<QByteArray>("data");
-
- QTest::newRow("Push to remote test device") << remoteAddress << true <<
- QByteArray("This is a very long byte array which we are going to access via a QBuffer"); ;
- QTest::newRow("Push to invalid address") << QBluetoothAddress() << false << QByteArray("test");
- QTest::newRow("Push to non-existend device") << QBluetoothAddress("11:22:33:44:55:66") << false << QByteArray("test");
-}
-
-
-
-void tst_QBluetoothTransferManager::tst_sendBuffer()
-{
- QFETCH(QBluetoothAddress, deviceAddress);
- QFETCH(bool, expectSuccess);
- QFETCH(QByteArray, data);
-
- QBuffer buffer;
- buffer.setData(data);
- buffer.open(QIODevice::ReadOnly);
- buffer.seek(0);
-
- QBluetoothLocalDevice dev;
- if (expectSuccess) {
- dev.requestPairing(deviceAddress, QBluetoothLocalDevice::Paired);
- QTest::qWait(2000);
- QCOMPARE(dev.pairingStatus(deviceAddress), QBluetoothLocalDevice::Paired);
- }
-
- QBluetoothTransferRequest request(deviceAddress);
- QCOMPARE(request.address(), deviceAddress);
-
- QBluetoothTransferManager manager;
-
- qDebug() << "Transferring test buffer to " << deviceAddress.toString();
- if (expectSuccess)
- qDebug() << "Please accept Object push request on remote device";
- QBluetoothTransferReply* reply = manager.put(request, &buffer);
- QSignalSpy finishedSpy(reply, SIGNAL(finished(QBluetoothTransferReply*)));
- QSignalSpy progressSpy(reply, SIGNAL(transferProgress(qint64,qint64)));
- QSignalSpy errorSpy(reply, SIGNAL(error(QBluetoothTransferReply::TransferError)));
-
- QCOMPARE(reply->request(), request);
- QVERIFY(reply->manager() == &manager);
- QVERIFY(!reply->isFinished());
- QVERIFY(reply->isRunning());
-
- const int maxWaitTime = 20 * 1000; //20s
- for (int time = 0;
- time<maxWaitTime && (finishedSpy.count()==0);
- time+=10000) {
- QTest::qWait(10000); //if interval
- }
-
- QVERIFY(finishedSpy.count()>0);
- if (expectSuccess) {
- QVERIFY(progressSpy.count()>0);
- QVERIFY(errorSpy.isEmpty());
- QCOMPARE(reply->error(), QBluetoothTransferReply::NoError);
- QCOMPARE(reply->errorString(), QString());
- } else {
- QVERIFY(progressSpy.count() == 0);
- QVERIFY(reply->error() != QBluetoothTransferReply::NoError);
- QVERIFY(!reply->errorString().isEmpty());
- QCOMPARE(errorSpy.count(), 1);
- }
-
- QVERIFY(reply->isFinished());
- QVERIFY(!reply->isRunning());
-}
-
-void tst_QBluetoothTransferManager::tst_sendNullPointer()
-{
- QBluetoothTransferRequest request(remoteAddress);
- QBluetoothTransferManager manager;
- QBluetoothTransferReply *reply = manager.put(request, 0);
-
- QVERIFY(reply);
- QCOMPARE(reply->isFinished(), true);
- QCOMPARE(reply->isRunning(), false);
- QCOMPARE(reply->manager(), &manager);
- QCOMPARE(reply->request(), request);
- QCOMPARE(reply->error(), QBluetoothTransferReply::FileNotFoundError);
-}
-
-QTEST_MAIN(tst_QBluetoothTransferManager)
-
-#include "tst_qbluetoothtransfermanager.moc"
diff --git a/tests/auto/qbluetoothtransferrequest/qbluetoothtransferrequest.pro b/tests/auto/qbluetoothtransferrequest/qbluetoothtransferrequest.pro
deleted file mode 100644
index 2dfbfe09..00000000
--- a/tests/auto/qbluetoothtransferrequest/qbluetoothtransferrequest.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-SOURCES += tst_qbluetoothtransferrequest.cpp
-TARGET=tst_qbluetoothtransferrequest
-CONFIG += testcase
-
-QT = core concurrent bluetooth testlib
diff --git a/tests/auto/qbluetoothtransferrequest/tst_qbluetoothtransferrequest.cpp b/tests/auto/qbluetoothtransferrequest/tst_qbluetoothtransferrequest.cpp
deleted file mode 100644
index dcf2c95b..00000000
--- a/tests/auto/qbluetoothtransferrequest/tst_qbluetoothtransferrequest.cpp
+++ /dev/null
@@ -1,164 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
-
-#include <QDebug>
-#include <QMap>
-
-#include <qbluetoothtransferrequest.h>
-#include <qbluetoothaddress.h>
-#include <qbluetoothlocaldevice.h>
-
-QT_USE_NAMESPACE
-
-typedef QMap<int,QVariant> tst_QBluetoothTransferRequest_QParameterMap;
-Q_DECLARE_METATYPE(tst_QBluetoothTransferRequest_QParameterMap)
-
-class tst_QBluetoothTransferRequest : public QObject
-{
- Q_OBJECT
-
-public:
- tst_QBluetoothTransferRequest();
- ~tst_QBluetoothTransferRequest();
-
-private slots:
- void initTestCase();
-
- void tst_construction_data();
- void tst_construction();
-
- void tst_assignment_data();
- void tst_assignment();
-};
-
-tst_QBluetoothTransferRequest::tst_QBluetoothTransferRequest()
-{
-}
-
-tst_QBluetoothTransferRequest::~tst_QBluetoothTransferRequest()
-{
-}
-
-void tst_QBluetoothTransferRequest::initTestCase()
-{
- // start Bluetooth if not started
- QBluetoothLocalDevice *device = new QBluetoothLocalDevice();
- device->powerOn();
- delete device;
-}
-
-void tst_QBluetoothTransferRequest::tst_construction_data()
-{
- QTest::addColumn<QBluetoothAddress>("address");
- QTest::addColumn<QMap<int, QVariant> >("parameters");
-
- QMap<int, QVariant> inparameters;
- inparameters.insert((int)QBluetoothTransferRequest::DescriptionAttribute, "Desciption");
- inparameters.insert((int)QBluetoothTransferRequest::LengthAttribute, QVariant(1024));
- inparameters.insert((int)QBluetoothTransferRequest::TypeAttribute, "OPP");
-
- QTest::newRow("0x000000 COD") << QBluetoothAddress("000000000000") << inparameters;
- QTest::newRow("0x000100 COD") << QBluetoothAddress("000000000000") << inparameters;
- QTest::newRow("0x000104 COD") << QBluetoothAddress("000000000000") << inparameters;
- QTest::newRow("0x000118 COD") << QBluetoothAddress("000000000000") << inparameters;
- QTest::newRow("0x000200 COD") << QBluetoothAddress("000000000000") << inparameters;
-}
-
-void tst_QBluetoothTransferRequest::tst_construction()
-{
- QFETCH(QBluetoothAddress, address);
- QFETCH(tst_QBluetoothTransferRequest_QParameterMap, parameters);
-
- QBluetoothTransferRequest transferRequest(address);
-
- const QList<int> keys = parameters.keys();
- for (const int key : keys) {
- transferRequest.setAttribute((QBluetoothTransferRequest::Attribute)key, parameters[key]);
- QCOMPARE(parameters[key], transferRequest.attribute((QBluetoothTransferRequest::Attribute)key));
- }
-
- QCOMPARE(transferRequest.address(), address);
-
- QBluetoothTransferRequest copyRequest(transferRequest);
-
- QCOMPARE(copyRequest.address(), address);
- QCOMPARE(transferRequest, copyRequest);
-}
-
-void tst_QBluetoothTransferRequest::tst_assignment_data()
-{
- tst_construction_data();
-}
-
-void tst_QBluetoothTransferRequest::tst_assignment()
-{
- QFETCH(QBluetoothAddress, address);
- QFETCH(tst_QBluetoothTransferRequest_QParameterMap, parameters);
-
- QBluetoothTransferRequest transferRequest(address);
-
- const QList<int> keys = parameters.keys();
- for (const int key : keys) {
- transferRequest.setAttribute((QBluetoothTransferRequest::Attribute)key, parameters[key]);
- }
-
- {
- QBluetoothTransferRequest copyRequest = transferRequest;
-
- QCOMPARE(copyRequest.address(), address);
- QCOMPARE(transferRequest, copyRequest);
- }
-
- {
- QBluetoothTransferRequest copyRequest(QBluetoothAddress("000000000001"));
-
- copyRequest = transferRequest;
-
- QCOMPARE(copyRequest.address(), address);
- QCOMPARE(transferRequest, copyRequest);
- }
-
- {
- QBluetoothTransferRequest copyRequest1(QBluetoothAddress("000000000001"));
- QBluetoothTransferRequest copyRequest2(QBluetoothAddress("000000000001"));
-
- copyRequest1 = copyRequest2 = transferRequest;
-
- QCOMPARE(copyRequest1.address(), address);
- QCOMPARE(copyRequest2.address(), address);
- QCOMPARE(transferRequest, copyRequest1);
- QCOMPARE(transferRequest, copyRequest2);
-
- }
-}
-
-QTEST_MAIN(tst_QBluetoothTransferRequest)
-
-#include "tst_qbluetoothtransferrequest.moc"
diff --git a/tests/auto/qbluetoothuuid/CMakeLists.txt b/tests/auto/qbluetoothuuid/CMakeLists.txt
new file mode 100644
index 00000000..de981305
--- /dev/null
+++ b/tests/auto/qbluetoothuuid/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qbluetoothuuid Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qbluetoothuuid LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qbluetoothuuid
+ SOURCES
+ tst_qbluetoothuuid.cpp
+ LIBRARIES
+ Qt::Bluetooth
+ Qt::CorePrivate
+)
diff --git a/tests/auto/qbluetoothuuid/qbluetoothuuid.pro b/tests/auto/qbluetoothuuid/qbluetoothuuid.pro
deleted file mode 100644
index 2d81c4af..00000000
--- a/tests/auto/qbluetoothuuid/qbluetoothuuid.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-SOURCES += tst_qbluetoothuuid.cpp
-TARGET = tst_qbluetoothuuid
-CONFIG += testcase
-
-QT = core concurrent bluetooth testlib
diff --git a/tests/auto/qbluetoothuuid/tst_qbluetoothuuid.cpp b/tests/auto/qbluetoothuuid/tst_qbluetoothuuid.cpp
index 2206826d..377f788a 100644
--- a/tests/auto/qbluetoothuuid/tst_qbluetoothuuid.cpp
+++ b/tests/auto/qbluetoothuuid/tst_qbluetoothuuid.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QUuid>
@@ -33,6 +8,10 @@
#include <qbluetoothuuid.h>
+#if defined(Q_OS_DARWIN)
+#include <QtCore/private/qcore_mac_p.h>
+#endif
+
#if defined(Q_OS_UNIX)
# include <arpa/inet.h>
# include <netinet/in.h>
@@ -40,8 +19,6 @@
QT_USE_NAMESPACE
-Q_DECLARE_METATYPE(quint128)
-
class tst_QBluetoothUuid : public QObject
{
Q_OBJECT
@@ -59,12 +36,10 @@ private slots:
void tst_conversion();
void tst_comparison_data();
void tst_comparison();
- void tst_quint128ToUuid();
};
tst_QBluetoothUuid::tst_QBluetoothUuid()
{
- qRegisterMetaType<quint128>();
}
tst_QBluetoothUuid::~tst_QBluetoothUuid()
@@ -84,7 +59,7 @@ void tst_QBluetoothUuid::tst_construction()
}
{
- QBluetoothUuid uuid(QBluetoothUuid::PublicBrowseGroup);
+ QBluetoothUuid uuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup);
QVERIFY(!uuid.isNull());
@@ -94,11 +69,11 @@ void tst_QBluetoothUuid::tst_construction()
uuid16 = uuid.toUInt16(&ok);
QVERIFY(ok);
- QCOMPARE(uuid16, static_cast<quint16>(QBluetoothUuid::PublicBrowseGroup));
+ QCOMPARE(uuid16, static_cast<quint16>(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup));
}
{
- QBluetoothUuid uuid(QBluetoothUuid::PublicBrowseGroup);
+ QBluetoothUuid uuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup);
QBluetoothUuid copy(uuid);
@@ -106,7 +81,7 @@ void tst_QBluetoothUuid::tst_construction()
}
{
- QBluetoothUuid uuid(QBluetoothUuid::L2cap);
+ QBluetoothUuid uuid(QBluetoothUuid::ProtocolUuid::L2cap);
QVERIFY(!uuid.isNull());
@@ -116,7 +91,7 @@ void tst_QBluetoothUuid::tst_construction()
uuid16 = uuid.toUInt16(&ok);
QVERIFY(ok);
- QCOMPARE(uuid16, static_cast<quint16>(QBluetoothUuid::L2cap));
+ QCOMPARE(uuid16, static_cast<quint16>(QBluetoothUuid::ProtocolUuid::L2cap));
}
{
@@ -146,7 +121,7 @@ void tst_QBluetoothUuid::tst_construction()
void tst_QBluetoothUuid::tst_assignment()
{
- QBluetoothUuid uuid(QBluetoothUuid::PublicBrowseGroup);
+ QBluetoothUuid uuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup);
{
QBluetoothUuid copy = uuid;
@@ -173,42 +148,6 @@ void tst_QBluetoothUuid::tst_assignment()
#define BASEUUID "-0000-1000-8000-00805F9B34FB"
-#define UUID128_32(x, a, b, c, d) \
- quint128 x = { \
- { \
- a, b, c, d, \
- 0x00, 0x00, \
- 0x10, 0x00, \
- 0x80, 0x00, \
- 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB \
- } \
- }
-
-#define UUID128_16(x, a, b) UUID128_32(x, 0, 0, a, b)
-
-#define NEWROW16(text, a, b, s) \
-do { \
- UUID128_16(uuid128, a, b); \
- quint32 uuid32 = a << 8 | b; \
- quint16 uuid16 = a << 8 | b; \
- QTest::newRow(text) << true << uuid16 << true << uuid32 << true << uuid128 \
- << (QLatin1Char('{') + QLatin1String(s) + QLatin1Char('}')); \
-} while (0)
-
-#define NEWROW32(text, a, b, c, d, s) \
-do { \
- UUID128_32(uuid128, a, b, c, d); \
- quint32 uuid32 = a << 24 | b << 16 | c << 8 | d; \
- quint16 uuid16; \
- bool constructUuid16 = (a == 0) && (b == 0); \
- if (constructUuid16) \
- uuid16 = c << 8 | d; \
- else \
- uuid16 = 0; \
- QTest::newRow(text) << constructUuid16 << uuid16 << true << uuid32 << true << uuid128 \
- << (QLatin1Char('{') + QLatin1String(s) + QLatin1Char('}')); \
-} while (0)
-
void tst_QBluetoothUuid::tst_conversion_data()
{
QTest::addColumn<bool>("constructUuid16");
@@ -216,19 +155,53 @@ void tst_QBluetoothUuid::tst_conversion_data()
QTest::addColumn<bool>("constructUuid32");
QTest::addColumn<quint32>("uuid32");
QTest::addColumn<bool>("constructUuid128");
- QTest::addColumn<quint128>("uuid128");
+ QTest::addColumn<QUuid::Id128Bytes>("uuid128");
QTest::addColumn<QString>("uuidS");
- NEWROW32("base uuid", 0x00, 0x00, 0x00, 0x00, "00000000" BASEUUID);
- NEWROW16("0x0001", 0x00, 0x01, "00000001" BASEUUID);
- NEWROW16("0xffff", 0xff, 0xff, "0000FFFF" BASEUUID);
- NEWROW32("0x00010000", 0x00, 0x01, 0x00, 0x00, "00010000" BASEUUID);
- NEWROW32("0x0001ffff", 0x00, 0x01, 0xff, 0xff, "0001FFFF" BASEUUID);
- NEWROW32("0xffff0000", 0xff, 0xff, 0x00, 0x00, "FFFF0000" BASEUUID);
- NEWROW32("0xffffffff", 0xff, 0xff, 0xff, 0xff, "FFFFFFFF" BASEUUID);
+ static const auto uuid128_32 = [](quint8 a, quint8 b, quint8 c, quint8 d) {
+ QUuid::Id128Bytes x = {
+ {
+ a, b, c, d,
+ 0x00, 0x00,
+ 0x10, 0x00,
+ 0x80, 0x00,
+ 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
+ }
+ };
+ return x;
+ };
+
+ auto newRow32 = [](const char *name, quint8 a, quint8 b, quint8 c, quint8 d, const char *s) {
+ auto uuid128 = uuid128_32(a, b, c, d);
+ quint32 uuid32 = a << 24 | b << 16 | c << 8 | d;
+ quint16 uuid16; \
+ bool constructUuid16 = (a == 0) && (b == 0);
+ if (constructUuid16)
+ uuid16 = c << 8 | d;
+ else
+ uuid16 = 0;
+ QTest::newRow(name) << constructUuid16 << uuid16 << true << uuid32 << true << uuid128
+ << (QLatin1Char('{') + QLatin1String(s) + QLatin1Char('}'));
+ };
+
+ auto newRow16 = [](const char *name, quint8 a, quint8 b, const char *s) {
+ auto uuid128 = uuid128_32(0, 0, a, b);
+ quint32 uuid32 = a << 8 | b;
+ quint16 uuid16 = a << 8 | b;
+ QTest::newRow(name) << true << uuid16 << true << uuid32 << true << uuid128
+ << (QLatin1Char('{') + QLatin1String(s) + QLatin1Char('}'));
+ };
+
+ newRow32("base uuid", 0x00, 0x00, 0x00, 0x00, "00000000" BASEUUID);
+ newRow16("0x0001", 0x00, 0x01, "00000001" BASEUUID);
+ newRow16("0xffff", 0xff, 0xff, "0000FFFF" BASEUUID);
+ newRow32("0x00010000", 0x00, 0x01, 0x00, 0x00, "00010000" BASEUUID);
+ newRow32("0x0001ffff", 0x00, 0x01, 0xff, 0xff, "0001FFFF" BASEUUID);
+ newRow32("0xffff0000", 0xff, 0xff, 0x00, 0x00, "FFFF0000" BASEUUID);
+ newRow32("0xffffffff", 0xff, 0xff, 0xff, 0xff, "FFFFFFFF" BASEUUID);
{
- quint128 uuid128 = {
+ QUuid::Id128Bytes uuid128 = {
{
0x00, 0x11, 0x22, 0x33,
0x44, 0x55,
@@ -251,7 +224,7 @@ void tst_QBluetoothUuid::tst_conversion()
QFETCH(bool, constructUuid32);
QFETCH(quint32, uuid32);
QFETCH(bool, constructUuid128);
- QFETCH(quint128, uuid128);
+ QFETCH(QUuid::Id128Bytes, uuid128);
QFETCH(QString, uuidS);
int minimumSize = 16;
@@ -260,9 +233,21 @@ void tst_QBluetoothUuid::tst_conversion()
else if (constructUuid32)
minimumSize = 4;
+#if defined(Q_OS_DARWIN)
+#define CHECK_PLATFORM_CONVERSION(qtUuid) \
+ const QMacAutoReleasePool pool; \
+ CBUUID *nativeUuid = qtUuid.toCBUUID(); \
+ QVERIFY(nativeUuid); \
+ QCOMPARE(qtUuid, QBluetoothUuid::fromCBUUID(nativeUuid));
+#else
+#define CHECK_PLATFORM_CONVERSION(qtUuid)
+#endif // Q_OS_DARWIN
+
if (constructUuid16) {
QBluetoothUuid uuid(uuid16);
+ QCOMPARE(uuid, QBluetoothUuid(QStringView{uuidS}));
+
bool ok;
QCOMPARE(uuid.toUInt16(&ok), uuid16);
@@ -271,16 +256,20 @@ void tst_QBluetoothUuid::tst_conversion()
QCOMPARE(uuid.toUInt32(&ok), uuid32);
QVERIFY(ok);
- QVERIFY(memcmp(uuid.toUInt128().data, uuid128.data, 16) == 0);
+ QVERIFY(memcmp(uuid.toBytes().data, uuid128.data, 16) == 0);
QCOMPARE(uuid.toString().toUpper(), uuidS.toUpper());
QCOMPARE(uuid.minimumSize(), minimumSize);
+
+ CHECK_PLATFORM_CONVERSION(uuid)
}
if (constructUuid32) {
QBluetoothUuid uuid(uuid32);
+ QCOMPARE(uuid, QBluetoothUuid(QLatin1StringView{uuidS.toLatin1()}));
+
bool ok;
quint16 tmp = uuid.toUInt16(&ok);
@@ -292,16 +281,20 @@ void tst_QBluetoothUuid::tst_conversion()
QCOMPARE(uuid.toUInt32(&ok), uuid32);
QVERIFY(ok);
- QVERIFY(memcmp(uuid.toUInt128().data, uuid128.data, 16) == 0);
+ QVERIFY(memcmp(uuid.toBytes().data, uuid128.data, 16) == 0);
QCOMPARE(uuid.toString().toUpper(), uuidS.toUpper());
QCOMPARE(uuid.minimumSize(), minimumSize);
+
+ CHECK_PLATFORM_CONVERSION(uuid)
}
if (constructUuid128) {
QBluetoothUuid uuid(uuid128);
+ QCOMPARE(uuid, QBluetoothUuid(QUtf8StringView{uuidS.toUtf8()}));
+
bool ok;
quint16 tmpUuid16 = uuid.toUInt16(&ok);
@@ -314,12 +307,15 @@ void tst_QBluetoothUuid::tst_conversion()
if (ok)
QCOMPARE(tmpUuid32, uuid32);
- QVERIFY(memcmp(uuid.toUInt128().data, uuid128.data, 16) == 0);
+ QVERIFY(memcmp(uuid.toBytes().data, uuid128.data, 16) == 0);
QCOMPARE(uuid.toString().toUpper(), uuidS.toUpper());
QCOMPARE(uuid.minimumSize(), minimumSize);
+
+ CHECK_PLATFORM_CONVERSION(uuid)
}
+#undef CHECK_PLATFORM_CONVERSION
}
void tst_QBluetoothUuid::tst_comparison_data()
@@ -334,7 +330,7 @@ void tst_QBluetoothUuid::tst_comparison()
QFETCH(bool, constructUuid32);
QFETCH(quint32, uuid32);
QFETCH(bool, constructUuid128);
- QFETCH(quint128, uuid128);
+ QFETCH(QUuid::Id128Bytes, uuid128);
QVERIFY(QBluetoothUuid() == QBluetoothUuid());
@@ -367,22 +363,28 @@ void tst_QBluetoothUuid::tst_comparison()
QBluetoothUuid quuid128(uuid128);
for (int var = 0; var < 16; ++var) {
- QVERIFY(quuid128.toUInt128().data[var] == uuid128.data[var]);
+ QVERIFY(quuid128.toBytes().data[var] == uuid128.data[var]);
}
- }
-}
-void tst_QBluetoothUuid::tst_quint128ToUuid()
-{
- QBluetoothUuid temp(QString("{67C8770B-44F1-410A-AB9A-F9B5446F13EE}"));
- quint128 array = temp.toUInt128();
- QBluetoothUuid u(array);
- QVERIFY(temp == u);
-
- QBENCHMARK {
- QBluetoothUuid u(array);
+ // check that toUInt128() call returns the value in the same format as
+ // QUuid::Id128Bytes, no matter what version we use (it can be
+ // QUuid::toUint128() on platforms that define __SIZEOF_INT128__ or
+ // QBluetoothUuid::toUint128() on other platforms).
+ const quint128 i128 = quuid128.toUInt128();
+ static_assert(sizeof(i128) == 16); // uint128 or QUuid::Id128Bytes
+ uchar dst[16];
+ memcpy(dst, &i128, sizeof(i128));
+ for (int var = 0; var < 16; ++var)
+ QCOMPARE_EQ(dst[var], uuid128.data[var]);
+
+ // check that we always have a c-tor taking quint128
+ QBluetoothUuid other{i128};
+ const auto bytes = other.toBytes();
+ for (int var = 0; var < 16; ++var)
+ QCOMPARE_EQ(bytes.data[var], uuid128.data[var]);
}
}
+
QTEST_MAIN(tst_QBluetoothUuid)
#include "tst_qbluetoothuuid.moc"
diff --git a/tests/auto/qlowenergycharacteristic/CMakeLists.txt b/tests/auto/qlowenergycharacteristic/CMakeLists.txt
new file mode 100644
index 00000000..7089c5cf
--- /dev/null
+++ b/tests/auto/qlowenergycharacteristic/CMakeLists.txt
@@ -0,0 +1,31 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qlowenergycharacteristic Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qlowenergycharacteristic LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qlowenergycharacteristic
+ SOURCES
+ tst_qlowenergycharacteristic.cpp
+ LIBRARIES
+ Qt::Bluetooth
+)
+
+set_target_properties(tst_qlowenergycharacteristic PROPERTIES
+ MACOSX_BUNDLE TRUE
+)
+
+if (APPLE AND NOT IOS)
+ # Ninja has trouble with relative paths, convert to absolute as a workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../shared ABSOLUTE)
+ set_target_properties(tst_qlowenergycharacteristic PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.macos.plist"
+ )
+endif()
diff --git a/tests/auto/qlowenergycharacteristic/qlowenergycharacteristic.pro b/tests/auto/qlowenergycharacteristic/qlowenergycharacteristic.pro
deleted file mode 100644
index 24106573..00000000
--- a/tests/auto/qlowenergycharacteristic/qlowenergycharacteristic.pro
+++ /dev/null
@@ -1,7 +0,0 @@
-SOURCES += tst_qlowenergycharacteristic.cpp
-TARGET = tst_qlowenergycharacteristic
-CONFIG += testcase
-
-QT = core bluetooth testlib
-
-
diff --git a/tests/auto/qlowenergycharacteristic/tst_qlowenergycharacteristic.cpp b/tests/auto/qlowenergycharacteristic/tst_qlowenergycharacteristic.cpp
index 7e191052..ea87d105 100644
--- a/tests/auto/qlowenergycharacteristic/tst_qlowenergycharacteristic.cpp
+++ b/tests/auto/qlowenergycharacteristic/tst_qlowenergycharacteristic.cpp
@@ -1,31 +1,6 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited all rights reserved
-** 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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 BlackBerry Limited all rights reserved
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QUuid>
@@ -86,22 +61,32 @@ tst_QLowEnergyCharacteristic::~tst_QLowEnergyCharacteristic()
void tst_QLowEnergyCharacteristic::initTestCase()
{
+#if defined(Q_OS_MACOS)
+ QSKIP("The low energy characteristic tests fail on macOS");
+#endif
if (QBluetoothLocalDevice::allDevices().isEmpty()) {
- qWarning("No remote device discovered.");
+ qWarning("No local adapter, not discovering remote devices");
return;
}
- // start Bluetooth if not started
QBluetoothLocalDevice device;
- device.powerOn();
+ if (device.hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
+ // Attempt to switch Bluetooth ON
+ device.powerOn();
+ QTest::qWait(1000);
+ if (device.hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
+ qWarning("Bluetooth couldn't be switched ON, not discovering remote devices");
+ return;
+ }
+ }
- // find an arbitrary low energy device in vincinity
+ // find an arbitrary low energy device in vicinity
// find an arbitrary service with characteristic
QBluetoothDeviceDiscoveryAgent *devAgent = new QBluetoothDeviceDiscoveryAgent(this);
connect(devAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
this, SLOT(deviceDiscovered(QBluetoothDeviceInfo)));
- QSignalSpy errorSpy(devAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)));
+ QSignalSpy errorSpy(devAgent, SIGNAL(errorOccurred(QBluetoothDeviceDiscoveryAgent::Error)));
QVERIFY(errorSpy.isValid());
QVERIFY(errorSpy.isEmpty());
@@ -110,17 +95,17 @@ void tst_QLowEnergyCharacteristic::initTestCase()
QVERIFY(spy.isEmpty());
devAgent->start();
- QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, 50000);
+ QTRY_VERIFY_WITH_TIMEOUT(!spy.isEmpty(), 100000);
// find first service with descriptor
QLowEnergyController *controller = 0;
- for (const QBluetoothDeviceInfo &remoteDevice : qAsConst(remoteLeDevices)) {
+ for (const QBluetoothDeviceInfo &remoteDevice : std::as_const(remoteLeDevices)) {
controller = QLowEnergyController::createCentral(remoteDevice, this);
qDebug() << "Connecting to" << remoteDevice.name()
<< remoteDevice.address() << remoteDevice.deviceUuid();
controller->connectToDevice();
QTRY_IMPL(controller->state() != QLowEnergyController::ConnectingState,
- 20000);
+ 50000);
if (controller->state() != QLowEnergyController::ConnectedState) {
// any error and we skip
delete controller;
@@ -131,8 +116,8 @@ void tst_QLowEnergyCharacteristic::initTestCase()
QSignalSpy discoveryFinishedSpy(controller, SIGNAL(discoveryFinished()));
QSignalSpy stateSpy(controller, SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
controller->discoverServices();
- QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 10000);
- QCOMPARE(stateSpy.count(), 2);
+ QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.size() == 1, 10000);
+ QCOMPARE(stateSpy.size(), 2);
QCOMPARE(stateSpy.at(0).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveringState);
QCOMPARE(stateSpy.at(1).at(0).value<QLowEnergyController::ControllerState>(),
@@ -146,7 +131,7 @@ void tst_QLowEnergyCharacteristic::initTestCase()
leService->discoverDetails();
QTRY_VERIFY_WITH_TIMEOUT(
- leService->state() == QLowEnergyService::ServiceDiscovered, 10000);
+ leService->state() == QLowEnergyService::RemoteServiceDiscovered, 10000);
const QList<QLowEnergyCharacteristic> chars = leService->characteristics();
for (const QLowEnergyCharacteristic &ch : chars) {
@@ -195,14 +180,13 @@ void tst_QLowEnergyCharacteristic::tst_constructionDefault()
QVERIFY(!characteristic.isValid());
QCOMPARE(characteristic.value(), QByteArray());
QVERIFY(characteristic.uuid().isNull());
- QVERIFY(characteristic.handle() == 0);
QCOMPARE(characteristic.name(), QString());
- QCOMPARE(characteristic.descriptors().count(), 0);
+ QCOMPARE(characteristic.descriptors().size(), 0);
QCOMPARE(characteristic.descriptor(QBluetoothUuid()),
QLowEnergyDescriptor());
- QCOMPARE(characteristic.descriptor(QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration)),
+ QCOMPARE(characteristic.descriptor(QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration)),
QLowEnergyDescriptor());
- QCOMPARE(characteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration),
+ QCOMPARE(characteristic.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration),
QLowEnergyDescriptor());
QCOMPARE(characteristic.properties(), QLowEnergyCharacteristic::Unknown);
@@ -210,9 +194,8 @@ void tst_QLowEnergyCharacteristic::tst_constructionDefault()
QVERIFY(!copyConstructed.isValid());
QCOMPARE(copyConstructed.value(), QByteArray());
QVERIFY(copyConstructed.uuid().isNull());
- QVERIFY(copyConstructed.handle() == 0);
QCOMPARE(copyConstructed.name(), QString());
- QCOMPARE(copyConstructed.descriptors().count(), 0);
+ QCOMPARE(copyConstructed.descriptors().size(), 0);
QCOMPARE(copyConstructed.properties(), QLowEnergyCharacteristic::Unknown);
QVERIFY(copyConstructed == characteristic);
@@ -231,9 +214,8 @@ void tst_QLowEnergyCharacteristic::tst_constructionDefault()
QVERIFY(!assigned.isValid());
QCOMPARE(assigned.value(), QByteArray());
QVERIFY(assigned.uuid().isNull());
- QVERIFY(assigned.handle() == 0);
QCOMPARE(assigned.name(), QString());
- QCOMPARE(assigned.descriptors().count(), 0);
+ QCOMPARE(assigned.descriptors().size(), 0);
QCOMPARE(assigned.properties(), QLowEnergyCharacteristic::Unknown);
QVERIFY(assigned == characteristic);
@@ -251,20 +233,19 @@ void tst_QLowEnergyCharacteristic::tst_assignCompare()
QVERIFY(!target.isValid());
QCOMPARE(target.value(), QByteArray());
QVERIFY(target.uuid().isNull());
- QVERIFY(target.handle() == 0);
QCOMPARE(target.name(), QString());
- QCOMPARE(target.descriptors().count(), 0);
+ QCOMPARE(target.descriptors().size(), 0);
QCOMPARE(target.properties(), QLowEnergyCharacteristic::Unknown);
- int indexWithDescriptor = -1;
+ qsizetype indexWithDescriptor = -1;
const QList<QLowEnergyCharacteristic> chars = globalService->characteristics();
QVERIFY(!chars.isEmpty());
- for (int i = 0; i < chars.count(); i++) {
+ for (qsizetype i = 0; i < chars.size(); ++i) {
const QLowEnergyCharacteristic specific =
globalService->characteristic(chars[i].uuid());
QVERIFY(specific.isValid());
QCOMPARE(specific, chars[i]);
- if (chars[i].descriptors().count() > 0) {
+ if (!chars[i].descriptors().isEmpty()) {
indexWithDescriptor = i;
break;
}
@@ -281,13 +262,12 @@ void tst_QLowEnergyCharacteristic::tst_assignCompare()
target = chars[indexWithDescriptor];
QVERIFY(target.isValid());
QVERIFY(!target.name().isEmpty());
- HANDLE_VERIFY(target.handle() > 0);
QVERIFY(!target.uuid().isNull());
QVERIFY(target.properties() != QLowEnergyCharacteristic::Unknown);
if (target.properties() & QLowEnergyCharacteristic::Read)
QVERIFY(!target.value().isEmpty());
if (!noDescriptors)
- QVERIFY(target.descriptors().count() > 0);
+ QVERIFY(!target.descriptors().isEmpty());
QVERIFY(target == chars[indexWithDescriptor]);
QVERIFY(chars[indexWithDescriptor] == target);
@@ -296,35 +276,35 @@ void tst_QLowEnergyCharacteristic::tst_assignCompare()
QCOMPARE(target.isValid(), chars[indexWithDescriptor].isValid());
QCOMPARE(target.name(), chars[indexWithDescriptor].name());
- QCOMPARE(target.handle(), chars[indexWithDescriptor].handle());
QCOMPARE(target.uuid(), chars[indexWithDescriptor].uuid());
QCOMPARE(target.value(), chars[indexWithDescriptor].value());
QCOMPARE(target.properties(), chars[indexWithDescriptor].properties());
- QCOMPARE(target.descriptors().count(),
- chars[indexWithDescriptor].descriptors().count());
- for (int i = 0; i < target.descriptors().count(); i++) {
- const QLowEnergyDescriptor ref = chars[indexWithDescriptor].descriptors()[i];
- QCOMPARE(target.descriptors()[i].name(), ref.name());
- QCOMPARE(target.descriptors()[i].isValid(), ref.isValid());
- QCOMPARE(target.descriptors()[i].type(), ref.type());
- QCOMPARE(target.descriptors()[i].handle(), ref.handle());
- QCOMPARE(target.descriptors()[i].uuid(), ref.uuid());
- QCOMPARE(target.descriptors()[i].value(), ref.value());
-
- const QLowEnergyDescriptor ref2 = chars[indexWithDescriptor].descriptor(ref.uuid());
- QCOMPARE(ref, ref2);
+ {
+ const auto targetDescriptors = target.descriptors();
+ const auto referenceDescriptors = chars[indexWithDescriptor].descriptors();
+ QCOMPARE(targetDescriptors.size(), referenceDescriptors.size());
+ for (qsizetype i = 0; i < targetDescriptors.size(); ++i) {
+ const QLowEnergyDescriptor ref = referenceDescriptors[i];
+ QCOMPARE(targetDescriptors[i].name(), ref.name());
+ QCOMPARE(targetDescriptors[i].isValid(), ref.isValid());
+ QCOMPARE(targetDescriptors[i].type(), ref.type());
+ QCOMPARE(targetDescriptors[i].uuid(), ref.uuid());
+ QCOMPARE(targetDescriptors[i].value(), ref.value());
+
+ const QLowEnergyDescriptor ref2 = chars[indexWithDescriptor].descriptor(ref.uuid());
+ QCOMPARE(ref, ref2);
+ }
}
// test copy constructor
QLowEnergyCharacteristic copyConstructed(target);
QCOMPARE(copyConstructed.isValid(), chars[indexWithDescriptor].isValid());
QCOMPARE(copyConstructed.name(), chars[indexWithDescriptor].name());
- QCOMPARE(copyConstructed.handle(), chars[indexWithDescriptor].handle());
QCOMPARE(copyConstructed.uuid(), chars[indexWithDescriptor].uuid());
QCOMPARE(copyConstructed.value(), chars[indexWithDescriptor].value());
QCOMPARE(copyConstructed.properties(), chars[indexWithDescriptor].properties());
- QCOMPARE(copyConstructed.descriptors().count(),
- chars[indexWithDescriptor].descriptors().count());
+ QCOMPARE(copyConstructed.descriptors().size(),
+ chars[indexWithDescriptor].descriptors().size());
QVERIFY(copyConstructed == target);
QVERIFY(target == copyConstructed);
@@ -337,9 +317,8 @@ void tst_QLowEnergyCharacteristic::tst_assignCompare()
QVERIFY(!target.isValid());
QCOMPARE(target.value(), QByteArray());
QVERIFY(target.uuid().isNull());
- QVERIFY(target.handle() == 0);
QCOMPARE(target.name(), QString());
- QCOMPARE(target.descriptors().count(), 0);
+ QCOMPARE(target.descriptors().size(), 0);
QCOMPARE(target.properties(), QLowEnergyCharacteristic::Unknown);
QVERIFY(invalid == target);
@@ -352,7 +331,7 @@ void tst_QLowEnergyCharacteristic::tst_assignCompare()
QVERIFY(chars[indexWithDescriptor] != target);
QVERIFY(target != chars[indexWithDescriptor]);
- if (chars.count() >= 2) {
+ if (chars.size() >= 2) {
// at least two characteristics
QVERIFY(!(chars[0] == chars[1]));
QVERIFY(!(chars[1] == chars[0]));
diff --git a/tests/auto/qlowenergycontroller-gattserver/CMakeLists.txt b/tests/auto/qlowenergycontroller-gattserver/CMakeLists.txt
new file mode 100644
index 00000000..5659ea8c
--- /dev/null
+++ b/tests/auto/qlowenergycontroller-gattserver/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(server)
+add_subdirectory(test)
diff --git a/tests/auto/qlowenergycontroller-gattserver/qlowenergycontroller-gattserver.pro b/tests/auto/qlowenergycontroller-gattserver/qlowenergycontroller-gattserver.pro
deleted file mode 100644
index 8b6c52e7..00000000
--- a/tests/auto/qlowenergycontroller-gattserver/qlowenergycontroller-gattserver.pro
+++ /dev/null
@@ -1,2 +0,0 @@
-TEMPLATE = subdirs
-SUBDIRS = server test
diff --git a/tests/auto/qlowenergycontroller-gattserver/server/CMakeLists.txt b/tests/auto/qlowenergycontroller-gattserver/server/CMakeLists.txt
new file mode 100644
index 00000000..3dc46724
--- /dev/null
+++ b/tests/auto/qlowenergycontroller-gattserver/server/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## server Binary:
+#####################################################################
+
+qt_internal_add_executable(qlecontroller-server
+ GUI
+ OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+ SOURCES
+ qlowenergycontroller-gattserver.cpp
+ LIBRARIES
+ Qt::Bluetooth
+)
diff --git a/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp b/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp
index 1275aa65..9eda2c0d 100644
--- a/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp
+++ b/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtBluetooth/qlowenergyadvertisingdata.h>
#include <QtBluetooth/qlowenergyadvertisingparameters.h>
@@ -36,9 +11,9 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qendian.h>
#include <QtCore/qhash.h>
+#include <QtCore/qlist.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qsharedpointer.h>
-#include <QtCore/qvector.h>
static QByteArray deviceName() { return "Qt GATT server"; }
@@ -59,14 +34,14 @@ void addService(const QLowEnergyServiceData &serviceData)
void addRunningSpeedService()
{
QLowEnergyServiceData serviceData;
- serviceData.setUuid(QBluetoothUuid::RunningSpeedAndCadence);
+ serviceData.setUuid(QBluetoothUuid::ServiceClassUuid::RunningSpeedAndCadence);
serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
QLowEnergyDescriptorData desc;
- desc.setUuid(QBluetoothUuid::ClientCharacteristicConfiguration);
+ desc.setUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
desc.setValue(QByteArray(2, 0)); // Default: No indication, no notification.
QLowEnergyCharacteristicData charData;
- charData.setUuid(QBluetoothUuid::RSCMeasurement);
+ charData.setUuid(QBluetoothUuid::CharacteristicType::RSCMeasurement);
charData.addDescriptor(desc);
charData.setProperties(QLowEnergyCharacteristic::Notify);
QByteArray value(4, 0);
@@ -75,7 +50,7 @@ void addRunningSpeedService()
serviceData.addCharacteristic(charData);
charData = QLowEnergyCharacteristicData();
- charData.setUuid(QBluetoothUuid::RSCFeature);
+ charData.setUuid(QBluetoothUuid::CharacteristicType::RSCFeature);
charData.setProperties(QLowEnergyCharacteristic::Read);
value = QByteArray(2, 0);
qToLittleEndian<quint16>(1 << 2, reinterpret_cast<uchar *>(value.data()));
@@ -87,24 +62,24 @@ void addRunningSpeedService()
void addGenericAccessService()
{
QLowEnergyServiceData serviceData;
- serviceData.setUuid(QBluetoothUuid::GenericAccess);
+ serviceData.setUuid(QBluetoothUuid::ServiceClassUuid::GenericAccess);
serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
QLowEnergyCharacteristicData charData;
- charData.setUuid(QBluetoothUuid::DeviceName);
+ charData.setUuid(QBluetoothUuid::CharacteristicType::DeviceName);
charData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Write);
charData.setValue(deviceName());
serviceData.addCharacteristic(charData);
charData = QLowEnergyCharacteristicData();
- charData.setUuid(QBluetoothUuid::Appearance);
+ charData.setUuid(QBluetoothUuid::CharacteristicType::Appearance);
charData.setProperties(QLowEnergyCharacteristic::Read);
QByteArray value(2, 0);
qToLittleEndian<quint16>(128, reinterpret_cast<uchar *>(value.data())); // Generic computer.
charData.setValue(value);
serviceData.addCharacteristic(charData);
- serviceData.addIncludedService(services.value(QBluetoothUuid::RunningSpeedAndCadence).data());
+ serviceData.addIncludedService(services.value(QBluetoothUuid::ServiceClassUuid::RunningSpeedAndCadence).data());
addService(serviceData);
}
@@ -122,14 +97,15 @@ void addCustomService()
charData.setUuid(QBluetoothUuid(quint16(0x5001)));
charData.setProperties(QLowEnergyCharacteristic::Read);
- charData.setReadConstraints(QBluetooth::AttAuthorizationRequired); // To test read failure.
+ charData.setReadConstraints(
+ QBluetooth::AttAccessConstraint::AttAuthorizationRequired); // To test read failure.
serviceData.addCharacteristic(charData);
charData.setValue("something");
charData.setUuid(QBluetoothUuid(quint16(0x5002)));
charData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Indicate);
charData.setReadConstraints(QBluetooth::AttAccessConstraints());
- const QLowEnergyDescriptorData desc(QBluetoothUuid::ClientCharacteristicConfiguration,
+ const QLowEnergyDescriptorData desc(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration,
QByteArray(2, 0));
charData.addDescriptor(desc);
serviceData.addCharacteristic(charData);
diff --git a/tests/auto/qlowenergycontroller-gattserver/server/server.pro b/tests/auto/qlowenergycontroller-gattserver/server/server.pro
deleted file mode 100644
index b9f2ccf9..00000000
--- a/tests/auto/qlowenergycontroller-gattserver/server/server.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-QT = core bluetooth
-
-CONFIG += c++11
-
-SOURCES = qlowenergycontroller-gattserver.cpp
diff --git a/tests/auto/qlowenergycontroller-gattserver/test/CMakeLists.txt b/tests/auto/qlowenergycontroller-gattserver/test/CMakeLists.txt
new file mode 100644
index 00000000..1e01efb2
--- /dev/null
+++ b/tests/auto/qlowenergycontroller-gattserver/test/CMakeLists.txt
@@ -0,0 +1,38 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qlowenergycontroller-gattserver Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qlowenergycontroller-gattserver LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qlowenergycontroller-gattserver
+ SOURCES
+ tst_qlowenergycontroller-gattserver.cpp
+ LIBRARIES
+ Qt::Bluetooth
+ Qt::BluetoothPrivate
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qlowenergycontroller-gattserver CONDITION QT_FEATURE_linux_crypto_api
+ DEFINES
+ CONFIG_LINUX_CRYPTO_API
+)
+
+qt_internal_extend_target(tst_qlowenergycontroller-gattserver CONDITION QT_FEATURE_bluez_le
+ DEFINES
+ CONFIG_BLUEZ_LE
+)
+
+qt_internal_extend_target(tst_qlowenergycontroller-gattserver CONDITION boot2qt
+ DEFINES
+ CHECK_CMAC_SUPPORT
+)
diff --git a/tests/auto/qlowenergycontroller-gattserver/test/test.pro b/tests/auto/qlowenergycontroller-gattserver/test/test.pro
deleted file mode 100644
index 5f80e660..00000000
--- a/tests/auto/qlowenergycontroller-gattserver/test/test.pro
+++ /dev/null
@@ -1,12 +0,0 @@
-QT = core bluetooth bluetooth-private testlib
-
-TARGET = tst_qlowenergycontroller-gattserver
-CONFIG += testcase c++11
-
-qtConfig(linux_crypto_api): DEFINES += CONFIG_LINUX_CRYPTO_API
-qtConfig(bluez_le): DEFINES += CONFIG_BLUEZ_LE
-
-SOURCES += tst_qlowenergycontroller-gattserver.cpp
-
-# qemu doesn't support all the needed socket operations
-boot2qt: DEFINES += CHECK_CMAC_SUPPORT
diff --git a/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp b/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp
index f3a0e9a4..bd72611c 100644
--- a/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp
+++ b/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtBluetooth/qbluetoothaddress.h>
#include <QtBluetooth/qbluetoothdevicediscoveryagent.h>
@@ -78,7 +53,7 @@ private:
QScopedPointer<QLowEnergyController> m_leController;
#if defined(CHECK_CMAC_SUPPORT)
- bool checkCmacSupport(const quint128& csrkMsb);
+ bool checkCmacSupport(const QUuid::Id128Bytes& csrkMsb);
#endif
};
@@ -151,8 +126,8 @@ void TestQLowEnergyControllerGattServer::advertisingData()
QCOMPARE(data.manufacturerId(), quint16(0xfffd));
QCOMPARE(data.manufacturerData(), QByteArray("some data"));
- const auto services = QList<QBluetoothUuid>() << QBluetoothUuid::CurrentTimeService
- << QBluetoothUuid::DeviceInformation;
+ const auto services = QList<QBluetoothUuid>() << QBluetoothUuid::ServiceClassUuid::CurrentTimeService
+ << QBluetoothUuid::ServiceClassUuid::DeviceInformation;
data.setServices(services);
QCOMPARE(data.services(), services);
@@ -167,7 +142,7 @@ void TestQLowEnergyControllerGattServer::cmacVerifier()
{
#if defined(CONFIG_LINUX_CRYPTO_API) && defined(QT_BUILD_INTERNAL) && defined(CONFIG_BLUEZ_LE)
// Test data comes from spec v4.2, Vol 3, Part H, Appendix D.1
- const quint128 csrk = {
+ const QUuid::Id128Bytes csrk = {
{ 0x3c, 0x4f, 0xcf, 0x09, 0x88, 0x15, 0xf7, 0xab,
0xa6, 0xd2, 0xae, 0x28, 0x16, 0x15, 0x7e, 0x2b }
};
@@ -193,11 +168,11 @@ void TestQLowEnergyControllerGattServer::cmacVerifier()
#include <linux/if_alg.h>
#include <unistd.h>
-bool TestQLowEnergyControllerGattServer::checkCmacSupport(const quint128& csrk)
+bool TestQLowEnergyControllerGattServer::checkCmacSupport(const QUuid::Id128Bytes& csrk)
{
bool retval = false;
#if defined(CONFIG_LINUX_CRYPTO_API) && defined(QT_BUILD_INTERNAL) && defined(CONFIG_BLUEZ_LE)
- quint128 csrkMsb;
+ QUuid::Id128Bytes csrkMsb;
std::reverse_copy(std::begin(csrk.data), std::end(csrk.data), std::begin(csrkMsb.data));
int testSocket = socket(AF_ALG, SOCK_SEQPACKET, 0);
@@ -212,14 +187,14 @@ bool TestQLowEnergyControllerGattServer::checkCmacSupport(const quint128& csrk)
if (setsockopt(testSocket, 279 /* SOL_ALG */, ALG_SET_KEY, csrkMsb.data, sizeof csrkMsb) != -1) {
retval = true;
} else {
- QWARN("Needed socket options (SOL_ALG) not available");
+ qWarning("Needed socket options (SOL_ALG) not available");
}
} else {
- QWARN("bind() failed for crypto socket:");
+ qWarning("bind() failed for crypto socket:");
}
close(testSocket);
} else {
- QWARN("Unable to create test socket");
+ qWarning("Unable to create test socket");
}
#endif
return retval;
@@ -286,9 +261,9 @@ void TestQLowEnergyControllerGattServer::advertisedData()
// name is seen on the scanning machine.
// QCOMPARE(m_serverInfo.name(), QString("Qt GATT server"));
- QVERIFY(m_serverInfo.serviceUuids().count() >= 3);
- QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid::GenericAccess));
- QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid::RunningSpeedAndCadence));
+ QVERIFY(m_serverInfo.serviceUuids().size() >= 3);
+ QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid::ServiceClassUuid::GenericAccess));
+ QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid::ServiceClassUuid::RunningSpeedAndCadence));
QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid(quint16(0x2000))));
}
@@ -306,64 +281,64 @@ void TestQLowEnergyControllerGattServer::serverCommunication()
spy.reset(new QSignalSpy(m_leController.data(), &QLowEnergyController::discoveryFinished));
QVERIFY(spy->wait(30000));
const QList<QBluetoothUuid> serviceUuids = m_leController->services();
- QCOMPARE(serviceUuids.count(), 4);
- QVERIFY(serviceUuids.contains(QBluetoothUuid::GenericAccess));
- QVERIFY(serviceUuids.contains(QBluetoothUuid::RunningSpeedAndCadence));
+ QCOMPARE(serviceUuids.size(), 4);
+ QVERIFY(serviceUuids.contains(QBluetoothUuid::ServiceClassUuid::GenericAccess));
+ QVERIFY(serviceUuids.contains(QBluetoothUuid::ServiceClassUuid::RunningSpeedAndCadence));
QVERIFY(serviceUuids.contains(QBluetoothUuid(quint16(0x2000))));
QVERIFY(serviceUuids.contains(QBluetoothUuid(QString("c47774c7-f237-4523-8968-e4ae75431daf"))));
const QScopedPointer<QLowEnergyService> genericAccessService(
- m_leController->createServiceObject(QBluetoothUuid::GenericAccess));
+ m_leController->createServiceObject(QBluetoothUuid::ServiceClassUuid::GenericAccess));
QVERIFY(!genericAccessService.isNull());
genericAccessService->discoverDetails();
- while (genericAccessService->state() != QLowEnergyService::ServiceDiscovered) {
+ while (genericAccessService->state() != QLowEnergyService::RemoteServiceDiscovered) {
spy.reset(new QSignalSpy(genericAccessService.data(), &QLowEnergyService::stateChanged));
QVERIFY(spy->wait(3000));
}
- QCOMPARE(genericAccessService->includedServices().count(), 1);
+ QCOMPARE(genericAccessService->includedServices().size(), 1);
QCOMPARE(genericAccessService->includedServices().first(),
- QBluetoothUuid(QBluetoothUuid::RunningSpeedAndCadence));
- QCOMPARE(genericAccessService->characteristics().count(), 2);
+ QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::RunningSpeedAndCadence));
+ QCOMPARE(genericAccessService->characteristics().size(), 2);
const QLowEnergyCharacteristic deviceNameChar
- = genericAccessService->characteristic(QBluetoothUuid::DeviceName);
+ = genericAccessService->characteristic(QBluetoothUuid::CharacteristicType::DeviceName);
QVERIFY(deviceNameChar.isValid());
- QCOMPARE(deviceNameChar.descriptors().count(), 0);
+ QCOMPARE(deviceNameChar.descriptors().size(), 0);
QCOMPARE(deviceNameChar.properties(),
QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Write);
QCOMPARE(deviceNameChar.value().constData(), "Qt GATT server");
const QLowEnergyCharacteristic appearanceChar
- = genericAccessService->characteristic(QBluetoothUuid::Appearance);
+ = genericAccessService->characteristic(QBluetoothUuid::CharacteristicType::Appearance);
QVERIFY(appearanceChar.isValid());
- QCOMPARE(appearanceChar.descriptors().count(), 0);
+ QCOMPARE(appearanceChar.descriptors().size(), 0);
QCOMPARE(appearanceChar.properties(), QLowEnergyCharacteristic::Read);
auto value = qFromLittleEndian<quint16>(reinterpret_cast<const uchar *>(
appearanceChar.value().constData()));
QCOMPARE(value, quint16(128));
const QScopedPointer<QLowEnergyService> runningSpeedService(
- m_leController->createServiceObject(QBluetoothUuid::RunningSpeedAndCadence));
+ m_leController->createServiceObject(QBluetoothUuid::ServiceClassUuid::RunningSpeedAndCadence));
QVERIFY(!runningSpeedService.isNull());
runningSpeedService->discoverDetails();
- while (runningSpeedService->state() != QLowEnergyService::ServiceDiscovered) {
+ while (runningSpeedService->state() != QLowEnergyService::RemoteServiceDiscovered) {
spy.reset(new QSignalSpy(runningSpeedService.data(), &QLowEnergyService::stateChanged));
QVERIFY(spy->wait(3000));
}
- QCOMPARE(runningSpeedService->includedServices().count(), 0);
- QCOMPARE(runningSpeedService->characteristics().count(), 2);
+ QCOMPARE(runningSpeedService->includedServices().size(), 0);
+ QCOMPARE(runningSpeedService->characteristics().size(), 2);
QLowEnergyCharacteristic measurementChar
- = runningSpeedService->characteristic(QBluetoothUuid::RSCMeasurement);
+ = runningSpeedService->characteristic(QBluetoothUuid::CharacteristicType::RSCMeasurement);
QVERIFY(measurementChar.isValid());
- QCOMPARE(measurementChar.descriptors().count(), 1);
+ QCOMPARE(measurementChar.descriptors().size(), 1);
const QLowEnergyDescriptor clientConfigDesc
- = measurementChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
+ = measurementChar.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(clientConfigDesc.isValid());
QCOMPARE(clientConfigDesc.value(), QByteArray(2, 0));
QCOMPARE(measurementChar.properties(), QLowEnergyCharacteristic::Notify);
QCOMPARE(measurementChar.value(), QByteArray()); // Empty because Read property not set
QLowEnergyCharacteristic featureChar
- = runningSpeedService->characteristic(QBluetoothUuid::RSCFeature);
+ = runningSpeedService->characteristic(QBluetoothUuid::CharacteristicType::RSCFeature);
QVERIFY(featureChar.isValid());
- QCOMPARE(featureChar.descriptors().count(), 0);
+ QCOMPARE(featureChar.descriptors().size(), 0);
QCOMPARE(featureChar.properties(), QLowEnergyCharacteristic::Read);
value = qFromLittleEndian<quint16>(reinterpret_cast<const uchar *>(
featureChar.value().constData()));
@@ -376,39 +351,39 @@ void TestQLowEnergyControllerGattServer::serverCommunication()
m_leController->createServiceObject(serviceUuid128));
QVERIFY(!customService128.isNull());
customService128->discoverDetails();
- while (customService128->state() != QLowEnergyService::ServiceDiscovered) {
+ while (customService128->state() != QLowEnergyService::RemoteServiceDiscovered) {
spy.reset(new QSignalSpy(customService128.data(), &QLowEnergyService::stateChanged));
QVERIFY(spy->wait(5000));
}
QCOMPARE(customService128->serviceUuid(), serviceUuid128);
- QCOMPARE(customService128->includedServices().count(), 0);
- QCOMPARE(customService128->characteristics().count(), 1);
+ QCOMPARE(customService128->includedServices().size(), 0);
+ QCOMPARE(customService128->characteristics().size(), 1);
QLowEnergyCharacteristic customChar128
= customService128->characteristic(charUuid128);
QVERIFY(customChar128.isValid());
- QCOMPARE(customChar128.descriptors().count(), 0);
+ QCOMPARE(customChar128.descriptors().size(), 0);
QCOMPARE(customChar128.value(), QByteArray(15, 'a'));
QScopedPointer<QLowEnergyService> customService(
m_leController->createServiceObject(QBluetoothUuid(quint16(0x2000))));
QVERIFY(!customService.isNull());
customService->discoverDetails();
- while (customService->state() != QLowEnergyService::ServiceDiscovered) {
+ while (customService->state() != QLowEnergyService::RemoteServiceDiscovered) {
spy.reset(new QSignalSpy(customService.data(), &QLowEnergyService::stateChanged));
QVERIFY(spy->wait(5000));
}
- QCOMPARE(customService->includedServices().count(), 0);
- QCOMPARE(customService->characteristics().count(), 5);
+ QCOMPARE(customService->includedServices().size(), 0);
+ QCOMPARE(customService->characteristics().size(), 5);
QLowEnergyCharacteristic customChar
= customService->characteristic(QBluetoothUuid(quint16(0x5000)));
QVERIFY(customChar.isValid());
- QCOMPARE(customChar.descriptors().count(), 0);
+ QCOMPARE(customChar.descriptors().size(), 0);
QCOMPARE(customChar.value(), QByteArray(1024, 'x'));
QLowEnergyCharacteristic customChar2
= customService->characteristic(QBluetoothUuid(quint16(0x5001)));
QVERIFY(customChar2.isValid());
- QCOMPARE(customChar2.descriptors().count(), 0);
+ QCOMPARE(customChar2.descriptors().size(), 0);
QCOMPARE(customChar2.value(), QByteArray()); // Was not readable due to authorization requirement.
QLowEnergyCharacteristic customChar3
@@ -416,9 +391,9 @@ void TestQLowEnergyControllerGattServer::serverCommunication()
QVERIFY(customChar3.isValid());
QCOMPARE(customChar3.properties(),
QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Indicate);
- QCOMPARE(customChar3.descriptors().count(), 1);
+ QCOMPARE(customChar3.descriptors().size(), 1);
QLowEnergyDescriptor cc3ClientConfig
- = customChar3.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
+ = customChar3.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(cc3ClientConfig.isValid());
QLowEnergyCharacteristic customChar4
@@ -426,9 +401,9 @@ void TestQLowEnergyControllerGattServer::serverCommunication()
QVERIFY(customChar4.isValid());
QCOMPARE(customChar4.properties(),
QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Notify);
- QCOMPARE(customChar4.descriptors().count(), 1);
+ QCOMPARE(customChar4.descriptors().size(), 1);
QLowEnergyDescriptor cc4ClientConfig
- = customChar4.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
+ = customChar4.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(cc4ClientConfig.isValid());
QLowEnergyCharacteristic customChar5
@@ -436,21 +411,19 @@ void TestQLowEnergyControllerGattServer::serverCommunication()
QVERIFY(customChar5.isValid());
QCOMPARE(customChar5.properties(),
QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::WriteSigned);
- QCOMPARE(customChar5.descriptors().count(), 0);
+ QCOMPARE(customChar5.descriptors().size(), 0);
QCOMPARE(customChar5.value(), QByteArray("initial"));
customService->writeCharacteristic(customChar, "whatever");
- spy.reset(new QSignalSpy(customService.data(), static_cast<void (QLowEnergyService::*)
- (QLowEnergyService::ServiceError)>(&QLowEnergyService::error)));
+ spy.reset(new QSignalSpy(customService.data(), &QLowEnergyService::errorOccurred));
QVERIFY(spy->wait(3000));
QCOMPARE(customService->error(), QLowEnergyService::CharacteristicWriteError);
- spy.reset(new QSignalSpy(customService.data(), static_cast<void (QLowEnergyService::*)
- (QLowEnergyService::ServiceError)>(&QLowEnergyService::error)));
+ spy.reset(new QSignalSpy(customService.data(), &QLowEnergyService::errorOccurred));
customService->writeCharacteristic(customChar5, "1", QLowEnergyService::WriteSigned);
// error might happen immediately or once event loop comes back
- bool wasError = ((spy->count() > 0) || spy->wait(3000)); //
+ bool wasError = (!spy->isEmpty() || spy->wait(3000)); //
if (!wasError) {
// Signed write is done twice to test the sign counter stuff.
@@ -484,7 +457,7 @@ void TestQLowEnergyControllerGattServer::serverCommunication()
spy.reset(new QSignalSpy(customService.data(), &QLowEnergyService::characteristicChanged));
QVERIFY(spy->wait(3000));
- if (spy->count() == 1)
+ if (spy->size() == 1)
QVERIFY(spy->wait(3000));
QCOMPARE(customChar3.value().constData(), "indicated");
QCOMPARE(customChar4.value().constData(), "notified");
@@ -516,7 +489,7 @@ void TestQLowEnergyControllerGattServer::serverCommunication()
customService.reset(m_leController->createServiceObject(QBluetoothUuid(quint16(0x2000))));
QVERIFY(!customService.isNull());
customService->discoverDetails();
- while (customService->state() != QLowEnergyService::ServiceDiscovered) {
+ while (customService->state() != QLowEnergyService::RemoteServiceDiscovered) {
spy.reset(new QSignalSpy(customService.data(), &QLowEnergyService::stateChanged));
QVERIFY(spy->wait(5000));
}
@@ -526,9 +499,9 @@ void TestQLowEnergyControllerGattServer::serverCommunication()
customChar4 = customService->characteristic(QBluetoothUuid(quint16(0x5003)));
QVERIFY(customChar4.isValid());
QCOMPARE(customChar4.value().constData(), "notified2");
- cc3ClientConfig = customChar3.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
+ cc3ClientConfig = customChar3.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(cc3ClientConfig.isValid());
- cc4ClientConfig = customChar4.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
+ cc4ClientConfig = customChar4.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(cc4ClientConfig.isValid());
const bool isBonded = QBluetoothLocalDevice().pairingStatus(m_serverAddress)
@@ -565,33 +538,33 @@ void TestQLowEnergyControllerGattServer::serviceData()
QLowEnergyDescriptorData descData;
QVERIFY(!descData.isValid());
- descData.setUuid(QBluetoothUuid::ValidRange);
- QCOMPARE(descData.uuid(), QBluetoothUuid(QBluetoothUuid::ValidRange));
+ descData.setUuid(QBluetoothUuid::DescriptorType::ValidRange);
+ QCOMPARE(descData.uuid(), QBluetoothUuid(QBluetoothUuid::DescriptorType::ValidRange));
QVERIFY(descData.isValid());
QVERIFY(descData != QLowEnergyDescriptorData());
descData.setValue("xyz");
QCOMPARE(descData.value().constData(), "xyz");
- descData.setReadPermissions(true, AttAuthenticationRequired);
+ descData.setReadPermissions(true, AttAccessConstraint::AttAuthenticationRequired);
QCOMPARE(descData.isReadable(), true);
- QCOMPARE(descData.readConstraints(), AttAuthenticationRequired);
+ QCOMPARE(descData.readConstraints(), AttAccessConstraint::AttAuthenticationRequired);
descData.setWritePermissions(false);
QCOMPARE(descData.isWritable(), false);
- QLowEnergyDescriptorData descData2(QBluetoothUuid::ReportReference, "abc");
+ QLowEnergyDescriptorData descData2(QBluetoothUuid::DescriptorType::ReportReference, "abc");
QVERIFY(descData2 != QLowEnergyDescriptorData());
QVERIFY(descData2.isValid());
- QCOMPARE(descData2.uuid(), QBluetoothUuid(QBluetoothUuid::ReportReference));
+ QCOMPARE(descData2.uuid(), QBluetoothUuid(QBluetoothUuid::DescriptorType::ReportReference));
QCOMPARE(descData2.value().constData(), "abc");
QLowEnergyCharacteristicData charData;
QVERIFY(!charData.isValid());
- charData.setUuid(QBluetoothUuid::BatteryLevel);
+ charData.setUuid(QBluetoothUuid::CharacteristicType::BatteryLevel);
QVERIFY(charData != QLowEnergyCharacteristicData());
- QCOMPARE(charData.uuid(), QBluetoothUuid(QBluetoothUuid::BatteryLevel));
+ QCOMPARE(charData.uuid(), QBluetoothUuid(QBluetoothUuid::CharacteristicType::BatteryLevel));
QVERIFY(charData.isValid());
charData.setValue("value");
@@ -609,17 +582,20 @@ void TestQLowEnergyControllerGattServer::serviceData()
charData.setProperties(props);
QCOMPARE(charData.properties(), props);
- charData.setReadConstraints(AttEncryptionRequired);
- QCOMPARE(charData.readConstraints(), AttEncryptionRequired);
- charData.setWriteConstraints(AttAuthenticationRequired | AttAuthorizationRequired);
- QCOMPARE(charData.writeConstraints(), AttAuthenticationRequired | AttAuthorizationRequired);
+ charData.setReadConstraints(AttAccessConstraint::AttEncryptionRequired);
+ QCOMPARE(charData.readConstraints(), AttAccessConstraint::AttEncryptionRequired);
+ charData.setWriteConstraints(AttAccessConstraint::AttAuthenticationRequired
+ | AttAccessConstraint::AttAuthorizationRequired);
+ QCOMPARE(charData.writeConstraints(),
+ AttAccessConstraint::AttAuthenticationRequired
+ | AttAccessConstraint::AttAuthorizationRequired);
charData.addDescriptor(descData);
- QCOMPARE(charData.descriptors().count(), 1);
+ QCOMPARE(charData.descriptors().size(), 1);
charData.setDescriptors(QList<QLowEnergyDescriptorData>());
- QCOMPARE(charData.descriptors().count(), 0);
+ QCOMPARE(charData.descriptors().size(), 0);
charData.setDescriptors(QList<QLowEnergyDescriptorData>() << descData << descData2);
- QLowEnergyDescriptorData descData3(QBluetoothUuid::ExternalReportReference, "someval");
+ QLowEnergyDescriptorData descData3(QBluetoothUuid::DescriptorType::ExternalReportReference, "someval");
charData.addDescriptor(descData3);
charData.addDescriptor(QLowEnergyDescriptorData()); // Invalid.
QCOMPARE(charData.descriptors(),
@@ -628,8 +604,8 @@ void TestQLowEnergyControllerGattServer::serviceData()
QLowEnergyServiceData secondaryData;
QVERIFY(!secondaryData.isValid());
- secondaryData.setUuid(QBluetoothUuid::SerialPort);
- QCOMPARE(secondaryData.uuid(), QBluetoothUuid(QBluetoothUuid::SerialPort));
+ secondaryData.setUuid(QBluetoothUuid::ServiceClassUuid::SerialPort);
+ QCOMPARE(secondaryData.uuid(), QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
QVERIFY(secondaryData.isValid());
QVERIFY(secondaryData != QLowEnergyServiceData());
@@ -637,16 +613,16 @@ void TestQLowEnergyControllerGattServer::serviceData()
QCOMPARE(secondaryData.type(), QLowEnergyServiceData::ServiceTypeSecondary);
secondaryData.addCharacteristic(charData);
- QCOMPARE(secondaryData.characteristics().count(), 1);
+ QCOMPARE(secondaryData.characteristics().size(), 1);
secondaryData.setCharacteristics(QList<QLowEnergyCharacteristicData>());
- QCOMPARE(secondaryData.characteristics().count(), 0);
+ QCOMPARE(secondaryData.characteristics().size(), 0);
secondaryData.setCharacteristics(QList<QLowEnergyCharacteristicData>()
<< charData << QLowEnergyCharacteristicData());
QCOMPARE(secondaryData.characteristics(), QList<QLowEnergyCharacteristicData>() << charData);
QLowEnergyServiceData backupData;
- backupData.setUuid(QBluetoothUuid::SerialPort);
- QCOMPARE(backupData.uuid(), QBluetoothUuid(QBluetoothUuid::SerialPort));
+ backupData.setUuid(QBluetoothUuid::ServiceClassUuid::SerialPort);
+ QCOMPARE(backupData.uuid(), QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
QVERIFY(backupData.isValid());
QVERIFY(backupData != QLowEnergyServiceData());
@@ -667,10 +643,10 @@ void TestQLowEnergyControllerGattServer::serviceData()
QVERIFY(!secondaryService.isNull());
QCOMPARE(secondaryService->serviceUuid(), secondaryData.uuid());
const QList<QLowEnergyCharacteristic> characteristics = secondaryService->characteristics();
- QCOMPARE(characteristics.count(), 1);
+ QCOMPARE(characteristics.size(), 1);
QCOMPARE(characteristics.first().uuid(), charData.uuid());
const QList<QLowEnergyDescriptor> descriptors = characteristics.first().descriptors();
- QCOMPARE(descriptors.count(), 3);
+ QCOMPARE(descriptors.size(), 3);
const auto inUuids = QSet<QBluetoothUuid>() << descData.uuid() << descData2.uuid()
<< descData3.uuid();
QSet<QBluetoothUuid> outUuids;
@@ -679,13 +655,13 @@ void TestQLowEnergyControllerGattServer::serviceData()
QCOMPARE(inUuids, outUuids);
QLowEnergyServiceData primaryData;
- primaryData.setUuid(QBluetoothUuid::Headset);
+ primaryData.setUuid(QBluetoothUuid::ServiceClassUuid::Headset);
primaryData.addIncludedService(secondaryService.data());
const QScopedPointer<QLowEnergyService> primaryService(controller->addService(primaryData));
QVERIFY(!primaryService.isNull());
- QCOMPARE(primaryService->characteristics().count(), 0);
+ QCOMPARE(primaryService->characteristics().size(), 0);
const QList<QBluetoothUuid> includedServices = primaryService->includedServices();
- QCOMPARE(includedServices.count(), 1);
+ QCOMPARE(includedServices.size(), 1);
QCOMPARE(includedServices.first(), secondaryService->serviceUuid());
}
diff --git a/tests/auto/qlowenergycontroller/CMakeLists.txt b/tests/auto/qlowenergycontroller/CMakeLists.txt
new file mode 100644
index 00000000..f374088e
--- /dev/null
+++ b/tests/auto/qlowenergycontroller/CMakeLists.txt
@@ -0,0 +1,44 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qlowenergycontroller Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qlowenergycontroller LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qlowenergycontroller
+ SOURCES
+ tst_qlowenergycontroller.cpp
+ LIBRARIES
+ Qt::BluetoothPrivate
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qlowenergycontroller CONDITION ANDROID
+ LIBRARIES
+ Qt::Widgets
+)
+
+qt_internal_extend_target(tst_qlowenergycontroller CONDITION IOS OR MACOS
+ LIBRARIES
+ Qt::Widgets
+)
+
+set_target_properties(tst_qlowenergycontroller PROPERTIES
+ MACOSX_BUNDLE TRUE
+)
+
+if (APPLE AND NOT IOS)
+ # Ninja has trouble with relative paths, convert to absolute as a workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../shared ABSOLUTE)
+ set_target_properties(tst_qlowenergycontroller PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.macos.plist"
+ )
+endif()
diff --git a/tests/auto/qlowenergycontroller/qlowenergycontroller.pro b/tests/auto/qlowenergycontroller/qlowenergycontroller.pro
deleted file mode 100644
index 7a67e8e4..00000000
--- a/tests/auto/qlowenergycontroller/qlowenergycontroller.pro
+++ /dev/null
@@ -1,13 +0,0 @@
-QT = core bluetooth-private testlib
-
-# Android requires GUI application when running test
-android: QT += widgets
-
-TARGET = tst_qlowenergycontroller
-CONFIG += testcase
-
-SOURCES += tst_qlowenergycontroller.cpp
-
-osx|ios {
- QT += widgets
-}
diff --git a/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp b/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp
index ab393210..18365c94 100644
--- a/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp
+++ b/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -39,6 +14,13 @@
#include <QLowEnergyController>
#include <QLowEnergyCharacteristic>
+#if QT_CONFIG(permissions)
+#include <QCoreApplication>
+#include <QPermissions>
+
+#include <QtCore/qnamespace.h>
+#endif
+
#include <QDebug>
/*!
@@ -53,22 +35,6 @@
QT_USE_NAMESPACE
-// This define must be set if the platform provides access to GATT handles
-// otherwise it must not be defined. As of now the two supported platforms
-// (Android and Bluez/Linux) provide access or some notion of it.
-#ifndef Q_OS_MAC
-#define HANDLES_PROVIDED_BY_PLATFORM
-#endif
-
-#ifdef HANDLES_PROVIDED_BY_PLATFORM
-#define HANDLE_COMPARE(actual,expected) \
- if (!isBluezDbusLE) {\
- QCOMPARE(actual, expected);\
- };
-#else
-#define HANDLE_COMPARE(actual,expected)
-#endif
-
class tst_QLowEnergyController : public QObject
{
Q_OBJECT
@@ -90,6 +56,7 @@ private slots:
void tst_readWriteDescriptor();
void tst_customProgrammableDevice();
void tst_errorCases();
+ void tst_rssiError();
private:
void verifyServiceProperties(const QLowEnergyService *info);
bool verifyClientCharacteristicValue(const QByteArray& value);
@@ -99,6 +66,9 @@ private:
QBluetoothDeviceInfo remoteDeviceInfo;
QList<QBluetoothUuid> foundServices;
bool isBluezDbusLE = false;
+#if QT_CONFIG(permissions)
+ Qt::PermissionStatus permissionStatus = Qt::PermissionStatus::Undetermined;
+#endif
};
tst_QLowEnergyController::tst_QLowEnergyController()
@@ -121,6 +91,25 @@ tst_QLowEnergyController::tst_QLowEnergyController()
isBluezDbusLE = (bluetoothdVersion() >= QVersionNumber(5, 42));
qDebug() << "isDBusBluez:" << isBluezDbusLE;
#endif
+
+#if QT_CONFIG(permissions)
+ // FIXME: for Android, set additional parameters for scan and connect
+ // permissions.
+ permissionStatus = qApp->checkPermission(QBluetoothPermission{});
+ // Note: even with missing Bluetooth permission, we still can run tests on
+ // LE controller to test its logic/errors it emits, even if we cannot scan
+ // and cannot connect.
+ const bool ciRun = qEnvironmentVariable("QTEST_ENVIRONMENT").split(' ').contains("ci");
+ if (!ciRun && permissionStatus == Qt::PermissionStatus::Undetermined) {
+ QTestEventLoop loop;
+ qApp->requestPermission(QBluetoothPermission{}, [this, &loop](const QPermission &permission){
+ permissionStatus = permission.status();
+ loop.exitLoop();
+ });
+ if (permissionStatus == Qt::PermissionStatus::Undetermined)
+ loop.enterLoopMSecs(30000);
+ }
+#endif // QT_CONFIG(permissions)
}
tst_QLowEnergyController::~tst_QLowEnergyController()
@@ -140,7 +129,7 @@ void tst_QLowEnergyController::initTestCase()
qWarning("No remote device or local adapter found.");
return;
}
-#elif defined(Q_OS_OSX)
+#elif defined(Q_OS_MACOS)
// allDevices is always empty on iOS:
if (QBluetoothLocalDevice::allDevices().isEmpty()) {
qWarning("No local adapter found.");
@@ -148,6 +137,7 @@ void tst_QLowEnergyController::initTestCase()
}
#endif
+ // QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
devAgent = new QBluetoothDeviceDiscoveryAgent(this);
devAgent->setLowEnergyDiscoveryTimeout(5000);
@@ -158,7 +148,13 @@ void tst_QLowEnergyController::initTestCase()
bool deviceFound = false;
devAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
- QTRY_VERIFY_WITH_TIMEOUT(finishedSpy.count() > 0, 30000);
+#if QT_CONFIG(permissions)
+ if (permissionStatus != Qt::PermissionStatus::Granted) {
+ QCOMPARE(devAgent->error(), QBluetoothDeviceDiscoveryAgent::MissingPermissionsError);
+ return;
+ }
+#endif
+ QTRY_VERIFY_WITH_TIMEOUT(!finishedSpy.isEmpty(), 30000);
const QList<QBluetoothDeviceInfo> infos = devAgent->discoveredDevices();
for (const QBluetoothDeviceInfo &info : infos) {
#ifndef Q_OS_MAC
@@ -174,7 +170,8 @@ void tst_QLowEnergyController::initTestCase()
}
}
- QVERIFY2(deviceFound, "Cannot find remote device.");
+ if (!deviceFound || !remoteDeviceInfo.isValid())
+ qWarning() << "The sensor tag device was not found, will skip most of the test";
// These are the services exported by the TI SensorTag
#ifndef Q_OS_MAC
@@ -218,13 +215,22 @@ void tst_QLowEnergyController::cleanupTestCase()
void tst_QLowEnergyController::tst_emptyCtor()
{
{
- QBluetoothAddress remoteAddress;
- QLowEnergyController control(remoteAddress);
- QSignalSpy connectedSpy(&control, SIGNAL(connected()));
- QSignalSpy stateSpy(&control, SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
- QSignalSpy errorSpy(&control, SIGNAL(error(QLowEnergyController::Error)));
- QCOMPARE(control.error(), QLowEnergyController::NoError);
- control.connectToDevice();
+ QScopedPointer<QLowEnergyController> control(QLowEnergyController::createCentral(QBluetoothDeviceInfo()));
+ QSignalSpy connectedSpy(control.data(), SIGNAL(connected()));
+ QSignalSpy stateSpy(control.data(), SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
+ QSignalSpy errorSpy(control.data(), SIGNAL(errorOccurred(QLowEnergyController::Error)));
+#if QT_CONFIG(bluez)
+ QBluetoothLocalDevice localDevice;
+ // With bluez Kernel ATT interface we get the error already at construction time if the
+ // device does not have a bluetooth adapter
+ if (!isBluezDbusLE && !localDevice.isValid())
+ QCOMPARE(control->error(), QLowEnergyController::InvalidBluetoothAdapterError);
+ else
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
+#else
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
+#endif
+ control->connectToDevice();
QTRY_VERIFY_WITH_TIMEOUT(!errorSpy.isEmpty(), 10000);
@@ -237,13 +243,22 @@ void tst_QLowEnergyController::tst_emptyCtor()
}
{
- QBluetoothDeviceInfo deviceInfo;
- QLowEnergyController control(deviceInfo);
- QSignalSpy connectedSpy(&control, SIGNAL(connected()));
- QSignalSpy stateSpy(&control, SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
- QSignalSpy errorSpy(&control, SIGNAL(error(QLowEnergyController::Error)));
- QCOMPARE(control.error(), QLowEnergyController::NoError);
- control.connectToDevice();
+ QScopedPointer<QLowEnergyController> control(QLowEnergyController::createCentral(
+ QBluetoothDeviceInfo(), QBluetoothAddress(), this));
+ QSignalSpy connectedSpy(control.data(), SIGNAL(connected()));
+ QSignalSpy stateSpy(control.data(), SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
+ QSignalSpy errorSpy(control.data(), SIGNAL(errorOccurred(QLowEnergyController::Error)));
+#if QT_CONFIG(bluez)
+ QBluetoothLocalDevice localDevice;
+ if (!isBluezDbusLE && !localDevice.isValid())
+ QCOMPARE(control->error(), QLowEnergyController::InvalidBluetoothAdapterError);
+ else
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
+#else
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
+#endif
+
+ control->connectToDevice();
QTRY_VERIFY_WITH_TIMEOUT(!errorSpy.isEmpty(), 10000);
@@ -254,7 +269,6 @@ void tst_QLowEnergyController::tst_emptyCtor()
QVERIFY(lastError == QLowEnergyController::UnknownRemoteDeviceError // if local device on platform found
|| lastError == QLowEnergyController::InvalidBluetoothAdapterError); // otherwise, e.g. fallback backend
}
-
}
void tst_QLowEnergyController::tst_connect()
@@ -268,148 +282,149 @@ void tst_QLowEnergyController::tst_connect()
#endif
QSKIP("No local Bluetooth or remote BTLE device found. Skipping test.");
- QLowEnergyController control(remoteDeviceInfo);
- QCOMPARE(remoteDeviceInfo.deviceUuid(), control.remoteDeviceUuid());
- QCOMPARE(control.role(), QLowEnergyController::CentralRole);
- QSignalSpy connectedSpy(&control, SIGNAL(connected()));
- QSignalSpy disconnectedSpy(&control, SIGNAL(disconnected()));
+ QScopedPointer<QLowEnergyController> control(QLowEnergyController::createCentral(remoteDeviceInfo));
+ QCOMPARE(remoteDeviceInfo.deviceUuid(), control->remoteDeviceUuid());
+ QCOMPARE(control->role(), QLowEnergyController::CentralRole);
+ QSignalSpy connectedSpy(control.data(), SIGNAL(connected()));
+ QSignalSpy disconnectedSpy(control.data(), SIGNAL(disconnected()));
if (remoteDeviceInfo.name().isEmpty())
- QVERIFY(control.remoteName().isEmpty());
+ QVERIFY(control->remoteName().isEmpty());
else
- QCOMPARE(control.remoteName(), remoteDeviceInfo.name());
+ QCOMPARE(control->remoteName(), remoteDeviceInfo.name());
#if !defined(Q_OS_IOS) && !defined(Q_OS_TVOS) && !QT_CONFIG(winrt_bt)
const QBluetoothAddress localAdapter = localAdapters.at(0).address();
- QCOMPARE(control.localAddress(), localAdapter);
- QVERIFY(!control.localAddress().isNull());
+ QCOMPARE(control->localAddress(), localAdapter);
+ QVERIFY(!control->localAddress().isNull());
#endif
#ifndef Q_OS_MAC
- QCOMPARE(control.remoteAddress(), remoteDevice);
+ QCOMPARE(control->remoteAddress(), remoteDevice);
#endif
- QCOMPARE(control.state(), QLowEnergyController::UnconnectedState);
- QCOMPARE(control.error(), QLowEnergyController::NoError);
- QVERIFY(control.errorString().isEmpty());
- QCOMPARE(disconnectedSpy.count(), 0);
- QCOMPARE(connectedSpy.count(), 0);
- QVERIFY(control.services().isEmpty());
+ QCOMPARE(control->state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
+ QVERIFY(control->errorString().isEmpty());
+ QCOMPARE(disconnectedSpy.size(), 0);
+ QCOMPARE(connectedSpy.size(), 0);
+ QVERIFY(control->services().isEmpty());
bool wasError = false;
- control.connectToDevice();
- QTRY_IMPL(control.state() != QLowEnergyController::ConnectingState,
- 10000);
+ control->connectToDevice();
+ QTRY_IMPL(control->state() != QLowEnergyController::ConnectingState,
+ 10000)
- QCOMPARE(disconnectedSpy.count(), 0);
- if (control.error() != QLowEnergyController::NoError) {
+ QCOMPARE(disconnectedSpy.size(), 0);
+ if (control->error() != QLowEnergyController::NoError) {
//error during connect
- QCOMPARE(connectedSpy.count(), 0);
- QCOMPARE(control.state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(connectedSpy.size(), 0);
+ QCOMPARE(control->state(), QLowEnergyController::UnconnectedState);
wasError = true;
- } else if (control.state() == QLowEnergyController::ConnectingState) {
+ } else if (control->state() == QLowEnergyController::ConnectingState) {
//timeout
- QCOMPARE(connectedSpy.count(), 0);
- QVERIFY(control.errorString().isEmpty());
- QCOMPARE(control.error(), QLowEnergyController::NoError);
- QVERIFY(control.services().isEmpty());
+ QCOMPARE(connectedSpy.size(), 0);
+ QVERIFY(control->errorString().isEmpty());
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
+ QVERIFY(control->services().isEmpty());
QSKIP("Connection to LE device cannot be established. Skipping test.");
return;
} else {
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
- QCOMPARE(connectedSpy.count(), 1);
- QCOMPARE(control.error(), QLowEnergyController::NoError);
- QVERIFY(control.errorString().isEmpty());
+ QCOMPARE(control->state(), QLowEnergyController::ConnectedState);
+ QCOMPARE(connectedSpy.size(), 1);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
+ QVERIFY(control->errorString().isEmpty());
}
- QVERIFY(control.services().isEmpty());
+ QVERIFY(control->services().isEmpty());
QList<QLowEnergyService *> savedReferences;
if (!wasError) {
- QSignalSpy discoveryFinishedSpy(&control, SIGNAL(discoveryFinished()));
- QSignalSpy serviceFoundSpy(&control, SIGNAL(serviceDiscovered(QBluetoothUuid)));
- QSignalSpy stateSpy(&control, SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
- control.discoverServices();
- QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 20000);
- QCOMPARE(stateSpy.count(), 2);
+ QSignalSpy discoveryFinishedSpy(control.data(), SIGNAL(discoveryFinished()));
+ QSignalSpy serviceFoundSpy(control.data(), SIGNAL(serviceDiscovered(QBluetoothUuid)));
+ QSignalSpy stateSpy(control.data(), SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
+ control->discoverServices();
+ QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.size() == 1, 20000);
+ QCOMPARE(stateSpy.size(), 2);
QCOMPARE(stateSpy.at(0).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveringState);
QCOMPARE(stateSpy.at(1).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveredState);
QVERIFY(!serviceFoundSpy.isEmpty());
- QVERIFY(serviceFoundSpy.count() >= foundServices.count());
+ QVERIFY(serviceFoundSpy.size() >= foundServices.size());
QVERIFY(!serviceFoundSpy.isEmpty());
QList<QBluetoothUuid> listing;
- for (int i = 0; i < serviceFoundSpy.count(); i++) {
+ for (qsizetype i = 0; i < serviceFoundSpy.size(); ++i) {
const QVariant v = serviceFoundSpy[i].at(0);
listing.append(v.value<QBluetoothUuid>());
}
- for (const QBluetoothUuid &uuid : qAsConst(foundServices)) {
+ for (const QBluetoothUuid &uuid : std::as_const(foundServices)) {
QVERIFY2(listing.contains(uuid),
uuid.toString().toLatin1());
- QLowEnergyService *service = control.createServiceObject(uuid);
+ QLowEnergyService *service = control->createServiceObject(uuid);
QVERIFY2(service, uuid.toString().toLatin1());
savedReferences.append(service);
QCOMPARE(service->type(), QLowEnergyService::PrimaryService);
- QCOMPARE(service->state(), QLowEnergyService::DiscoveryRequired);
+ QCOMPARE(service->state(), QLowEnergyService::RemoteService);
}
// unrelated uuids don't return valid service object
// invalid service uuid
- QVERIFY(!control.createServiceObject(QBluetoothUuid()));
+ QVERIFY(!control->createServiceObject(QBluetoothUuid()));
// some random uuid
- QVERIFY(!control.createServiceObject(QBluetoothUuid(QBluetoothUuid::DeviceName)));
+ QVERIFY(!control->createServiceObject(
+ QBluetoothUuid(QBluetoothUuid::CharacteristicType::DeviceName)));
// initiate characteristic discovery
- for (QLowEnergyService *service : qAsConst(savedReferences)) {
+ for (QLowEnergyService *service : std::as_const(savedReferences)) {
qDebug() << "Discovering" << service->serviceUuid();
QSignalSpy stateSpy(service,
SIGNAL(stateChanged(QLowEnergyService::ServiceState)));
- QSignalSpy errorSpy(service, SIGNAL(error(QLowEnergyService::ServiceError)));
+ QSignalSpy errorSpy(service, SIGNAL(errorOccurred(QLowEnergyService::ServiceError)));
service->discoverDetails();
QTRY_VERIFY_WITH_TIMEOUT(
- service->state() == QLowEnergyService::ServiceDiscovered, 10000);
+ service->state() == QLowEnergyService::RemoteServiceDiscovered, 10000);
- QCOMPARE(errorSpy.count(), 0); //no error
- QCOMPARE(stateSpy.count(), 2); //
+ QCOMPARE(errorSpy.size(), 0); //no error
+ QCOMPARE(stateSpy.size(), 2); //
verifyServiceProperties(service);
}
// ensure that related service objects share same state
- for (QLowEnergyService* originalService : qAsConst(savedReferences)) {
- QLowEnergyService *newService = control.createServiceObject(
+ for (QLowEnergyService* originalService : std::as_const(savedReferences)) {
+ QLowEnergyService *newService = control->createServiceObject(
originalService->serviceUuid());
QVERIFY(newService);
- QCOMPARE(newService->state(), QLowEnergyService::ServiceDiscovered);
+ QCOMPARE(newService->state(), QLowEnergyService::RemoteServiceDiscovered);
delete newService;
}
}
// Finish off
- control.disconnectFromDevice();
+ control->disconnectFromDevice();
QTRY_VERIFY_WITH_TIMEOUT(
- control.state() == QLowEnergyController::UnconnectedState,
+ control->state() == QLowEnergyController::UnconnectedState,
10000);
if (wasError) {
- QCOMPARE(disconnectedSpy.count(), 0);
+ QCOMPARE(disconnectedSpy.size(), 0);
} else {
- QCOMPARE(disconnectedSpy.count(), 1);
+ QCOMPARE(disconnectedSpy.size(), 1);
// after disconnect all service references must be invalid
- for (const QLowEnergyService *entry : qAsConst(savedReferences)) {
+ for (const QLowEnergyService *entry : std::as_const(savedReferences)) {
const QBluetoothUuid &uuid = entry->serviceUuid();
QVERIFY2(entry->state() == QLowEnergyService::InvalidService,
uuid.toString().toLatin1());
//after disconnect all related characteristics and descriptors are invalid
QList<QLowEnergyCharacteristic> chars = entry->characteristics();
- for (int i = 0; i < chars.count(); i++) {
+ for (qsizetype i = 0; i < chars.size(); ++i) {
QCOMPARE(chars.at(i).isValid(), false);
QList<QLowEnergyDescriptor> descriptors = chars[i].descriptors();
- for (int j = 0; j < descriptors.count(); j++)
+ for (qsizetype j = 0; j < descriptors.size(); ++j)
QCOMPARE(descriptors[j].isValid(), false);
}
}
@@ -429,78 +444,78 @@ void tst_QLowEnergyController::tst_concurrentDiscovery()
if (!remoteDeviceInfo.isValid())
QSKIP("No remote BTLE device found. Skipping test.");
- QLowEnergyController control(remoteDeviceInfo);
+ QScopedPointer<QLowEnergyController> control(QLowEnergyController::createCentral(remoteDeviceInfo));
- QCOMPARE(control.state(), QLowEnergyController::UnconnectedState);
- QCOMPARE(control.error(), QLowEnergyController::NoError);
+ QCOMPARE(control->state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
- control.connectToDevice();
+ control->connectToDevice();
{
- QTRY_IMPL(control.state() != QLowEnergyController::ConnectingState,
- 30000);
+ QTRY_IMPL(control->state() != QLowEnergyController::ConnectingState,
+ 30000)
}
- if (control.state() == QLowEnergyController::ConnectingState
- || control.error() != QLowEnergyController::NoError) {
+ if (control->state() == QLowEnergyController::ConnectingState
+ || control->error() != QLowEnergyController::NoError) {
// default BTLE backend forever hangs in ConnectingState
QSKIP("Cannot connect to remote device");
}
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
+ QCOMPARE(control->state(), QLowEnergyController::ConnectedState);
// 2. new controller to same device fails
{
-#ifdef Q_OS_DARWIN
- QLowEnergyController control2(remoteDeviceInfo);
-#else
- QLowEnergyController control2(remoteDevice);
-#endif
- control2.connectToDevice();
+
+ QScopedPointer<QLowEnergyController> control2(
+ QLowEnergyController::createCentral(remoteDeviceInfo));
+ control2->connectToDevice();
{
- QTRY_IMPL(control2.state() != QLowEnergyController::ConnectingState,
- 30000);
+ QTRY_IMPL(control2->state() != QLowEnergyController::ConnectingState,
+ 30000)
}
#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN) || QT_CONFIG(winrt_bt)
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
- QCOMPARE(control2.state(), QLowEnergyController::ConnectedState);
- control2.disconnectFromDevice();
+ QCOMPARE(control->state(), QLowEnergyController::ConnectedState);
+ QCOMPARE(control2->state(), QLowEnergyController::ConnectedState);
+ control2->disconnectFromDevice();
QTest::qWait(3000);
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
- QCOMPARE(control2.state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->state(), QLowEnergyController::ConnectedState);
+ QCOMPARE(control2->state(), QLowEnergyController::UnconnectedState);
#else
if (!isBluezDbusLE) {
// see QTBUG-42519
// Linux non-DBus GATT cannot maintain two controller connections at the same time
- QCOMPARE(control.state(), QLowEnergyController::UnconnectedState);
- QCOMPARE(control2.state(), QLowEnergyController::ConnectedState);
- control2.disconnectFromDevice();
- QTRY_COMPARE(control2.state(), QLowEnergyController::UnconnectedState);
- QTRY_COMPARE(control2.error(), QLowEnergyController::NoError);
+ QCOMPARE(control->state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control2->state(), QLowEnergyController::ConnectedState);
+ control2->disconnectFromDevice();
+ QTRY_COMPARE(control2->state(), QLowEnergyController::UnconnectedState);
+ QTRY_COMPARE(control2->error(), QLowEnergyController::NoError);
// reconnect control
- control.connectToDevice();
+ control->connectToDevice();
{
- QTRY_VERIFY_WITH_TIMEOUT(control.state() != QLowEnergyController::ConnectingState,
+ QTRY_VERIFY_WITH_TIMEOUT(control->state() != QLowEnergyController::ConnectingState,
30000);
}
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
+ QCOMPARE(control->state(), QLowEnergyController::ConnectedState);
} else {
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
- QCOMPARE(control2.state(), QLowEnergyController::ConnectedState);
- control2.disconnectFromDevice();
- QTRY_COMPARE(control2.state(), QLowEnergyController::UnconnectedState);
- QTRY_COMPARE(control2.error(), QLowEnergyController::NoError);
- QTRY_COMPARE(control.state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->state(), QLowEnergyController::ConnectedState);
+ QCOMPARE(control2->state(), QLowEnergyController::ConnectedState);
+ QTRY_COMPARE(control2->error(), QLowEnergyController::NoError);
+ control2->disconnectFromDevice();
+ QTRY_COMPARE(control2->state(), QLowEnergyController::UnconnectedState);
+ QTRY_COMPARE(control->error(), QLowEnergyController::NoError);
+ QTRY_COMPARE(control2->error(), QLowEnergyController::NoError);
+ QTRY_COMPARE(control->state(), QLowEnergyController::UnconnectedState);
// reconnect control
- control.connectToDevice();
+ control->connectToDevice();
{
- QTRY_VERIFY_WITH_TIMEOUT(control.state() != QLowEnergyController::ConnectingState,
+ QTRY_VERIFY_WITH_TIMEOUT(control->state() != QLowEnergyController::ConnectingState,
30000);
}
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
+ QCOMPARE(control->state(), QLowEnergyController::ConnectedState);
}
#endif
}
@@ -509,11 +524,11 @@ void tst_QLowEnergyController::tst_concurrentDiscovery()
* for multiple services at the same time.
* */
- QSignalSpy discoveryFinishedSpy(&control, SIGNAL(discoveryFinished()));
- QSignalSpy stateSpy(&control, SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
- control.discoverServices();
- QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 20000);
- QCOMPARE(stateSpy.count(), 2);
+ QSignalSpy discoveryFinishedSpy(control.data(), SIGNAL(discoveryFinished()));
+ QSignalSpy stateSpy(control.data(), SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
+ control->discoverServices();
+ QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.size() == 1, 20000);
+ QCOMPARE(stateSpy.size(), 2);
QCOMPARE(stateSpy.at(0).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveringState);
QCOMPARE(stateSpy.at(1).at(0).value<QLowEnergyController::ControllerState>(),
@@ -524,13 +539,13 @@ void tst_QLowEnergyController::tst_concurrentDiscovery()
#define MAX_SERVICES_SAME_TIME_ACCESS 3
QLowEnergyService *services[MAX_SERVICES_SAME_TIME_ACCESS];
- QVERIFY(control.services().count() >= MAX_SERVICES_SAME_TIME_ACCESS);
+ QVERIFY(control->services().size() >= MAX_SERVICES_SAME_TIME_ACCESS);
- QList<QBluetoothUuid> uuids = control.services();
+ QList<QBluetoothUuid> uuids = control->services();
// initialize services
for (int i = 0; i<MAX_SERVICES_SAME_TIME_ACCESS; i++) {
- services[i] = control.createServiceObject(uuids.at(i), this);
+ services[i] = control->createServiceObject(uuids.at(i), this);
QVERIFY(services[i]);
}
@@ -542,7 +557,7 @@ void tst_QLowEnergyController::tst_concurrentDiscovery()
for (int i = 0; i<MAX_SERVICES_SAME_TIME_ACCESS; i++) {
qWarning() << "Waiting for" << i << services[i]->serviceUuid();
QTRY_VERIFY_WITH_TIMEOUT(
- services[i]->state() == QLowEnergyService::ServiceDiscovered,
+ services[i]->state() == QLowEnergyService::RemoteServiceDiscovered,
30000);
}
@@ -554,24 +569,24 @@ void tst_QLowEnergyController::tst_concurrentDiscovery()
QVERIFY(!services[i]->contains(QLowEnergyDescriptor()));
}
- control.disconnectFromDevice();
- QTRY_VERIFY_WITH_TIMEOUT(control.state() == QLowEnergyController::UnconnectedState,
+ control->disconnectFromDevice();
+ QTRY_VERIFY_WITH_TIMEOUT(control->state() == QLowEnergyController::UnconnectedState,
30000);
discoveryFinishedSpy.clear();
// redo the discovery with same controller
QLowEnergyService *services_second[MAX_SERVICES_SAME_TIME_ACCESS];
- control.connectToDevice();
+ control->connectToDevice();
{
- QTRY_IMPL(control.state() != QLowEnergyController::ConnectingState,
+ QTRY_IMPL(control->state() != QLowEnergyController::ConnectingState,
30000);
}
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
+ QCOMPARE(control->state(), QLowEnergyController::ConnectedState);
stateSpy.clear();
- control.discoverServices();
- QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 20000);
- QCOMPARE(stateSpy.count(), 2);
+ control->discoverServices();
+ QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.size() == 1, 20000);
+ QCOMPARE(stateSpy.size(), 2);
QCOMPARE(stateSpy.at(0).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveringState);
QCOMPARE(stateSpy.at(1).at(0).value<QLowEnergyController::ControllerState>(),
@@ -579,10 +594,10 @@ void tst_QLowEnergyController::tst_concurrentDiscovery()
// get all details
for (int i = 0; i<MAX_SERVICES_SAME_TIME_ACCESS; i++) {
- services_second[i] = control.createServiceObject(uuids.at(i), this);
+ services_second[i] = control->createServiceObject(uuids.at(i), this);
QVERIFY(services_second[i]->parent() == this);
QVERIFY(services[i]);
- QVERIFY(services_second[i]->state() == QLowEnergyService::DiscoveryRequired);
+ QVERIFY(services_second[i]->state() == QLowEnergyService::RemoteService);
services_second[i]->discoverDetails();
}
@@ -590,7 +605,7 @@ void tst_QLowEnergyController::tst_concurrentDiscovery()
for (int i = 0; i<MAX_SERVICES_SAME_TIME_ACCESS; i++) {
qWarning() << "Waiting for" << i << services_second[i]->serviceUuid();
QTRY_VERIFY_WITH_TIMEOUT(
- services_second[i]->state() == QLowEnergyService::ServiceDiscovered,
+ services_second[i]->state() == QLowEnergyService::RemoteServiceDiscovered,
30000);
QCOMPARE(services_second[i]->serviceName(), services[i]->serviceName());
QCOMPARE(services_second[i]->serviceUuid(), services[i]->serviceUuid());
@@ -601,12 +616,12 @@ void tst_QLowEnergyController::tst_concurrentDiscovery()
verifyServiceProperties(services_second[i]);
//after disconnect all related characteristics and descriptors are invalid
const QList<QLowEnergyCharacteristic> chars = services[i]->characteristics();
- for (int j = 0; j < chars.count(); j++) {
+ for (qsizetype j = 0; j < chars.size(); ++j) {
QCOMPARE(chars.at(j).isValid(), false);
QVERIFY(services[i]->contains(chars[j]));
QVERIFY(!services_second[i]->contains(chars[j]));
const QList<QLowEnergyDescriptor> descriptors = chars[j].descriptors();
- for (int k = 0; k < descriptors.count(); k++) {
+ for (qsizetype k = 0; k < descriptors.size(); ++k) {
QCOMPARE(descriptors[k].isValid(), false);
services[i]->contains(descriptors[k]);
QVERIFY(!services_second[i]->contains(chars[j]));
@@ -617,7 +632,7 @@ void tst_QLowEnergyController::tst_concurrentDiscovery()
QCOMPARE(services[i]->serviceName(), services_second[i]->serviceName());
QCOMPARE(services[i]->type(), services_second[i]->type());
QVERIFY(services[i]->state() == QLowEnergyService::InvalidService);
- QVERIFY(services_second[i]->state() == QLowEnergyService::ServiceDiscovered);
+ QVERIFY(services_second[i]->state() == QLowEnergyService::RemoteServiceDiscovered);
}
// cleanup
@@ -626,7 +641,9 @@ void tst_QLowEnergyController::tst_concurrentDiscovery()
delete services_second[i];
}
- control.disconnectFromDevice();
+ control->disconnectFromDevice();
+ QTRY_COMPARE(control->state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
}
void tst_QLowEnergyController::verifyServiceProperties(
@@ -636,42 +653,38 @@ void tst_QLowEnergyController::verifyServiceProperties(
QBluetoothUuid(QString("00001800-0000-1000-8000-00805f9b34fb"))) {
qDebug() << "Verifying GAP Service";
QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QCOMPARE(chars.count(), 5);
+ QCOMPARE(chars.size(), 5);
// Device Name
QString temp("00002a00-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0x3));
QCOMPARE(chars[0].properties(), QLowEnergyCharacteristic::Read);
QCOMPARE(chars[0].value(), QByteArray::fromHex("544920424c452053656e736f7220546167"));
QVERIFY(chars[0].isValid());
- QCOMPARE(chars[0].descriptors().count(), 0);
+ QCOMPARE(chars[0].descriptors().size(), 0);
QVERIFY(info->contains(chars[0]));
// Appearance
temp = QString("00002a01-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[1].handle(), QLowEnergyHandle(0x5));
QCOMPARE(chars[1].properties(), QLowEnergyCharacteristic::Read);
QCOMPARE(chars[1].value(), QByteArray::fromHex("0000"));
QVERIFY(chars[1].isValid());
- QCOMPARE(chars[1].descriptors().count(), 0);
+ QCOMPARE(chars[1].descriptors().size(), 0);
QVERIFY(info->contains(chars[1]));
// Peripheral Privacy Flag
temp = QString("00002a02-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[2].handle(), QLowEnergyHandle(0x7));
QVERIFY(chars[2].properties() & QLowEnergyCharacteristic::Read);
QCOMPARE(chars[2].value(), QByteArray::fromHex("00"));
QVERIFY(chars[2].isValid());
- QCOMPARE(chars[2].descriptors().count(), 0);
+ QCOMPARE(chars[2].descriptors().size(), 0);
QVERIFY(info->contains(chars[2]));
// Reconnection Address
temp = QString("00002a03-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[3].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[3].handle(), QLowEnergyHandle(0x9));
//Early firmware version had this characteristic as Read|Write and may fail
QCOMPARE(chars[3].properties(), QLowEnergyCharacteristic::Write);
if (chars[3].properties() & QLowEnergyCharacteristic::Read)
@@ -679,87 +692,80 @@ void tst_QLowEnergyController::verifyServiceProperties(
else
QCOMPARE(chars[3].value(), QByteArray());
QVERIFY(chars[3].isValid());
- QCOMPARE(chars[3].descriptors().count(), 0);
+ QCOMPARE(chars[3].descriptors().size(), 0);
QVERIFY(info->contains(chars[3]));
// Peripheral Preferred Connection Parameters
temp = QString("00002a04-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[4].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[4].handle(), QLowEnergyHandle(0xb));
QCOMPARE(chars[4].properties(), QLowEnergyCharacteristic::Read);
QCOMPARE(chars[4].value(), QByteArray::fromHex("5000a0000000e803"));
QVERIFY(chars[4].isValid());
- QCOMPARE(chars[4].descriptors().count(), 0);
+ QCOMPARE(chars[4].descriptors().size(), 0);
QVERIFY(info->contains(chars[4]));
} else if (info->serviceUuid() ==
QBluetoothUuid(QString("00001801-0000-1000-8000-00805f9b34fb"))) {
qDebug() << "Verifying GATT Service";
QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QCOMPARE(chars.count(), 1);
+ QCOMPARE(chars.size(), 1);
// Service Changed
QString temp("00002a05-0000-1000-8000-00805f9b34fb");
//this should really be readable according to GATT Service spec
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0xe));
QCOMPARE(chars[0].properties(), QLowEnergyCharacteristic::Indicate);
QCOMPARE(chars[0].value(), QByteArray());
QVERIFY(chars[0].isValid());
QVERIFY(info->contains(chars[0]));
- QCOMPARE(chars[0].descriptors().count(), 1);
+ QCOMPARE(chars[0].descriptors().size(), 1);
QCOMPARE(chars[0].descriptors().at(0).isValid(), true);
- HANDLE_COMPARE(chars[0].descriptors().at(0).handle(), QLowEnergyHandle(0xf));
QCOMPARE(chars[0].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
QCOMPARE(chars[0].descriptors().at(0).type(),
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(verifyClientCharacteristicValue(chars[0].descriptors().at(0).value()));
QVERIFY(info->contains(chars[0].descriptors().at(0)));
} else if (info->serviceUuid() ==
QBluetoothUuid(QString("0000180a-0000-1000-8000-00805f9b34fb"))) {
qDebug() << "Verifying Device Information";
QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QCOMPARE(chars.count(), 9);
+ QCOMPARE(chars.size(), 9);
// System ID
QString temp("00002a23-0000-1000-8000-00805f9b34fb");
//this should really be readable according to GATT Service spec
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0x12));
QCOMPARE(chars[0].properties(), QLowEnergyCharacteristic::Read);
// Do not read the System ID as it is different for every device
// QEXPECT_FAIL("", "The value is different on different devices", Continue);
// QCOMPARE(chars[0].value(), QByteArray::fromHex("6e41ab0000296abc"));
QVERIFY(chars[0].isValid());
QVERIFY(info->contains(chars[0]));
- QCOMPARE(chars[0].descriptors().count(), 0);
+ QCOMPARE(chars[0].descriptors().size(), 0);
// Model Number
temp = QString("00002a24-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[1].handle(), QLowEnergyHandle(0x14));
QCOMPARE(chars[1].properties(), QLowEnergyCharacteristic::Read);
QCOMPARE(chars[1].value(), QByteArray::fromHex("4e2e412e00"));
QVERIFY(chars[1].isValid());
QVERIFY(info->contains(chars[1]));
- QCOMPARE(chars[1].descriptors().count(), 0);
+ QCOMPARE(chars[1].descriptors().size(), 0);
// Serial Number
temp = QString("00002a25-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[2].handle(), QLowEnergyHandle(0x16));
QCOMPARE(chars[2].properties(),
(QLowEnergyCharacteristic::Read));
QCOMPARE(chars[2].value(), QByteArray::fromHex("4e2e412e00"));
QVERIFY(chars[2].isValid());
QVERIFY(info->contains(chars[2]));
- QCOMPARE(chars[2].descriptors().count(), 0);
+ QCOMPARE(chars[2].descriptors().size(), 0);
// Firmware Revision
temp = QString("00002a26-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[3].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[3].handle(), QLowEnergyHandle(0x18));
QCOMPARE(chars[3].properties(),
(QLowEnergyCharacteristic::Read));
//FW rev. : 1.5 (Oct 23 2013)
@@ -767,95 +773,87 @@ void tst_QLowEnergyController::verifyServiceProperties(
QCOMPARE(chars[3].value(), QByteArray::fromHex("312e3520284f637420323320323031332900"));
QVERIFY(chars[3].isValid());
QVERIFY(info->contains(chars[3]));
- QCOMPARE(chars[3].descriptors().count(), 0);
+ QCOMPARE(chars[3].descriptors().size(), 0);
// Hardware Revision
temp = QString("00002a27-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[4].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[4].handle(), QLowEnergyHandle(0x1a));
QCOMPARE(chars[4].properties(),
(QLowEnergyCharacteristic::Read));
QCOMPARE(chars[4].value(), QByteArray::fromHex("4e2e412e00"));
QVERIFY(chars[4].isValid());
QVERIFY(info->contains(chars[4]));
- QCOMPARE(chars[4].descriptors().count(), 0);
+ QCOMPARE(chars[4].descriptors().size(), 0);
// Software Revision
temp = QString("00002a28-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[5].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[5].handle(), QLowEnergyHandle(0x1c));
QCOMPARE(chars[5].properties(),
(QLowEnergyCharacteristic::Read));
QCOMPARE(chars[5].value(), QByteArray::fromHex("4e2e412e00"));
QVERIFY(chars[5].isValid());
QVERIFY(info->contains(chars[5]));
- QCOMPARE(chars[5].descriptors().count(), 0);
+ QCOMPARE(chars[5].descriptors().size(), 0);
// Manufacturer Name
temp = QString("00002a29-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[6].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[6].handle(), QLowEnergyHandle(0x1e));
QCOMPARE(chars[6].properties(),
(QLowEnergyCharacteristic::Read));
QCOMPARE(chars[6].value(), QByteArray::fromHex("546578617320496e737472756d656e747300"));
QVERIFY(chars[6].isValid());
QVERIFY(info->contains(chars[6]));
- QCOMPARE(chars[6].descriptors().count(), 0);
+ QCOMPARE(chars[6].descriptors().size(), 0);
// IEEE
temp = QString("00002a2a-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[7].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[7].handle(), QLowEnergyHandle(0x20));
QCOMPARE(chars[7].properties(),
(QLowEnergyCharacteristic::Read));
QCOMPARE(chars[7].value(), QByteArray::fromHex("fe006578706572696d656e74616c"));
QVERIFY(chars[7].isValid());
QVERIFY(info->contains(chars[7]));
- QCOMPARE(chars[7].descriptors().count(), 0);
+ QCOMPARE(chars[7].descriptors().size(), 0);
// PnP ID
temp = QString("00002a50-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[8].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[8].handle(), QLowEnergyHandle(0x22));
QCOMPARE(chars[8].properties(),
(QLowEnergyCharacteristic::Read));
QCOMPARE(chars[8].value(), QByteArray::fromHex("010d0000001001"));
QVERIFY(chars[8].isValid());
QVERIFY(info->contains(chars[8]));
- QCOMPARE(chars[8].descriptors().count(), 0);
+ QCOMPARE(chars[8].descriptors().size(), 0);
} else if (info->serviceUuid() ==
QBluetoothUuid(QString("f000aa00-0451-4000-b000-000000000000"))) {
qDebug() << "Verifying Temperature";
QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QVERIFY(chars.count() >= 2);
+ QVERIFY(chars.size() >= 2);
// Temp Data
QString temp("f000aa01-0451-4000-b000-000000000000");
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0x25));
QCOMPARE(chars[0].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify));
QCOMPARE(chars[0].value(), QByteArray::fromHex("00000000"));
QVERIFY(chars[0].isValid());
QVERIFY(info->contains(chars[0]));
- QCOMPARE(chars[0].descriptors().count(), 2);
+ QCOMPARE(chars[0].descriptors().size(), 2);
//descriptor checks
QCOMPARE(chars[0].descriptors().at(0).isValid(), true);
- HANDLE_COMPARE(chars[0].descriptors().at(0).handle(), QLowEnergyHandle(0x26));
QCOMPARE(chars[0].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
QCOMPARE(chars[0].descriptors().at(0).type(),
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(verifyClientCharacteristicValue(chars[0].descriptors().at(0).value()));
QVERIFY(info->contains(chars[0].descriptors().at(0)));
QCOMPARE(chars[0].descriptors().at(1).isValid(), true);
- HANDLE_COMPARE(chars[0].descriptors().at(1).handle(), QLowEnergyHandle(0x27));
QCOMPARE(chars[0].descriptors().at(1).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[0].descriptors().at(1).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
// value different in other revisions and test may fail
QCOMPARE(chars[0].descriptors().at(1).value(),
QByteArray::fromHex("54656d702e2044617461"));
@@ -864,21 +862,19 @@ void tst_QLowEnergyController::verifyServiceProperties(
// Temp Config
temp = QString("f000aa02-0451-4000-b000-000000000000");
QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[1].handle(), QLowEnergyHandle(0x29));
QCOMPARE(chars[1].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(chars[1].value(), QByteArray::fromHex("00"));
QVERIFY(chars[1].isValid());
QVERIFY(info->contains(chars[1]));
- QCOMPARE(chars[1].descriptors().count(), 1);
+ QCOMPARE(chars[1].descriptors().size(), 1);
//descriptor checks
QCOMPARE(chars[1].descriptors().at(0).isValid(), true);
- HANDLE_COMPARE(chars[1].descriptors().at(0).handle(), QLowEnergyHandle(0x2a));
QCOMPARE(chars[1].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[1].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
// value different in other revisions and test may fail
QCOMPARE(chars[1].descriptors().at(0).value(),
QByteArray::fromHex("54656d702e20436f6e662e"));
@@ -886,24 +882,22 @@ void tst_QLowEnergyController::verifyServiceProperties(
//Temp Period (introduced by later firmware versions)
- if (chars.count() > 2) {
+ if (chars.size() > 2) {
temp = QString("f000aa03-0451-4000-b000-000000000000");
QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[2].handle(), QLowEnergyHandle(0x2c));
QCOMPARE(chars[2].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(chars[2].value(), QByteArray::fromHex("64"));
QVERIFY(chars[2].isValid());
QVERIFY(info->contains(chars[2]));
- QCOMPARE(chars[2].descriptors().count(), 1);
+ QCOMPARE(chars[2].descriptors().size(), 1);
//descriptor checks
QCOMPARE(chars[2].descriptors().at(0).isValid(), true);
- HANDLE_COMPARE(chars[2].descriptors().at(0).handle(), QLowEnergyHandle(0x2d));
QCOMPARE(chars[2].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[2].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[2].descriptors().at(0).value(),
QByteArray::fromHex("54656d702e20506572696f64"));
QVERIFY(info->contains(chars[2].descriptors().at(0)));
@@ -912,38 +906,35 @@ void tst_QLowEnergyController::verifyServiceProperties(
QBluetoothUuid(QString("0000ffe0-0000-1000-8000-00805f9b34fb"))) {
qDebug() << "Verifying Simple Keys";
QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QCOMPARE(chars.count(), 1);
+ QCOMPARE(chars.size(), 1);
// Temp Data
QString temp("0000ffe1-0000-1000-8000-00805f9b34fb");
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0x6b));
QCOMPARE(chars[0].properties(),
(QLowEnergyCharacteristic::Notify));
QCOMPARE(chars[0].value(), QByteArray());
QVERIFY(chars[0].isValid());
QVERIFY(info->contains(chars[0]));
- QCOMPARE(chars[0].descriptors().count(), 2);
+ QCOMPARE(chars[0].descriptors().size(), 2);
//descriptor checks
QCOMPARE(chars[0].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(0).handle(), QLowEnergyHandle(0x6c));
QCOMPARE(chars[0].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
QCOMPARE(chars[0].descriptors().at(0).type(),
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(verifyClientCharacteristicValue(chars[0].descriptors().at(0).value()));
QVERIFY(info->contains(chars[0].descriptors().at(0)));
QCOMPARE(chars[0].descriptors().at(1).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(1).handle(), QLowEnergyHandle(0x6d));
QCOMPARE(chars[0].descriptors().at(1).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[0].descriptors().at(1).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[0].descriptors().at(1).value(),
QByteArray::fromHex("4b6579205072657373205374617465"));
QVERIFY(info->contains(chars[0].descriptors().at(1)));
@@ -952,38 +943,35 @@ void tst_QLowEnergyController::verifyServiceProperties(
QBluetoothUuid(QString("f000aa10-0451-4000-b000-000000000000"))) {
qDebug() << "Verifying Accelerometer";
QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QCOMPARE(chars.count(), 3);
+ QCOMPARE(chars.size(), 3);
// Accel Data
QString temp("f000aa11-0451-4000-b000-000000000000");
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0x30));
QCOMPARE(chars[0].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify));
QCOMPARE(chars[0].value(), QByteArray::fromHex("000000"));
QVERIFY(chars[0].isValid());
QVERIFY(info->contains(chars[0]));
- QCOMPARE(chars[0].descriptors().count(), 2);
+ QCOMPARE(chars[0].descriptors().size(), 2);
QCOMPARE(chars[0].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(0).handle(), QLowEnergyHandle(0x31));
QCOMPARE(chars[0].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
QCOMPARE(chars[0].descriptors().at(0).type(),
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(verifyClientCharacteristicValue(chars[0].descriptors().at(0).value()));
QVERIFY(info->contains(chars[0].descriptors().at(0)));
QCOMPARE(chars[0].descriptors().at(1).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(1).handle(), QLowEnergyHandle(0x32));
QCOMPARE(chars[0].descriptors().at(1).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[0].descriptors().at(1).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[0].descriptors().at(1).value(),
QByteArray::fromHex("416363656c2e2044617461"));
QVERIFY(info->contains(chars[0].descriptors().at(1)));
@@ -992,21 +980,19 @@ void tst_QLowEnergyController::verifyServiceProperties(
temp = QString("f000aa12-0451-4000-b000-000000000000");
QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].handle(), QLowEnergyHandle(0x34));
QCOMPARE(chars[1].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(chars[1].value(), QByteArray::fromHex("00"));
QVERIFY(chars[1].isValid());
QVERIFY(info->contains(chars[1]));
- QCOMPARE(chars[1].descriptors().count(), 1);
+ QCOMPARE(chars[1].descriptors().size(), 1);
QCOMPARE(chars[1].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].descriptors().at(0).handle(), QLowEnergyHandle(0x35));
QCOMPARE(chars[1].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[1].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[1].descriptors().at(0).value(),
QByteArray::fromHex("416363656c2e20436f6e662e"));
QVERIFY(info->contains(chars[1].descriptors().at(0)));
@@ -1015,22 +1001,20 @@ void tst_QLowEnergyController::verifyServiceProperties(
temp = QString("f000aa13-0451-4000-b000-000000000000");
QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[2].handle(), QLowEnergyHandle(0x37));
QCOMPARE(chars[2].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(chars[2].value(), QByteArray::fromHex("64")); // don't change it or set it to 0x64
QVERIFY(chars[2].isValid());
QVERIFY(info->contains(chars[2]));
- QCOMPARE(chars[2].descriptors().count(), 1);
+ QCOMPARE(chars[2].descriptors().size(), 1);
//descriptor checks
QCOMPARE(chars[2].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[2].descriptors().at(0).handle(), QLowEnergyHandle(0x38));
QCOMPARE(chars[2].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[2].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
// value different in other revisions and test may fail
QCOMPARE(chars[2].descriptors().at(0).value(),
QByteArray::fromHex("416363656c2e20506572696f64"));
@@ -1039,38 +1023,35 @@ void tst_QLowEnergyController::verifyServiceProperties(
QBluetoothUuid(QString("f000aa20-0451-4000-b000-000000000000"))) {
qDebug() << "Verifying Humidity";
QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QVERIFY(chars.count() >= 2); //new firmware has more chars
+ QVERIFY(chars.size() >= 2); //new firmware has more chars
// Humidity Data
QString temp("f000aa21-0451-4000-b000-000000000000");
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0x3b));
QCOMPARE(chars[0].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify));
QCOMPARE(chars[0].value(), QByteArray::fromHex("00000000"));
QVERIFY(chars[0].isValid());
QVERIFY(info->contains(chars[0]));
- QCOMPARE(chars[0].descriptors().count(), 2);
+ QCOMPARE(chars[0].descriptors().size(), 2);
//descriptor checks
QCOMPARE(chars[0].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(0).handle(), QLowEnergyHandle(0x3c));
QCOMPARE(chars[0].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
QCOMPARE(chars[0].descriptors().at(0).type(),
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(verifyClientCharacteristicValue(chars[0].descriptors().at(0).value()));
QVERIFY(info->contains(chars[0].descriptors().at(0)));
QCOMPARE(chars[0].descriptors().at(1).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(1).handle(), QLowEnergyHandle(0x3d));
QCOMPARE(chars[0].descriptors().at(1).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[0].descriptors().at(1).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[0].descriptors().at(1).value(),
QByteArray::fromHex("48756d69642e2044617461"));
QVERIFY(info->contains(chars[0].descriptors().at(1)));
@@ -1079,46 +1060,42 @@ void tst_QLowEnergyController::verifyServiceProperties(
temp = QString("f000aa22-0451-4000-b000-000000000000");
QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].handle(), QLowEnergyHandle(0x3f));
QCOMPARE(chars[1].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(chars[1].value(), QByteArray::fromHex("00"));
QVERIFY(chars[1].isValid());
QVERIFY(info->contains(chars[1]));
- QCOMPARE(chars[1].descriptors().count(), 1);
+ QCOMPARE(chars[1].descriptors().size(), 1);
//descriptor checks
QCOMPARE(chars[1].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].descriptors().at(0).handle(), QLowEnergyHandle(0x40));
QCOMPARE(chars[1].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[1].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[1].descriptors().at(0).value(),
QByteArray::fromHex("48756d69642e20436f6e662e"));
QVERIFY(info->contains(chars[1].descriptors().at(0)));
- if (chars.count() >= 3) {
+ if (chars.size() >= 3) {
// New firmware new characteristic
// Humidity Period
temp = QString("f000aa23-0451-4000-b000-000000000000");
QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[2].handle(), QLowEnergyHandle(0x42));
QCOMPARE(chars[2].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(chars[2].value(), QByteArray::fromHex("64"));
QVERIFY(chars[2].isValid());
QVERIFY(info->contains(chars[2]));
- QCOMPARE(chars[2].descriptors().count(), 1);
+ QCOMPARE(chars[2].descriptors().size(), 1);
//descriptor checks
QCOMPARE(chars[2].descriptors().at(0).isValid(), true);
- HANDLE_COMPARE(chars[2].descriptors().at(0).handle(), QLowEnergyHandle(0x43));
QCOMPARE(chars[2].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[2].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[2].descriptors().at(0).value(),
QByteArray::fromHex("48756d69642e20506572696f64"));
QVERIFY(info->contains(chars[2].descriptors().at(0)));
@@ -1127,38 +1104,35 @@ void tst_QLowEnergyController::verifyServiceProperties(
QBluetoothUuid(QString("f000aa30-0451-4000-b000-000000000000"))) {
qDebug() << "Verifying Magnetometer";
QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QCOMPARE(chars.count(), 3);
+ QCOMPARE(chars.size(), 3);
// Magnetometer Data
QString temp("f000aa31-0451-4000-b000-000000000000");
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0x46));
QCOMPARE(chars[0].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify));
QCOMPARE(chars[0].value(), QByteArray::fromHex("000000000000"));
QVERIFY(chars[0].isValid());
QVERIFY(info->contains(chars[0]));
- QCOMPARE(chars[0].descriptors().count(), 2);
+ QCOMPARE(chars[0].descriptors().size(), 2);
QCOMPARE(chars[0].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(0).handle(), QLowEnergyHandle(0x47));
QCOMPARE(chars[0].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
QCOMPARE(chars[0].descriptors().at(0).type(),
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(verifyClientCharacteristicValue(chars[0].descriptors().at(0).value()));
QVERIFY(info->contains(chars[0].descriptors().at(0)));
QCOMPARE(chars[0].descriptors().at(1).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(1).handle(), QLowEnergyHandle(0x48));
QCOMPARE(chars[0].descriptors().at(1).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[0].descriptors().at(1).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[0].descriptors().at(1).value(),
QByteArray::fromHex("4d61676e2e2044617461"));
QVERIFY(info->contains(chars[0].descriptors().at(1)));
@@ -1167,21 +1141,19 @@ void tst_QLowEnergyController::verifyServiceProperties(
temp = QString("f000aa32-0451-4000-b000-000000000000");
QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].handle(), QLowEnergyHandle(0x4a));
QCOMPARE(chars[1].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(chars[1].value(), QByteArray::fromHex("00"));
QVERIFY(chars[1].isValid());
QVERIFY(info->contains(chars[1]));
- QCOMPARE(chars[1].descriptors().count(), 1);
+ QCOMPARE(chars[1].descriptors().size(), 1);
QCOMPARE(chars[1].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].descriptors().at(0).handle(), QLowEnergyHandle(0x4b));
QCOMPARE(chars[1].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[1].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
// value different in other revisions and test may fail
QCOMPARE(chars[1].descriptors().at(0).value(),
QByteArray::fromHex("4d61676e2e20436f6e662e"));
@@ -1191,21 +1163,19 @@ void tst_QLowEnergyController::verifyServiceProperties(
temp = QString("f000aa33-0451-4000-b000-000000000000");
QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[2].handle(), QLowEnergyHandle(0x4d));
QCOMPARE(chars[2].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(chars[2].value(), QByteArray::fromHex("c8")); // don't change it or set it to 0xc8
QVERIFY(chars[2].isValid());
QVERIFY(info->contains(chars[2]));
- QCOMPARE(chars[2].descriptors().count(), 1);
+ QCOMPARE(chars[2].descriptors().size(), 1);
QCOMPARE(chars[2].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[2].descriptors().at(0).handle(), QLowEnergyHandle(0x4e));
QCOMPARE(chars[2].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[2].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
// value different in other revisions and test may fail
QCOMPARE(chars[2].descriptors().at(0).value(),
QByteArray::fromHex("4d61676e2e20506572696f64"));
@@ -1214,38 +1184,35 @@ void tst_QLowEnergyController::verifyServiceProperties(
QBluetoothUuid(QString("f000aa40-0451-4000-b000-000000000000"))) {
qDebug() << "Verifying Pressure";
const QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QVERIFY(chars.count() >= 3);
+ QVERIFY(chars.size() >= 3);
// Pressure Data
QString temp("f000aa41-0451-4000-b000-000000000000");
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0x51));
QCOMPARE(chars[0].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify));
QCOMPARE(chars[0].value(), QByteArray::fromHex("00000000"));
QVERIFY(chars[0].isValid());
QVERIFY(info->contains(chars[0]));
- QCOMPARE(chars[0].descriptors().count(), 2);
+ QCOMPARE(chars[0].descriptors().size(), 2);
//descriptor checks
QCOMPARE(chars[0].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(0).handle(), QLowEnergyHandle(0x52));
QCOMPARE(chars[0].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
QCOMPARE(chars[0].descriptors().at(0).type(),
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(verifyClientCharacteristicValue(chars[0].descriptors().at(0).value()));
QVERIFY(info->contains(chars[0].descriptors().at(0)));
QCOMPARE(chars[0].descriptors().at(1).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(1).handle(), QLowEnergyHandle(0x53));
QCOMPARE(chars[0].descriptors().at(1).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[0].descriptors().at(1).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
// value different in other revisions and test may fail
QCOMPARE(chars[0].descriptors().at(1).value(),
QByteArray::fromHex("4261726f6d2e2044617461"));
@@ -1255,21 +1222,19 @@ void tst_QLowEnergyController::verifyServiceProperties(
temp = QString("f000aa42-0451-4000-b000-000000000000");
QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].handle(), QLowEnergyHandle(0x55));
QCOMPARE(chars[1].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(chars[1].value(), QByteArray::fromHex("00"));
QVERIFY(chars[1].isValid());
QVERIFY(info->contains(chars[1]));
- QCOMPARE(chars[1].descriptors().count(), 1);
+ QCOMPARE(chars[1].descriptors().size(), 1);
QCOMPARE(chars[1].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].descriptors().at(0).handle(), QLowEnergyHandle(0x56));
QCOMPARE(chars[1].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[1].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[1].descriptors().at(0).value(),
QByteArray::fromHex("4261726f6d2e20436f6e662e"));
QVERIFY(info->contains(chars[1].descriptors().at(0)));
@@ -1289,32 +1254,30 @@ void tst_QLowEnergyController::verifyServiceProperties(
temp = QString("f000aa43-0451-4000-b000-000000000000");
QCOMPARE(calibration.uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(calibration.handle(), QLowEnergyHandle(0x5b));
QCOMPARE(calibration.properties(),
(QLowEnergyCharacteristic::Read));
QCOMPARE(calibration.value(), QByteArray::fromHex("00000000000000000000000000000000")); // don't change it
QVERIFY(calibration.isValid());
QVERIFY(info->contains(calibration));
- QCOMPARE(calibration.descriptors().count(), 2);
+ QCOMPARE(calibration.descriptors().size(), 2);
//descriptor checks
QCOMPARE(calibration.descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(calibration.descriptors().at(0).handle(), QLowEnergyHandle(0x5c));
QCOMPARE(calibration.descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
QCOMPARE(calibration.descriptors().at(0).type(),
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(verifyClientCharacteristicValue(calibration.descriptors().at(0).value()));
QVERIFY(info->contains(calibration.descriptors().at(0)));
QCOMPARE(calibration.descriptors().at(1).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(calibration.descriptors().at(1).handle(), QLowEnergyHandle(0x5d));
QCOMPARE(calibration.descriptors().at(1).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(calibration.descriptors().at(1).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(calibration.descriptors().at(1).value(),
QByteArray::fromHex("4261726f6d2e2043616c6962722e"));
QVERIFY(info->contains(calibration.descriptors().at(1)));
@@ -1325,22 +1288,20 @@ void tst_QLowEnergyController::verifyServiceProperties(
temp = QString("f000aa44-0451-4000-b000-000000000000");
QCOMPARE(period.uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(period.handle(), QLowEnergyHandle(0x58));
QCOMPARE(period.properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(period.value(), QByteArray::fromHex("64"));
QVERIFY(period.isValid());
QVERIFY(info->contains(period));
- QCOMPARE(period.descriptors().count(), 1);
+ QCOMPARE(period.descriptors().size(), 1);
//descriptor checks
QCOMPARE(period.descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(period.descriptors().at(0).handle(), QLowEnergyHandle(0x59));
QCOMPARE(period.descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(period.descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(period.descriptors().at(0).value(),
QByteArray::fromHex("4261726f6d2e20506572696f64"));
QVERIFY(info->contains(period.descriptors().at(0)));
@@ -1349,38 +1310,35 @@ void tst_QLowEnergyController::verifyServiceProperties(
QBluetoothUuid(QString("f000aa50-0451-4000-b000-000000000000"))) {
qDebug() << "Verifying Gyroscope";
QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QVERIFY(chars.count() >= 2);
+ QVERIFY(chars.size() >= 2);
// Gyroscope Data
QString temp("f000aa51-0451-4000-b000-000000000000");
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0x60));
QCOMPARE(chars[0].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Notify));
QCOMPARE(chars[0].value(), QByteArray::fromHex("000000000000"));
QVERIFY(chars[0].isValid());
QVERIFY(info->contains(chars[0]));
- QCOMPARE(chars[0].descriptors().count(), 2);
+ QCOMPARE(chars[0].descriptors().size(), 2);
//descriptor checks
QCOMPARE(chars[0].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(0).handle(), QLowEnergyHandle(0x61));
QCOMPARE(chars[0].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
QCOMPARE(chars[0].descriptors().at(0).type(),
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(verifyClientCharacteristicValue(chars[0].descriptors().at(0).value()));
QVERIFY(info->contains(chars[0].descriptors().at(0)));
QCOMPARE(chars[0].descriptors().at(1).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(1).handle(), QLowEnergyHandle(0x62));
QCOMPARE(chars[0].descriptors().at(1).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[0].descriptors().at(1).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
// value different in other revisions and test may fail
QCOMPARE(chars[0].descriptors().at(1).value(),
QByteArray::fromHex("4779726f2044617461"));
@@ -1390,22 +1348,20 @@ void tst_QLowEnergyController::verifyServiceProperties(
temp = QString("f000aa52-0451-4000-b000-000000000000");
QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].handle(), QLowEnergyHandle(0x64));
QCOMPARE(chars[1].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(chars[1].value(), QByteArray::fromHex("00"));
QVERIFY(chars[1].isValid());
QVERIFY(info->contains(chars[1]));
- QCOMPARE(chars[1].descriptors().count(), 1);
+ QCOMPARE(chars[1].descriptors().size(), 1);
//descriptor checks
QCOMPARE(chars[1].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].descriptors().at(0).handle(), QLowEnergyHandle(0x65));
QCOMPARE(chars[1].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[1].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[1].descriptors().at(0).value(),
QByteArray::fromHex("4779726f20436f6e662e"));
QVERIFY(info->contains(chars[1].descriptors().at(0)));
@@ -1414,21 +1370,19 @@ void tst_QLowEnergyController::verifyServiceProperties(
temp = QString("f000aa53-0451-4000-b000-000000000000");
QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[2].handle(), QLowEnergyHandle(0x67));
QCOMPARE(chars[2].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(chars[2].value(), QByteArray::fromHex("64"));
QVERIFY(chars[2].isValid());
QVERIFY(info->contains(chars[2]));
- QCOMPARE(chars[2].descriptors().count(), 1);
+ QCOMPARE(chars[2].descriptors().size(), 1);
//descriptor checks
QCOMPARE(chars[2].descriptors().at(0).isValid(), true);
- HANDLE_COMPARE(chars[2].descriptors().at(0).handle(), QLowEnergyHandle(0x68));
QCOMPARE(chars[2].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[2].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[2].descriptors().at(0).value(),
QByteArray::fromHex("4779726f20506572696f64"));
QVERIFY(info->contains(chars[2].descriptors().at(0)));
@@ -1436,27 +1390,25 @@ void tst_QLowEnergyController::verifyServiceProperties(
QBluetoothUuid(QString("f000aa60-0451-4000-b000-000000000000"))) {
qDebug() << "Verifying Test Service";
QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QCOMPARE(chars.count(), 2);
+ QCOMPARE(chars.size(), 2);
// Test Data
QString temp("f000aa61-0451-4000-b000-000000000000");
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0x70));
QCOMPARE(chars[0].properties(),
(QLowEnergyCharacteristic::Read));
QCOMPARE(chars[0].value(), QByteArray::fromHex("3f00"));
QVERIFY(chars[0].isValid());
QVERIFY(info->contains(chars[0]));
- QCOMPARE(chars[0].descriptors().count(), 1);
+ QCOMPARE(chars[0].descriptors().size(), 1);
QCOMPARE(chars[0].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(0).handle(), QLowEnergyHandle(0x71));
QCOMPARE(chars[0].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[0].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[0].descriptors().at(0).value(),
QByteArray::fromHex("546573742044617461"));
QVERIFY(info->contains(chars[0].descriptors().at(0)));
@@ -1464,22 +1416,20 @@ void tst_QLowEnergyController::verifyServiceProperties(
// Test Config
temp = QString("f000aa62-0451-4000-b000-000000000000");
QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[1].handle(), QLowEnergyHandle(0x73));
QCOMPARE(chars[1].properties(),
(QLowEnergyCharacteristic::Read|QLowEnergyCharacteristic::Write));
QCOMPARE(chars[1].value(), QByteArray::fromHex("00"));
QVERIFY(chars[1].isValid());
QVERIFY(info->contains(chars[1]));
- QCOMPARE(chars[1].descriptors().count(), 1);
+ QCOMPARE(chars[1].descriptors().size(), 1);
//descriptor checks
QCOMPARE(chars[1].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].descriptors().at(0).handle(), QLowEnergyHandle(0x74));
QCOMPARE(chars[1].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[1].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[1].descriptors().at(0).value(),
QByteArray::fromHex("5465737420436f6e666967"));
QVERIFY(info->contains(chars[1].descriptors().at(0)));
@@ -1487,12 +1437,11 @@ void tst_QLowEnergyController::verifyServiceProperties(
QBluetoothUuid(QString("f000ccc0-0451-4000-b000-000000000000"))) {
qDebug() << "Connection Control Service";
QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QCOMPARE(chars.count(), 3);
+ QCOMPARE(chars.size(), 3);
//first characteristic
QString temp("f000ccc1-0451-4000-b000-000000000000");
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0x77));
QCOMPARE(chars[0].properties(),
(QLowEnergyCharacteristic::Notify|QLowEnergyCharacteristic::Read));
// the connection control parameter change from platform to platform
@@ -1501,24 +1450,22 @@ void tst_QLowEnergyController::verifyServiceProperties(
QVERIFY(chars[0].isValid());
QVERIFY(info->contains(chars[0]));
- QCOMPARE(chars[0].descriptors().count(), 2);
+ QCOMPARE(chars[0].descriptors().size(), 2);
//descriptor checks
QCOMPARE(chars[0].descriptors().at(0).isValid(), true);
- HANDLE_COMPARE(chars[0].descriptors().at(0).handle(), QLowEnergyHandle(0x78));
QCOMPARE(chars[0].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
QCOMPARE(chars[0].descriptors().at(0).type(),
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(verifyClientCharacteristicValue(chars[0].descriptors().at(0).value()));
QVERIFY(info->contains(chars[0].descriptors().at(0)));
QCOMPARE(chars[0].descriptors().at(1).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(1).handle(), QLowEnergyHandle(0x79));
QCOMPARE(chars[0].descriptors().at(1).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[0].descriptors().at(1).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[0].descriptors().at(1).value(),
QByteArray::fromHex("436f6e6e2e20506172616d73"));
QVERIFY(info->contains(chars[0].descriptors().at(1)));
@@ -1526,19 +1473,17 @@ void tst_QLowEnergyController::verifyServiceProperties(
//second characteristic
temp = QString("f000ccc2-0451-4000-b000-000000000000");
QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[1].handle(), QLowEnergyHandle(0x7b));
QCOMPARE(chars[1].properties(), QLowEnergyCharacteristic::Write);
QCOMPARE(chars[1].value(), QByteArray());
QVERIFY(chars[1].isValid());
QVERIFY(info->contains(chars[1]));
- QCOMPARE(chars[1].descriptors().count(), 1);
+ QCOMPARE(chars[1].descriptors().size(), 1);
QCOMPARE(chars[1].descriptors().at(0).isValid(), true);
- HANDLE_COMPARE(chars[1].descriptors().at(0).handle(), QLowEnergyHandle(0x7c));
QCOMPARE(chars[1].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[1].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[1].descriptors().at(0).value(),
QByteArray::fromHex("436f6e6e2e20506172616d7320526571"));
QVERIFY(info->contains(chars[1].descriptors().at(0)));
@@ -1546,19 +1491,17 @@ void tst_QLowEnergyController::verifyServiceProperties(
//third characteristic
temp = QString("f000ccc3-0451-4000-b000-000000000000");
QCOMPARE(chars[2].uuid(), QBluetoothUuid(temp));
- HANDLE_COMPARE(chars[2].handle(), QLowEnergyHandle(0x7e));
QCOMPARE(chars[2].properties(), QLowEnergyCharacteristic::Write);
QCOMPARE(chars[2].value(), QByteArray());
QVERIFY(chars[2].isValid());
QVERIFY(info->contains(chars[2]));
- QCOMPARE(chars[2].descriptors().count(), 1);
+ QCOMPARE(chars[2].descriptors().size(), 1);
QCOMPARE(chars[2].descriptors().at(0).isValid(), true);
- HANDLE_COMPARE(chars[2].descriptors().at(0).handle(), QLowEnergyHandle(0x7f));
QCOMPARE(chars[2].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[2].descriptors().at(0).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[2].descriptors().at(0).value(),
QByteArray::fromHex("446973636f6e6e65637420526571"));
QVERIFY(info->contains(chars[2].descriptors().at(0)));
@@ -1566,37 +1509,34 @@ void tst_QLowEnergyController::verifyServiceProperties(
QBluetoothUuid(QString("f000ffc0-0451-4000-b000-000000000000"))) {
qDebug() << "Verifying OID Service";
QList<QLowEnergyCharacteristic> chars = info->characteristics();
- QCOMPARE(chars.count(), 2);
+ QCOMPARE(chars.size(), 2);
// first characteristic
QString temp("f000ffc1-0451-4000-b000-000000000000");
QCOMPARE(chars[0].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].handle(), QLowEnergyHandle(0x82));
QCOMPARE(chars[0].properties(),
(QLowEnergyCharacteristic::Notify|QLowEnergyCharacteristic::Write|QLowEnergyCharacteristic::WriteNoResponse));
QCOMPARE(chars[0].value(), QByteArray());
QVERIFY(chars[0].isValid());
QVERIFY(info->contains(chars[0]));
- QCOMPARE(chars[0].descriptors().count(), 2);
+ QCOMPARE(chars[0].descriptors().size(), 2);
//descriptor checks
QCOMPARE(chars[0].descriptors().at(0).isValid(), true);
- HANDLE_COMPARE(chars[0].descriptors().at(0).handle(), QLowEnergyHandle(0x83));
QCOMPARE(chars[0].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
QCOMPARE(chars[0].descriptors().at(0).type(),
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(verifyClientCharacteristicValue(chars[0].descriptors().at(0).value()));
QVERIFY(info->contains(chars[0].descriptors().at(0)));
QCOMPARE(chars[0].descriptors().at(1).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[0].descriptors().at(1).handle(), QLowEnergyHandle(0x84));
QCOMPARE(chars[0].descriptors().at(1).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[0].descriptors().at(1).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[0].descriptors().at(1).value(),
QByteArray::fromHex("496d67204964656e74696679"));
QVERIFY(info->contains(chars[0].descriptors().at(1)));
@@ -1605,32 +1545,29 @@ void tst_QLowEnergyController::verifyServiceProperties(
temp = QString("f000ffc2-0451-4000-b000-000000000000");
QCOMPARE(chars[1].uuid(), QBluetoothUuid(temp));
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].handle(), QLowEnergyHandle(0x86));
QCOMPARE(chars[1].properties(),
(QLowEnergyCharacteristic::Notify|QLowEnergyCharacteristic::Write|QLowEnergyCharacteristic::WriteNoResponse));
QCOMPARE(chars[1].value(), QByteArray());
QVERIFY(chars[1].isValid());
QVERIFY(info->contains(chars[1]));
- QCOMPARE(chars[1].descriptors().count(), 2);
+ QCOMPARE(chars[1].descriptors().size(), 2);
//descriptor checks
QCOMPARE(chars[1].descriptors().at(0).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].descriptors().at(0).handle(), QLowEnergyHandle(0x87));
QCOMPARE(chars[1].descriptors().at(0).uuid(),
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
QCOMPARE(chars[1].descriptors().at(0).type(),
- QBluetoothUuid::ClientCharacteristicConfiguration);
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
QVERIFY(verifyClientCharacteristicValue(chars[0].descriptors().at(0).value()));
QVERIFY(info->contains(chars[1].descriptors().at(0)));
QCOMPARE(chars[1].descriptors().at(1).isValid(), true);
// value different in other revisions and test may fail
- HANDLE_COMPARE(chars[1].descriptors().at(1).handle(), QLowEnergyHandle(0x88));
QCOMPARE(chars[1].descriptors().at(1).uuid(),
- QBluetoothUuid(QBluetoothUuid::CharacteristicUserDescription));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::CharacteristicUserDescription));
QCOMPARE(chars[1].descriptors().at(1).type(),
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QCOMPARE(chars[1].descriptors().at(1).value(),
QByteArray::fromHex("496d6720426c6f636b"));
QVERIFY(info->contains(chars[1].descriptors().at(1)));
@@ -1671,44 +1608,50 @@ void tst_QLowEnergyController::tst_defaultBehavior()
const QBluetoothAddress randomAddress("11:22:33:44:55:66");
// Test automatic detection of local adapter
- QLowEnergyController controlDefaultAdapter(randomAddress);
- QCOMPARE(controlDefaultAdapter.remoteAddress(), randomAddress);
- QCOMPARE(controlDefaultAdapter.state(), QLowEnergyController::UnconnectedState);
+ QScopedPointer<QLowEnergyController> controlDefaultAdapter(QLowEnergyController::createCentral(
+ QBluetoothDeviceInfo(randomAddress, QString("random"), 1)));
+
+ QCOMPARE(controlDefaultAdapter->remoteAddress(), randomAddress);
+ QCOMPARE(controlDefaultAdapter->state(), QLowEnergyController::UnconnectedState);
if (foundAddresses.isEmpty()) {
- QVERIFY(controlDefaultAdapter.localAddress().isNull());
+ QVERIFY(controlDefaultAdapter->localAddress().isNull());
} else {
- QCOMPARE(controlDefaultAdapter.error(), QLowEnergyController::NoError);
- QVERIFY(controlDefaultAdapter.errorString().isEmpty());
- QVERIFY(foundAddresses.contains(controlDefaultAdapter.localAddress()));
+ QCOMPARE(controlDefaultAdapter->error(), QLowEnergyController::NoError);
+ QVERIFY(controlDefaultAdapter->errorString().isEmpty());
+ QVERIFY(foundAddresses.contains(controlDefaultAdapter->localAddress()));
// unrelated uuids don't return valid service object
// invalid service uuid
- QVERIFY(!controlDefaultAdapter.createServiceObject(
+ QVERIFY(!controlDefaultAdapter->createServiceObject(
QBluetoothUuid()));
// some random uuid
- QVERIFY(!controlDefaultAdapter.createServiceObject(
- QBluetoothUuid(QBluetoothUuid::DeviceName)));
+ QVERIFY(!controlDefaultAdapter->createServiceObject(
+ QBluetoothUuid(QBluetoothUuid::CharacteristicType::DeviceName)));
}
- QCOMPARE(controlDefaultAdapter.services().count(), 0);
+ QCOMPARE(controlDefaultAdapter->services().size(), 0);
// Test explicit local adapter
if (!foundAddresses.isEmpty()) {
- QLowEnergyController controlExplicitAdapter(randomAddress,
- foundAddresses[0]);
- QCOMPARE(controlExplicitAdapter.remoteAddress(), randomAddress);
- QCOMPARE(controlExplicitAdapter.localAddress(), foundAddresses[0]);
- QCOMPARE(controlExplicitAdapter.state(),
+
+ QScopedPointer<QLowEnergyController> controlExplicitAdapter(
+ QLowEnergyController::createCentral(
+ QBluetoothDeviceInfo(randomAddress, QString("random"), 1),
+ foundAddresses[0]));
+
+ QCOMPARE(controlExplicitAdapter->remoteAddress(), randomAddress);
+ QCOMPARE(controlExplicitAdapter->localAddress(), foundAddresses[0]);
+ QCOMPARE(controlExplicitAdapter->state(),
QLowEnergyController::UnconnectedState);
- QCOMPARE(controlExplicitAdapter.services().count(), 0);
+ QCOMPARE(controlExplicitAdapter->services().size(), 0);
// unrelated uuids don't return valid service object
// invalid service uuid
- QVERIFY(!controlExplicitAdapter.createServiceObject(
+ QVERIFY(!controlExplicitAdapter->createServiceObject(
QBluetoothUuid()));
// some random uuid
- QVERIFY(!controlExplicitAdapter.createServiceObject(
- QBluetoothUuid(QBluetoothUuid::DeviceName)));
+ QVERIFY(!controlExplicitAdapter->createServiceObject(
+ QBluetoothUuid(QBluetoothUuid::CharacteristicType::DeviceName)));
}
}
@@ -1722,42 +1665,43 @@ void tst_QLowEnergyController::tst_writeCharacteristic()
if (!remoteDeviceInfo.isValid())
QSKIP("No remote BTLE device found. Skipping test.");
- QLowEnergyController control(remoteDeviceInfo);
+ QScopedPointer<QLowEnergyController> control(
+ QLowEnergyController::createCentral(remoteDeviceInfo));
- QCOMPARE(control.error(), QLowEnergyController::NoError);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
- control.connectToDevice();
+ control->connectToDevice();
{
- QTRY_IMPL(control.state() != QLowEnergyController::ConnectingState,
- 30000);
+ QTRY_IMPL(control->state() != QLowEnergyController::ConnectingState,
+ 30000)
}
- if (control.state() == QLowEnergyController::ConnectingState
- || control.error() != QLowEnergyController::NoError) {
+ if (control->state() == QLowEnergyController::ConnectingState
+ || control->error() != QLowEnergyController::NoError) {
// default BTLE backend forever hangs in ConnectingState
QSKIP("Cannot connect to remote device");
}
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
- QSignalSpy discoveryFinishedSpy(&control, SIGNAL(discoveryFinished()));
- QSignalSpy stateSpy(&control, SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
- control.discoverServices();
- QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 20000);
- QCOMPARE(stateSpy.count(), 2);
+ QTRY_VERIFY_WITH_TIMEOUT(control->state() == QLowEnergyController::ConnectedState, 20000);
+ QSignalSpy discoveryFinishedSpy(control.data(), SIGNAL(discoveryFinished()));
+ QSignalSpy stateSpy(control.data(), SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
+ control->discoverServices();
+ QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.size() == 1, 20000);
+ QCOMPARE(stateSpy.size(), 2);
QCOMPARE(stateSpy.at(0).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveringState);
QCOMPARE(stateSpy.at(1).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveredState);
const QBluetoothUuid testService(QString("f000aa60-0451-4000-b000-000000000000"));
- QList<QBluetoothUuid> uuids = control.services();
+ QList<QBluetoothUuid> uuids = control->services();
QVERIFY(uuids.contains(testService));
- QLowEnergyService *service = control.createServiceObject(testService, this);
+ QLowEnergyService *service = control->createServiceObject(testService, this);
QVERIFY(service);
service->discoverDetails();
QTRY_VERIFY_WITH_TIMEOUT(
- service->state() == QLowEnergyService::ServiceDiscovered, 30000);
+ service->state() == QLowEnergyService::RemoteServiceDiscovered, 30000);
// test service described by
// http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User%27s_Guide
@@ -1765,7 +1709,7 @@ void tst_QLowEnergyController::tst_writeCharacteristic()
QLowEnergyCharacteristic dataChar;
QLowEnergyCharacteristic configChar;
- for (int i = 0; i < chars.count(); i++) {
+ for (qsizetype i = 0; i < chars.size(); ++i) {
if (chars[i].uuid() == QBluetoothUuid(QString("f000aa61-0451-4000-b000-000000000000")))
dataChar = chars[i];
else if (chars[i].uuid() == QBluetoothUuid(QString("f000aa62-0451-4000-b000-000000000000")))
@@ -1812,7 +1756,7 @@ void tst_QLowEnergyController::tst_writeCharacteristic()
service->readCharacteristic(configChar);
QTRY_VERIFY_WITH_TIMEOUT(!readSpy.isEmpty(), 10000);
QCOMPARE(configChar.value(), QByteArray::fromHex("81"));
- QCOMPARE(readSpy.count(), 1); //expect one characteristicRead signal
+ QCOMPARE(readSpy.size(), 1); //expect one characteristicRead signal
{
//verify the readCharacteristic()
QList<QVariant> firstSignalData = readSpy.first();
@@ -1836,10 +1780,10 @@ void tst_QLowEnergyController::tst_writeCharacteristic()
// *******************************************
// write wrong value -> error response required
- QSignalSpy errorSpy(service, SIGNAL(error(QLowEnergyService::ServiceError)));
+ QSignalSpy errorSpy(service, SIGNAL(errorOccurred(QLowEnergyService::ServiceError)));
writeSpy.clear();
- QCOMPARE(errorSpy.count(), 0);
- QCOMPARE(writeSpy.count(), 0);
+ QCOMPARE(errorSpy.size(), 0);
+ QCOMPARE(writeSpy.size(), 0);
// write 2 byte value to 1 byte characteristic
service->writeCharacteristic(configChar, QByteArray::fromHex("1111"));
@@ -1847,35 +1791,36 @@ void tst_QLowEnergyController::tst_writeCharacteristic()
QCOMPARE(errorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
QLowEnergyService::CharacteristicWriteError);
QCOMPARE(service->error(), QLowEnergyService::CharacteristicWriteError);
- QCOMPARE(writeSpy.count(), 0);
+ QCOMPARE(writeSpy.size(), 0);
QCOMPARE(configChar.value(), QByteArray::fromHex("00"));
// *******************************************
// write to read-only characteristic -> error
errorSpy.clear();
- QCOMPARE(errorSpy.count(), 0);
+ QCOMPARE(errorSpy.size(), 0);
service->writeCharacteristic(dataChar, QByteArray::fromHex("ffff"));
QTRY_VERIFY_WITH_TIMEOUT(!errorSpy.isEmpty(), 10000);
QCOMPARE(errorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
QLowEnergyService::CharacteristicWriteError);
QCOMPARE(service->error(), QLowEnergyService::CharacteristicWriteError);
- QCOMPARE(writeSpy.count(), 0);
+ QCOMPARE(writeSpy.size(), 0);
QCOMPARE(dataChar.value(), QByteArray::fromHex("3f00"));
- control.disconnectFromDevice();
-
+ control->disconnectFromDevice();
+ QTRY_COMPARE(control->state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
// *******************************************
// write value while disconnected -> error
errorSpy.clear();
- QCOMPARE(errorSpy.count(), 0);
+ QCOMPARE(errorSpy.size(), 0);
service->writeCharacteristic(configChar, QByteArray::fromHex("ffff"));
QTRY_VERIFY_WITH_TIMEOUT(!errorSpy.isEmpty(), 2000);
QCOMPARE(errorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
QLowEnergyService::OperationError);
QCOMPARE(service->error(), QLowEnergyService::OperationError);
- QCOMPARE(writeSpy.count(), 0);
+ QCOMPARE(writeSpy.size(), 0);
QCOMPARE(configChar.value(), QByteArray::fromHex("00"));
// invalid characteristics still belong to their respective service
@@ -1897,73 +1842,77 @@ void tst_QLowEnergyController::tst_readWriteDescriptor()
if (!remoteDeviceInfo.isValid())
QSKIP("No remote BTLE device found. Skipping test.");
- QLowEnergyController control(remoteDeviceInfo);
+ QScopedPointer<QLowEnergyController> control(QLowEnergyController::createCentral(remoteDeviceInfo));
// quick setup - more elaborate test is done by connect()
- control.connectToDevice();
+ control->connectToDevice();
{
- QTRY_IMPL(control.state() != QLowEnergyController::ConnectingState,
- 30000);
+ QTRY_IMPL(control->state() != QLowEnergyController::ConnectingState,
+ 30000)
}
- if (control.state() == QLowEnergyController::ConnectingState
- || control.error() != QLowEnergyController::NoError) {
+ if (control->state() == QLowEnergyController::ConnectingState
+ || control->error() != QLowEnergyController::NoError) {
// default BTLE backend forever hangs in ConnectingState
QSKIP("Cannot connect to remote device");
}
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
- QSignalSpy discoveryFinishedSpy(&control, SIGNAL(discoveryFinished()));
- QSignalSpy stateSpy(&control, SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
- control.discoverServices();
- QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 20000);
- QCOMPARE(stateSpy.count(), 2);
+ QCOMPARE(control->state(), QLowEnergyController::ConnectedState);
+ QSignalSpy discoveryFinishedSpy(control.data(), SIGNAL(discoveryFinished()));
+ QSignalSpy stateSpy(control.data(), SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
+ control->discoverServices();
+ QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.size() == 1, 20000);
+ QCOMPARE(stateSpy.size(), 2);
QCOMPARE(stateSpy.at(0).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveringState);
QCOMPARE(stateSpy.at(1).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveredState);
- const QBluetoothUuid testService(QString("f000aa00-0451-4000-b000-000000000000"));
- QList<QBluetoothUuid> uuids = control.services();
+ const QBluetoothUuid testService(QString("f000aa20-0451-4000-b000-000000000000"));
+ QList<QBluetoothUuid> uuids = control->services();
QVERIFY(uuids.contains(testService));
- QLowEnergyService *service = control.createServiceObject(testService, this);
+ QLowEnergyService *service = control->createServiceObject(testService, this);
QVERIFY(service);
service->discoverDetails();
QTRY_VERIFY_WITH_TIMEOUT(
- service->state() == QLowEnergyService::ServiceDiscovered, 30000);
+ service->state() == QLowEnergyService::RemoteServiceDiscovered, 30000);
- // Temperature service described by
+ // Humidity service described by
// http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User%27s_Guide
- // 1. Find temperature data characteristic
- const QLowEnergyCharacteristic tempData = service->characteristic(
- QBluetoothUuid(QStringLiteral("f000aa01-0451-4000-b000-000000000000")));
- const QLowEnergyCharacteristic tempConfig = service->characteristic(
- QBluetoothUuid(QStringLiteral("f000aa02-0451-4000-b000-000000000000")));
+ // 1. Find humidity data characteristic
+ const QLowEnergyCharacteristic humidData = service->characteristic(
+ QBluetoothUuid(QStringLiteral("f000aa21-0451-4000-b000-000000000000")));
+ const QLowEnergyCharacteristic humidConfig = service->characteristic(
+ QBluetoothUuid(QStringLiteral("f000aa22-0451-4000-b000-000000000000")));
- if (!tempData.isValid()) {
+ if (!humidData.isValid()) {
delete service;
- control.disconnectFromDevice();
- QSKIP("Cannot find temperature data characteristic of TI Sensor");
+ control->disconnectFromDevice();
+ QTRY_COMPARE(control->state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
+ QSKIP("Cannot find humidity data characteristic of TI Sensor");
}
- // 2. Find temperature data notification descriptor
- const QLowEnergyDescriptor notification = tempData.descriptor(
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ // 2. Find humidity data notification descriptor
+ const QLowEnergyDescriptor notification = humidData.descriptor(
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
if (!notification.isValid()) {
delete service;
- control.disconnectFromDevice();
- QSKIP("Cannot find temperature data notification of TI Sensor");
+ control->disconnectFromDevice();
+ QTRY_COMPARE(control->state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
+ QSKIP("Cannot find humidity data notification of TI Sensor");
}
QCOMPARE(notification.value(), QByteArray::fromHex("0000"));
QVERIFY(service->contains(notification));
- QVERIFY(service->contains(tempData));
- if (tempConfig.isValid()) {
- QVERIFY(service->contains(tempConfig));
- QCOMPARE(tempConfig.value(), QByteArray::fromHex("00"));
+ QVERIFY(service->contains(humidData));
+ if (humidConfig.isValid()) {
+ QVERIFY(service->contains(humidConfig));
+ QCOMPARE(humidConfig.value(), QByteArray::fromHex("00"));
}
// 3. Test reading and writing to descriptor -> activate notifications
@@ -1994,46 +1943,46 @@ void tst_QLowEnergyController::tst_readWriteDescriptor()
}
// 4. Test reception of notifications
- // activate the temperature sensor if available
- if (tempConfig.isValid()) {
- service->writeCharacteristic(tempConfig, QByteArray::fromHex("01"));
+ // activate the humidity sensor if available
+ if (humidConfig.isValid()) {
+ service->writeCharacteristic(humidConfig, QByteArray::fromHex("01"));
- // first signal is confirmation of tempConfig write
+ // first signal is confirmation of humidConfig write
// subsequent signals are temp data updates
- QTRY_VERIFY_WITH_TIMEOUT(charWrittenSpy.count() == 1, 10000);
- QTRY_VERIFY_WITH_TIMEOUT(charChangedSpy.count() >= 4, 10000);
+ QTRY_VERIFY_WITH_TIMEOUT(charWrittenSpy.size() == 1, 10000);
+ QTRY_VERIFY_WITH_TIMEOUT(charChangedSpy.size() >= 4, 10000);
- QCOMPARE(charWrittenSpy.count(), 1);
+ QCOMPARE(charWrittenSpy.size(), 1);
QLowEnergyCharacteristic writtenChar = charWrittenSpy[0].at(0).value<QLowEnergyCharacteristic>();
QByteArray writtenValue = charWrittenSpy[0].at(1).toByteArray();
- QCOMPARE(tempConfig, writtenChar);
- QCOMPARE(tempConfig.value(), writtenValue);
+ QCOMPARE(humidConfig, writtenChar);
+ QCOMPARE(humidConfig.value(), writtenValue);
QCOMPARE(writtenChar.value(), writtenValue);
QCOMPARE(writtenValue, QByteArray::fromHex("01"));
QList<QVariant> entry;
- for (int i = 0; i < charChangedSpy.count(); i++) {
+ for (qsizetype i = 0; i < charChangedSpy.size(); ++i) {
entry = charChangedSpy[i];
const QLowEnergyCharacteristic ch = entry[0].value<QLowEnergyCharacteristic>();
- QCOMPARE(tempData, ch);
+ QCOMPARE(humidData, ch);
//check last characteristic changed value matches the characteristics current value
- if (i == (charChangedSpy.count() - 1)) {
+ if (i == (charChangedSpy.size() - 1)) {
writtenValue = entry[1].toByteArray();
QCOMPARE(ch.value(), writtenValue);
- QCOMPARE(tempData.value(), writtenValue);
+ QCOMPARE(humidData.value(), writtenValue);
}
}
- service->writeCharacteristic(tempConfig, QByteArray::fromHex("00"));
+ service->writeCharacteristic(humidConfig, QByteArray::fromHex("00"));
}
// 5. Test reading and writing of/to descriptor -> deactivate notifications
service->readDescriptor(notification);
QTRY_VERIFY_WITH_TIMEOUT(!descReadSpy.isEmpty(), 3000);
- QCOMPARE(descReadSpy.count(), 1);
+ QCOMPARE(descReadSpy.size(), 1);
firstSignalData = descReadSpy.first();
signalDesc = firstSignalData[0].value<QLowEnergyDescriptor>();
signalValue = firstSignalData[1].toByteArray();
@@ -2077,10 +2026,10 @@ void tst_QLowEnergyController::tst_readWriteDescriptor()
if (isBluezDbusLE)
QTest::qWait(1000);
- QTRY_VERIFY_WITH_TIMEOUT(descWrittenSpy.count() == 4, 10000);
+ QTRY_VERIFY_WITH_TIMEOUT(descWrittenSpy.size() == 4, 10000);
QCOMPARE(notification.value(), QByteArray::fromHex("0000"));
- for (int i = 0; i < descWrittenSpy.count(); i++) {
+ for (qsizetype i = 0; i < descWrittenSpy.size(); ++i) {
firstSignalData = descWrittenSpy.at(i);
signalDesc = firstSignalData[0].value<QLowEnergyDescriptor>();
signalValue = firstSignalData[1].toByteArray();
@@ -2096,7 +2045,7 @@ void tst_QLowEnergyController::tst_readWriteDescriptor()
service->readDescriptor(notification);
QTRY_VERIFY_WITH_TIMEOUT(!descReadSpy.isEmpty(), 3000);
- QCOMPARE(descReadSpy.count(), 1);
+ QCOMPARE(descReadSpy.size(), 1);
firstSignalData = descReadSpy.first();
signalDesc = firstSignalData[0].value<QLowEnergyDescriptor>();
signalValue = firstSignalData[1].toByteArray();
@@ -2108,10 +2057,10 @@ void tst_QLowEnergyController::tst_readWriteDescriptor()
// *******************************************
// write wrong value -> error response required
- QSignalSpy errorSpy(service, SIGNAL(error(QLowEnergyService::ServiceError)));
+ QSignalSpy errorSpy(service, SIGNAL(errorOccurred(QLowEnergyService::ServiceError)));
descWrittenSpy.clear();
- QCOMPARE(errorSpy.count(), 0);
- QCOMPARE(descWrittenSpy.count(), 0);
+ QCOMPARE(errorSpy.size(), 0);
+ QCOMPARE(descWrittenSpy.size(), 0);
// write 4 byte value to 2 byte characteristic
service->writeDescriptor(notification, QByteArray::fromHex("11112222"));
@@ -2127,10 +2076,12 @@ void tst_QLowEnergyController::tst_readWriteDescriptor()
QCOMPARE(errorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
QLowEnergyService::DescriptorWriteError);
QCOMPARE(service->error(), QLowEnergyService::DescriptorWriteError);
- QCOMPARE(descWrittenSpy.count(), 0);
+ QCOMPARE(descWrittenSpy.size(), 0);
QCOMPARE(notification.value(), QByteArray::fromHex("0000"));
- control.disconnectFromDevice();
+ control->disconnectFromDevice();
+ QTRY_COMPARE(control->state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
// *******************************************
// write value while disconnected -> error
@@ -2140,7 +2091,7 @@ void tst_QLowEnergyController::tst_readWriteDescriptor()
QCOMPARE(errorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
QLowEnergyService::OperationError);
QCOMPARE(service->error(), QLowEnergyService::OperationError);
- QCOMPARE(descWrittenSpy.count(), 0);
+ QCOMPARE(descWrittenSpy.size(), 0);
QCOMPARE(notification.value(), QByteArray::fromHex("0000"));
delete service;
@@ -2181,45 +2132,46 @@ void tst_QLowEnergyController::tst_customProgrammableDevice()
//The target characteristic must be readble and writable
//under encryption to test dynamic switching of security level
QBluetoothAddress encryptedDevice(QString("00:02:5B:00:15:10"));
- QBluetoothUuid serviceUuid(QBluetoothUuid::GenericAccess);
- QBluetoothUuid characterristicUuid(QBluetoothUuid::DeviceName);
+ QBluetoothUuid serviceUuid(QBluetoothUuid::ServiceClassUuid::GenericAccess);
+ QBluetoothUuid characterristicUuid(QBluetoothUuid::CharacteristicType::DeviceName);
- QLowEnergyController control(encryptedDevice);
- QCOMPARE(control.error(), QLowEnergyController::NoError);
+ QScopedPointer<QLowEnergyController> control(
+ QLowEnergyController::createCentral(QBluetoothDeviceInfo(encryptedDevice, QString("DeviceFoo"), 1)));
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
- control.connectToDevice();
+ control->connectToDevice();
{
- QTRY_IMPL(control.state() != QLowEnergyController::ConnectingState,
- 30000);
+ QTRY_IMPL(control->state() != QLowEnergyController::ConnectingState,
+ 30000)
}
- if (control.state() == QLowEnergyController::ConnectingState
- || control.error() != QLowEnergyController::NoError) {
+ if (control->state() == QLowEnergyController::ConnectingState
+ || control->error() != QLowEnergyController::NoError) {
// default BTLE backend forever hangs in ConnectingState
QSKIP("Cannot connect to remote device");
}
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
- QSignalSpy discoveryFinishedSpy(&control, SIGNAL(discoveryFinished()));
- QSignalSpy stateSpy(&control, SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
- control.discoverServices();
- QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 20000);
- QCOMPARE(stateSpy.count(), 2);
+ QCOMPARE(control->state(), QLowEnergyController::ConnectedState);
+ QSignalSpy discoveryFinishedSpy(control.data(), SIGNAL(discoveryFinished()));
+ QSignalSpy stateSpy(control.data(), SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
+ control->discoverServices();
+ QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.size() == 1, 20000);
+ QCOMPARE(stateSpy.size(), 2);
QCOMPARE(stateSpy.at(0).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveringState);
QCOMPARE(stateSpy.at(1).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveredState);
- QList<QBluetoothUuid> uuids = control.services();
+ QList<QBluetoothUuid> uuids = control->services();
QVERIFY(uuids.contains(serviceUuid));
- QLowEnergyService *service = control.createServiceObject(serviceUuid, this);
+ QLowEnergyService *service = control->createServiceObject(serviceUuid, this);
QVERIFY(service);
// 1.) discovery triggers read of device name char which is encrypted
service->discoverDetails();
QTRY_VERIFY_WITH_TIMEOUT(
- service->state() == QLowEnergyService::ServiceDiscovered, 30000);
+ service->state() == QLowEnergyService::RemoteServiceDiscovered, 30000);
QLowEnergyCharacteristic encryptedChar = service->characteristic(
characterristicUuid);
@@ -2232,12 +2184,11 @@ void tst_QLowEnergyController::tst_customProgrammableDevice()
// encryption already.
QSignalSpy encryptedReadSpy(service,
SIGNAL(characteristicRead(QLowEnergyCharacteristic,QByteArray)));
- QSignalSpy encryptedErrorSpy(service,
- SIGNAL(error(QLowEnergyService::ServiceError)));
+ QSignalSpy encryptedErrorSpy(service, SIGNAL(errorOccurred(QLowEnergyService::ServiceError)));
service->readCharacteristic(encryptedChar);
QTRY_VERIFY_WITH_TIMEOUT(!encryptedReadSpy.isEmpty(), 10000);
QVERIFY(encryptedErrorSpy.isEmpty());
- QCOMPARE(encryptedReadSpy.count(), 1);
+ QCOMPARE(encryptedReadSpy.size(), 1);
QList<QVariant> entry = encryptedReadSpy[0];
QVERIFY(entry[0].value<QLowEnergyCharacteristic>() == encryptedChar);
QCOMPARE(entry[1].toByteArray(), encryptedReference);
@@ -2253,7 +2204,7 @@ void tst_QLowEnergyController::tst_customProgrammableDevice()
QTRY_VERIFY_WITH_TIMEOUT(!encryptedWriteSpy.isEmpty(), 10000);
QVERIFY(encryptedErrorSpy.isEmpty());
QVERIFY(encryptedReadSpy.isEmpty());
- QCOMPARE(encryptedWriteSpy.count(), 1);
+ QCOMPARE(encryptedWriteSpy.size(), 1);
entry = encryptedWriteSpy[0];
QVERIFY(entry[0].value<QLowEnergyCharacteristic>() == encryptedChar);
QCOMPARE(entry[1].toByteArray(), newValue);
@@ -2262,31 +2213,30 @@ void tst_QLowEnergyController::tst_customProgrammableDevice()
delete service;
//change to Device Information service
- QVERIFY(uuids.contains(QBluetoothUuid::DeviceInformation));
- service = control.createServiceObject(QBluetoothUuid::DeviceInformation);
+ QVERIFY(uuids.contains(QBluetoothUuid::ServiceClassUuid::DeviceInformation));
+ service = control->createServiceObject(QBluetoothUuid::ServiceClassUuid::DeviceInformation);
QVERIFY(service);
service->discoverDetails();
QTRY_VERIFY_WITH_TIMEOUT(
- service->state() == QLowEnergyService::ServiceDiscovered, 30000);
+ service->state() == QLowEnergyService::RemoteServiceDiscovered, 30000);
// 4.) read of software revision string which is longer than mtu
// tests readCharacteristic() including blob reads
QSignalSpy readSpy(service,
SIGNAL(characteristicRead(QLowEnergyCharacteristic,QByteArray)));
- QSignalSpy errorSpy(service,
- SIGNAL(error(QLowEnergyService::ServiceError)));
+ QSignalSpy errorSpy(service, SIGNAL(errorOccurred(QLowEnergyService::ServiceError)));
const QByteArray expectedSoftRev("Application version 2.3.0.0");
- QLowEnergyCharacteristic softwareRevChar
- = service->characteristic(QBluetoothUuid::SoftwareRevisionString);
+ QLowEnergyCharacteristic softwareRevChar =
+ service->characteristic(QBluetoothUuid::CharacteristicType::SoftwareRevisionString);
QVERIFY(softwareRevChar.isValid());
QCOMPARE(softwareRevChar.value(), expectedSoftRev);
service->readCharacteristic(softwareRevChar);
QTRY_VERIFY_WITH_TIMEOUT(!readSpy.isEmpty(), 10000);
QVERIFY(errorSpy.isEmpty());
- QCOMPARE(readSpy.count(), 1);
+ QCOMPARE(readSpy.size(), 1);
entry = readSpy[0];
QVERIFY(entry[0].value<QLowEnergyCharacteristic>() == softwareRevChar);
QCOMPARE(entry[1].toByteArray(), expectedSoftRev);
@@ -2303,22 +2253,24 @@ void tst_QLowEnergyController::tst_customProgrammableDevice()
// This assumes the manufacturer string was mondified via CSR SDK
// see function description above
const QByteArray expectedManufacturer("Cambridge Silicon Radi");
- QLowEnergyCharacteristic manufacturerChar = service->characteristic(
- QBluetoothUuid::ManufacturerNameString);
+ QLowEnergyCharacteristic manufacturerChar =
+ service->characteristic(QBluetoothUuid::CharacteristicType::ManufacturerNameString);
QVERIFY(manufacturerChar.isValid());
QCOMPARE(manufacturerChar.value(), expectedManufacturer);
service->readCharacteristic(manufacturerChar);
QTRY_VERIFY_WITH_TIMEOUT(!readSpy.isEmpty(), 10000);
QVERIFY(errorSpy.isEmpty());
- QCOMPARE(readSpy.count(), 1);
+ QCOMPARE(readSpy.size(), 1);
entry = readSpy[0];
QVERIFY(entry[0].value<QLowEnergyCharacteristic>() == manufacturerChar);
QCOMPARE(entry[1].toByteArray(), expectedManufacturer);
QCOMPARE(manufacturerChar.value(), expectedManufacturer);
delete service;
- control.disconnectFromDevice();
+ control->disconnectFromDevice();
+ QTRY_COMPARE(control->state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
}
@@ -2338,27 +2290,27 @@ void tst_QLowEnergyController::tst_errorCases()
if (!remoteDeviceInfo.isValid())
QSKIP("No remote BTLE device found. Skipping test.");
- QLowEnergyController control(remoteDeviceInfo);
- QCOMPARE(control.error(), QLowEnergyController::NoError);
+ QScopedPointer<QLowEnergyController> control(QLowEnergyController::createCentral(remoteDeviceInfo));
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
- control.connectToDevice();
+ control->connectToDevice();
{
- QTRY_IMPL(control.state() != QLowEnergyController::ConnectingState,
- 30000);
+ QTRY_IMPL(control->state() != QLowEnergyController::ConnectingState,
+ 30000)
}
- if (control.state() == QLowEnergyController::ConnectingState
- || control.error() != QLowEnergyController::NoError) {
+ if (control->state() == QLowEnergyController::ConnectingState
+ || control->error() != QLowEnergyController::NoError) {
// default BTLE backend forever hangs in ConnectingState
QSKIP("Cannot connect to remote device");
}
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
- QSignalSpy discoveryFinishedSpy(&control, SIGNAL(discoveryFinished()));
- QSignalSpy stateSpy(&control, SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
- control.discoverServices();
- QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 20000);
- QCOMPARE(stateSpy.count(), 2);
+ QCOMPARE(control->state(), QLowEnergyController::ConnectedState);
+ QSignalSpy discoveryFinishedSpy(control.data(), SIGNAL(discoveryFinished()));
+ QSignalSpy stateSpy(control.data(), SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
+ control->discoverServices();
+ QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.size() == 1, 20000);
+ QCOMPARE(stateSpy.size(), 2);
QCOMPARE(stateSpy.at(0).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveringState);
QCOMPARE(stateSpy.at(1).at(0).value<QLowEnergyController::ControllerState>(),
@@ -2371,17 +2323,17 @@ void tst_QLowEnergyController::tst_errorCases()
const QBluetoothUuid oadServiceUuid(QStringLiteral("f000ffc0-0451-4000-b000-000000000000"));
const QBluetoothUuid oadCharUuid(QString("f000ffc1-0451-4000-b000-000000000000"));
- QVERIFY(control.services().contains(irTemperaturServiceUuid));
- QVERIFY(control.services().contains(oadServiceUuid));
+ QVERIFY(control->services().contains(irTemperaturServiceUuid));
+ QVERIFY(control->services().contains(oadServiceUuid));
// Create service objects and basic tests
- QLowEnergyService *irService = control.createServiceObject(irTemperaturServiceUuid);
+ QLowEnergyService *irService = control->createServiceObject(irTemperaturServiceUuid);
QVERIFY(irService);
- QCOMPARE(irService->state(), QLowEnergyService::DiscoveryRequired);
+ QCOMPARE(irService->state(), QLowEnergyService::RemoteService);
QVERIFY(irService->characteristics().isEmpty());
- QLowEnergyService *oadService = control.createServiceObject(oadServiceUuid);
+ QLowEnergyService *oadService = control->createServiceObject(oadServiceUuid);
QVERIFY(oadService);
- QCOMPARE(oadService->state(), QLowEnergyService::DiscoveryRequired);
+ QCOMPARE(oadService->state(), QLowEnergyService::RemoteService);
QVERIFY(oadService->characteristics().isEmpty());
QLowEnergyCharacteristic invalidChar;
@@ -2390,8 +2342,8 @@ void tst_QLowEnergyController::tst_errorCases()
QVERIFY(!irService->contains(invalidChar));
QVERIFY(!irService->contains(invalidDesc));
- QSignalSpy irErrorSpy(irService, SIGNAL(error(QLowEnergyService::ServiceError)));
- QSignalSpy oadErrorSpy(oadService, SIGNAL(error(QLowEnergyService::ServiceError)));
+ QSignalSpy irErrorSpy(irService, SIGNAL(errorOccurred(QLowEnergyService::ServiceError)));
+ QSignalSpy oadErrorSpy(oadService, SIGNAL(errorOccurred(QLowEnergyService::ServiceError)));
QSignalSpy irReadSpy(irService, SIGNAL(characteristicRead(QLowEnergyCharacteristic,QByteArray)));
QSignalSpy irWrittenSpy(irService, SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray)));
@@ -2407,7 +2359,7 @@ void tst_QLowEnergyController::tst_errorCases()
// discover IR Service
irService->discoverDetails();
QTRY_VERIFY_WITH_TIMEOUT(
- irService->state() == QLowEnergyService::ServiceDiscovered, 30000);
+ irService->state() == QLowEnergyService::RemoteServiceDiscovered, 30000);
QVERIFY(!irService->contains(invalidChar));
QVERIFY(!irService->contains(invalidDesc));
irErrorSpy.clear();
@@ -2415,7 +2367,7 @@ void tst_QLowEnergyController::tst_errorCases()
// read invalid characteristic
irService->readCharacteristic(invalidChar);
QTRY_VERIFY_WITH_TIMEOUT(!irErrorSpy.isEmpty(), 5000);
- QCOMPARE(irErrorSpy.count(), 1);
+ QCOMPARE(irErrorSpy.size(), 1);
QVERIFY(irWrittenSpy.isEmpty());
QVERIFY(irReadSpy.isEmpty());
QCOMPARE(irErrorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
@@ -2425,7 +2377,7 @@ void tst_QLowEnergyController::tst_errorCases()
// read invalid descriptor
irService->readDescriptor(invalidDesc);
QTRY_VERIFY_WITH_TIMEOUT(!irErrorSpy.isEmpty(), 5000);
- QCOMPARE(irErrorSpy.count(), 1);
+ QCOMPARE(irErrorSpy.size(), 1);
QVERIFY(irDescWrittenSpy.isEmpty());
QVERIFY(irDescReadSpy.isEmpty());
QCOMPARE(irErrorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
@@ -2435,7 +2387,7 @@ void tst_QLowEnergyController::tst_errorCases()
// write invalid characteristic
irService->writeCharacteristic(invalidChar, QByteArray("foo"));
QTRY_VERIFY_WITH_TIMEOUT(!irErrorSpy.isEmpty(), 5000);
- QCOMPARE(irErrorSpy.count(), 1);
+ QCOMPARE(irErrorSpy.size(), 1);
QVERIFY(irWrittenSpy.isEmpty());
QVERIFY(irReadSpy.isEmpty());
QCOMPARE(irErrorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
@@ -2445,7 +2397,7 @@ void tst_QLowEnergyController::tst_errorCases()
// write invalid descriptor
irService->readDescriptor(invalidDesc);
QTRY_VERIFY_WITH_TIMEOUT(!irErrorSpy.isEmpty(), 5000);
- QCOMPARE(irErrorSpy.count(), 1);
+ QCOMPARE(irErrorSpy.size(), 1);
QVERIFY(irDescWrittenSpy.isEmpty());
QVERIFY(irDescReadSpy.isEmpty());
QCOMPARE(irErrorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
@@ -2459,7 +2411,7 @@ void tst_QLowEnergyController::tst_errorCases()
// read invalid characteristic
oadService->readCharacteristic(invalidChar);
QTRY_VERIFY_WITH_TIMEOUT(!oadErrorSpy.isEmpty(), 5000);
- QCOMPARE(oadErrorSpy.count(), 1);
+ QCOMPARE(oadErrorSpy.size(), 1);
QCOMPARE(oadErrorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
QLowEnergyService::OperationError);
oadErrorSpy.clear();
@@ -2467,7 +2419,7 @@ void tst_QLowEnergyController::tst_errorCases()
// read invalid descriptor
oadService->readDescriptor(invalidDesc);
QTRY_VERIFY_WITH_TIMEOUT(!oadErrorSpy.isEmpty(), 5000);
- QCOMPARE(oadErrorSpy.count(), 1);
+ QCOMPARE(oadErrorSpy.size(), 1);
QCOMPARE(oadErrorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
QLowEnergyService::OperationError);
oadErrorSpy.clear();
@@ -2475,7 +2427,7 @@ void tst_QLowEnergyController::tst_errorCases()
// write invalid characteristic
oadService->writeCharacteristic(invalidChar, QByteArray("foo"));
QTRY_VERIFY_WITH_TIMEOUT(!oadErrorSpy.isEmpty(), 5000);
- QCOMPARE(oadErrorSpy.count(), 1);
+ QCOMPARE(oadErrorSpy.size(), 1);
QCOMPARE(oadErrorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
QLowEnergyService::OperationError);
oadErrorSpy.clear();
@@ -2483,7 +2435,7 @@ void tst_QLowEnergyController::tst_errorCases()
// write invalid descriptor
oadService->readDescriptor(invalidDesc);
QTRY_VERIFY_WITH_TIMEOUT(!oadErrorSpy.isEmpty(), 5000);
- QCOMPARE(oadErrorSpy.count(), 1);
+ QCOMPARE(oadErrorSpy.size(), 1);
QCOMPARE(oadErrorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
QLowEnergyService::OperationError);
oadErrorSpy.clear();
@@ -2510,7 +2462,7 @@ void tst_QLowEnergyController::tst_errorCases()
// CharacteristicUserDescription is not writable
QLowEnergyDescriptor nonWritableDesc = nonWritableChar.descriptor(
- QBluetoothUuid::CharacteristicUserDescription);
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
QVERIFY(nonWritableDesc.isValid());
irService->writeDescriptor(nonWritableDesc, QByteArray("ABCD"));
QTRY_VERIFY_WITH_TIMEOUT(!irErrorSpy.isEmpty(), 5000);
@@ -2527,7 +2479,7 @@ void tst_QLowEnergyController::tst_errorCases()
// discover OAD Service
oadService->discoverDetails();
QTRY_VERIFY_WITH_TIMEOUT(
- oadService->state() == QLowEnergyService::ServiceDiscovered, 30000);
+ oadService->state() == QLowEnergyService::RemoteServiceDiscovered, 30000);
oadErrorSpy.clear();
// Test reading
@@ -2535,7 +2487,7 @@ void tst_QLowEnergyController::tst_errorCases()
QVERIFY(oadChar.isValid());
oadService->readCharacteristic(oadChar);
QTRY_VERIFY_WITH_TIMEOUT(!oadErrorSpy.isEmpty(), 5000);
- QCOMPARE(oadErrorSpy.count(), 1);
+ QCOMPARE(oadErrorSpy.size(), 1);
QVERIFY(oadCharReadSpy.isEmpty());
QCOMPARE(oadErrorSpy[0].at(0).value<QLowEnergyService::ServiceError>(),
QLowEnergyService::CharacteristicReadError);
@@ -2543,7 +2495,9 @@ void tst_QLowEnergyController::tst_errorCases()
delete irService;
delete oadService;
- control.disconnectFromDevice();
+ control->disconnectFromDevice();
+ QTRY_COMPARE(control->state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
}
/*
@@ -2560,28 +2514,28 @@ void tst_QLowEnergyController::tst_writeCharacteristicNoResponse()
if (!remoteDeviceInfo.isValid())
QSKIP("No remote BTLE device found. Skipping test.");
- QLowEnergyController control(remoteDeviceInfo);
+ QScopedPointer<QLowEnergyController> control(QLowEnergyController::createCentral(remoteDeviceInfo));
- QCOMPARE(control.error(), QLowEnergyController::NoError);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
- control.connectToDevice();
+ control->connectToDevice();
{
- QTRY_IMPL(control.state() != QLowEnergyController::ConnectingState,
- 30000);
+ QTRY_IMPL(control->state() != QLowEnergyController::ConnectingState,
+ 30000)
}
- if (control.state() == QLowEnergyController::ConnectingState
- || control.error() != QLowEnergyController::NoError) {
+ if (control->state() == QLowEnergyController::ConnectingState
+ || control->error() != QLowEnergyController::NoError) {
// default BTLE backend forever hangs in ConnectingState
QSKIP("Cannot connect to remote device");
}
- QCOMPARE(control.state(), QLowEnergyController::ConnectedState);
- QSignalSpy discoveryFinishedSpy(&control, SIGNAL(discoveryFinished()));
- QSignalSpy stateSpy(&control, SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
- control.discoverServices();
- QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 20000);
- QCOMPARE(stateSpy.count(), 2);
+ QTRY_VERIFY_WITH_TIMEOUT(control->state() == QLowEnergyController::ConnectedState, 20000);
+ QSignalSpy discoveryFinishedSpy(control.data(), SIGNAL(discoveryFinished()));
+ QSignalSpy stateSpy(control.data(), SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
+ control->discoverServices();
+ QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.size() == 1, 20000);
+ QCOMPARE(stateSpy.size(), 2);
QCOMPARE(stateSpy.at(0).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveringState);
QCOMPARE(stateSpy.at(1).at(0).value<QLowEnergyController::ControllerState>(),
@@ -2589,14 +2543,14 @@ void tst_QLowEnergyController::tst_writeCharacteristicNoResponse()
// The Over-The-Air update service uuid
const QBluetoothUuid testService(QString("f000ffc0-0451-4000-b000-000000000000"));
- QList<QBluetoothUuid> uuids = control.services();
+ QList<QBluetoothUuid> uuids = control->services();
QVERIFY(uuids.contains(testService));
- QLowEnergyService *service = control.createServiceObject(testService, this);
+ QLowEnergyService *service = control->createServiceObject(testService, this);
QVERIFY(service);
service->discoverDetails();
QTRY_VERIFY_WITH_TIMEOUT(
- service->state() == QLowEnergyService::ServiceDiscovered, 30000);
+ service->state() == QLowEnergyService::RemoteServiceDiscovered, 30000);
// 1. Get "Image Identity" and "Image Block" characteristic
const QLowEnergyCharacteristic imageIdentityChar = service->characteristic(
@@ -2611,15 +2565,17 @@ void tst_QLowEnergyController::tst_writeCharacteristicNoResponse()
// 2. Get "Image Identity" notification descriptor
const QLowEnergyDescriptor identityNotification = imageIdentityChar.descriptor(
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
const QLowEnergyDescriptor blockNotification = imageBlockChar.descriptor(
- QBluetoothUuid(QBluetoothUuid::ClientCharacteristicConfiguration));
+ QBluetoothUuid(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration));
if (!identityNotification.isValid()
|| !blockNotification.isValid()
|| !imageIdentityChar.isValid()) {
delete service;
- control.disconnectFromDevice();
+ control->disconnectFromDevice();
+ QTRY_COMPARE(control->state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
QSKIP("Cannot find OAD char/notification");
}
@@ -2632,8 +2588,7 @@ void tst_QLowEnergyController::tst_writeCharacteristicNoResponse()
SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray)));
QSignalSpy charReadSpy(service,
SIGNAL(characteristicRead(QLowEnergyCharacteristic,QByteArray)));
- QSignalSpy errorSpy(service,
- SIGNAL(error(QLowEnergyService::ServiceError)));
+ QSignalSpy errorSpy(service, SIGNAL(errorOccurred(QLowEnergyService::ServiceError)));
//enable notifications on both characteristics
if (identityNotification.value() != QByteArray::fromHex("0100")) {
@@ -2667,7 +2622,7 @@ void tst_QLowEnergyController::tst_writeCharacteristicNoResponse()
QVERIFY(charReadSpy.isEmpty());
service->readCharacteristic(imageIdentityChar);
QTRY_VERIFY_WITH_TIMEOUT(!errorSpy.isEmpty(), 10000);
- QCOMPARE(errorSpy.count(), 1); // should throw CharacteristicReadError
+ QCOMPARE(errorSpy.size(), 1); // should throw CharacteristicReadError
QVERIFY(charReadSpy.isEmpty());
entry = errorSpy[0];
QCOMPARE(entry[0].value<QLowEnergyService::ServiceError>(),
@@ -2680,8 +2635,8 @@ void tst_QLowEnergyController::tst_writeCharacteristicNoResponse()
// Write triggers a notification and write confirmation
service->writeCharacteristic(imageIdentityChar, QByteArray::fromHex("0"));
QTest::qWait(1000);
- QTRY_COMPARE_WITH_TIMEOUT(charChangedSpy.count(), 1, 5000);
- QTRY_COMPARE_WITH_TIMEOUT(charWrittenSpy.count(), 1, 5000);
+ QTRY_COMPARE_WITH_TIMEOUT(charChangedSpy.size(), 1, 5000);
+ QTRY_COMPARE_WITH_TIMEOUT(charWrittenSpy.size(), 1, 5000);
// This is very SensorTag specific logic.
// If the image block is empty the current firmware
@@ -2716,8 +2671,8 @@ void tst_QLowEnergyController::tst_writeCharacteristicNoResponse()
// Image B
service->writeCharacteristic(imageIdentityChar, QByteArray::fromHex("1"));
QTest::qWait(1000);
- QTRY_COMPARE_WITH_TIMEOUT(charChangedSpy.count(), 1, 5000);
- QTRY_COMPARE_WITH_TIMEOUT(charWrittenSpy.count(), 1, 5000);;
+ QTRY_COMPARE_WITH_TIMEOUT(charChangedSpy.size(), 1, 5000);
+ QTRY_COMPARE_WITH_TIMEOUT(charWrittenSpy.size(), 1, 5000);;
entry = charChangedSpy[0];
first = entry[0].value<QLowEnergyCharacteristic>();
@@ -2762,8 +2717,8 @@ void tst_QLowEnergyController::tst_writeCharacteristicNoResponse()
// we only expect one signal (the notification but not the write confirmation)
// Wait at least a second for a potential second signals
QTest::qWait(1000);
- QTRY_COMPARE_WITH_TIMEOUT(charChangedSpy.count(), 1, 10000);
- QTRY_COMPARE_WITH_TIMEOUT(charWrittenSpy.count(), 0, 10000);
+ QTRY_COMPARE_WITH_TIMEOUT(charChangedSpy.size(), 1, 10000);
+ QTRY_COMPARE_WITH_TIMEOUT(charWrittenSpy.size(), 0, 10000);
entry = charChangedSpy[0];
first = entry[0].value<QLowEnergyCharacteristic>();
@@ -2798,8 +2753,8 @@ void tst_QLowEnergyController::tst_writeCharacteristicNoResponse()
// we only expect one signal (the notification but not the write confirmation)
// Wait at least a second for a potential second signals
QTest::qWait(1000);
- QTRY_COMPARE_WITH_TIMEOUT(charWrittenSpy.count(), 0, 10000);
- QTRY_COMPARE_WITH_TIMEOUT(charChangedSpy.count(), 1, 10000);
+ QTRY_COMPARE_WITH_TIMEOUT(charWrittenSpy.size(), 0, 10000);
+ QTRY_COMPARE_WITH_TIMEOUT(charChangedSpy.size(), 1, 10000);
entry = charChangedSpy[0];
first = entry[0].value<QLowEnergyCharacteristic>();
@@ -2828,7 +2783,37 @@ void tst_QLowEnergyController::tst_writeCharacteristicNoResponse()
QVERIFY2(foundOneImage, "The SensorTag doesn't have a valid image? (2)");
delete service;
- control.disconnectFromDevice();
+ control->disconnectFromDevice();
+ QTRY_COMPARE(control->state(), QLowEnergyController::UnconnectedState);
+ QCOMPARE(control->error(), QLowEnergyController::NoError);
+}
+
+using namespace Qt::Literals::StringLiterals;
+
+void tst_QLowEnergyController::tst_rssiError()
+{
+ // Create unconnected/invalid controller instances and verify that
+ // reading RSSI value triggers error signal. For the actual
+ // RSSI read testing see tst_qlowenergycontroller_device
+
+ // Peripheral
+ std::unique_ptr<QLowEnergyController> peripheral{QLowEnergyController::createPeripheral()};
+ QSignalSpy peripheralErrorSpy(peripheral.get(), &QLowEnergyController::errorOccurred);
+ peripheral->readRssi();
+ QTRY_VERIFY(!peripheralErrorSpy.isEmpty());
+ QCOMPARE(peripheralErrorSpy.takeFirst().at(0).value<QLowEnergyController::Error>(),
+ QLowEnergyController::Error::RssiReadError);
+ QCOMPARE(peripheral->error(), QLowEnergyController::Error::RssiReadError);
+
+ // Central
+ QBluetoothDeviceInfo info(QBluetoothAddress{u"11:22:33:44:55:66"_s}, u"invalid"_s, 1);
+ std::unique_ptr<QLowEnergyController> central{QLowEnergyController::createCentral(info)};
+ QSignalSpy centralErrorSpy(central.get(), &QLowEnergyController::errorOccurred);
+ central->readRssi();
+ QTRY_VERIFY(!centralErrorSpy.isEmpty());
+ QCOMPARE(centralErrorSpy.takeFirst().at(0).value<QLowEnergyController::Error>(),
+ QLowEnergyController::Error::RssiReadError);
+ QCOMPARE(central->error(), QLowEnergyController::Error::RssiReadError);
}
QTEST_MAIN(tst_QLowEnergyController)
diff --git a/tests/auto/qlowenergydescriptor/CMakeLists.txt b/tests/auto/qlowenergydescriptor/CMakeLists.txt
new file mode 100644
index 00000000..81b814e1
--- /dev/null
+++ b/tests/auto/qlowenergydescriptor/CMakeLists.txt
@@ -0,0 +1,31 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qlowenergydescriptor Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qlowenergydescriptor LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qlowenergydescriptor
+ SOURCES
+ tst_qlowenergydescriptor.cpp
+ LIBRARIES
+ Qt::Bluetooth
+)
+
+set_target_properties(tst_qlowenergydescriptor PROPERTIES
+ MACOSX_BUNDLE TRUE
+)
+
+if (APPLE AND NOT IOS)
+ # Ninja has trouble with relative paths, convert to absolute as a workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../shared ABSOLUTE)
+ set_target_properties(tst_qlowenergydescriptor PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.macos.plist"
+ )
+endif()
diff --git a/tests/auto/qlowenergydescriptor/qlowenergydescriptor.pro b/tests/auto/qlowenergydescriptor/qlowenergydescriptor.pro
deleted file mode 100644
index 81ec9566..00000000
--- a/tests/auto/qlowenergydescriptor/qlowenergydescriptor.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-SOURCES += tst_qlowenergydescriptor.cpp
-TARGET = tst_qlowenergydescriptor
-CONFIG += testcase
-
-QT = core bluetooth testlib
-
diff --git a/tests/auto/qlowenergydescriptor/tst_qlowenergydescriptor.cpp b/tests/auto/qlowenergydescriptor/tst_qlowenergydescriptor.cpp
index 5ebb0b1d..8d9b04b7 100644
--- a/tests/auto/qlowenergydescriptor/tst_qlowenergydescriptor.cpp
+++ b/tests/auto/qlowenergydescriptor/tst_qlowenergydescriptor.cpp
@@ -1,31 +1,6 @@
-/***************************************************************************
-**
-** Copyright (C) 2016 BlackBerry Limited all rights reserved
-** 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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 BlackBerry Limited all rights reserved
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QUuid>
@@ -37,6 +12,12 @@
#include <QLowEnergyController>
#include <QBluetoothLocalDevice>
+#if QT_CONFIG(permissions)
+#include <QCoreApplication>
+#include <QPermissions>
+#include <QtCore/qnamespace.h>
+#endif
+
QT_USE_NAMESPACE
class tst_QLowEnergyDescriptor : public QObject
@@ -60,12 +41,28 @@ private:
QList<QBluetoothDeviceInfo> remoteLeDeviceInfos;
QLowEnergyController *globalControl;
QLowEnergyService *globalService;
+#if QT_CONFIG(permissions)
+ Qt::PermissionStatus permissionStatus = Qt::PermissionStatus::Undetermined;
+#endif
};
tst_QLowEnergyDescriptor::tst_QLowEnergyDescriptor() :
- globalControl(0), globalService(0)
+ globalControl(nullptr), globalService(nullptr)
{
QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
+#if QT_CONFIG(permissions)
+ permissionStatus = qApp->checkPermission(QBluetoothPermission{});
+ const bool ciRun = qEnvironmentVariable("QTEST_ENVIRONMENT").split(' ').contains("ci");
+ if (!ciRun && permissionStatus == Qt::PermissionStatus::Undetermined) {
+ QTestEventLoop loop;
+ qApp->requestPermission(QBluetoothPermission{}, [this, &loop](const QPermission &permission){
+ permissionStatus = permission.status();
+ loop.exitLoop();
+ });
+ if (permissionStatus == Qt::PermissionStatus::Undetermined)
+ loop.enterLoopMSecs(30000);
+ }
+#endif // QT_CONFIG(permissions)
}
tst_QLowEnergyDescriptor::~tst_QLowEnergyDescriptor()
@@ -75,23 +72,36 @@ tst_QLowEnergyDescriptor::~tst_QLowEnergyDescriptor()
void tst_QLowEnergyDescriptor::initTestCase()
{
if (QBluetoothLocalDevice::allDevices().isEmpty()) {
- qWarning("No remote device discovered.");
-
+ qWarning("No local adapter, not discovering remote devices");
return;
}
- // start Bluetooth if not started
QBluetoothLocalDevice device;
- device.powerOn();
+ if (device.hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
+ // Attempt to switch Bluetooth ON
+ device.powerOn();
+ QTest::qWait(1000);
+ if (device.hostMode() == QBluetoothLocalDevice::HostPoweredOff) {
+ qWarning("Bluetooth couldn't be switched ON, not discovering remote devices");
+ return;
+ }
+ }
- // find an arbitrary low energy device in vincinity
+#if QT_CONFIG(permissions)
+ if (permissionStatus != Qt::PermissionStatus::Granted) {
+ qWarning("Use of BLuetooth LE requires the Bluetooth permission granted");
+ return;
+ }
+#endif
+
+ // find an arbitrary low energy device in vicinity
// find an arbitrary service with descriptor
QBluetoothDeviceDiscoveryAgent *devAgent = new QBluetoothDeviceDiscoveryAgent(this);
connect(devAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
this, SLOT(deviceDiscovered(QBluetoothDeviceInfo)));
- QSignalSpy errorSpy(devAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)));
+ QSignalSpy errorSpy(devAgent, SIGNAL(errorOccurred(QBluetoothDeviceDiscoveryAgent::Error)));
QVERIFY(errorSpy.isValid());
QVERIFY(errorSpy.isEmpty());
@@ -101,16 +111,16 @@ void tst_QLowEnergyDescriptor::initTestCase()
QVERIFY(spy.isEmpty());
devAgent->start();
- QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, 50000);
+ QTRY_VERIFY_WITH_TIMEOUT(spy.size() > 0, 100000);
// find first service with descriptor
- QLowEnergyController *controller = 0;
- for (const QBluetoothDeviceInfo& remoteDeviceInfo : qAsConst(remoteLeDeviceInfos)) {
+ QLowEnergyController *controller = nullptr;
+ for (const QBluetoothDeviceInfo& remoteDeviceInfo : std::as_const(remoteLeDeviceInfos)) {
controller = QLowEnergyController::createCentral(remoteDeviceInfo, this);
qDebug() << "Connecting to" << remoteDeviceInfo.address();
controller->connectToDevice();
QTRY_IMPL(controller->state() != QLowEnergyController::ConnectingState,
- 20000);
+ 50000)
if (controller->state() != QLowEnergyController::ConnectedState) {
// any error and we skip
delete controller;
@@ -121,8 +131,8 @@ void tst_QLowEnergyDescriptor::initTestCase()
QSignalSpy discoveryFinishedSpy(controller, SIGNAL(discoveryFinished()));
QSignalSpy stateSpy(controller, SIGNAL(stateChanged(QLowEnergyController::ControllerState)));
controller->discoverServices();
- QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 10000);
- QCOMPARE(stateSpy.count(), 2);
+ QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.size() == 1, 10000);
+ QCOMPARE(stateSpy.size(), 2);
QCOMPARE(stateSpy.at(0).at(0).value<QLowEnergyController::ControllerState>(),
QLowEnergyController::DiscoveringState);
QCOMPARE(stateSpy.at(1).at(0).value<QLowEnergyController::ControllerState>(),
@@ -136,7 +146,7 @@ void tst_QLowEnergyDescriptor::initTestCase()
leService->discoverDetails();
QTRY_VERIFY_WITH_TIMEOUT(
- leService->state() == QLowEnergyService::ServiceDiscovered, 10000);
+ leService->state() == QLowEnergyService::RemoteServiceDiscovered, 10000);
const QList<QLowEnergyCharacteristic> chars = leService->characteristics();
for (const QLowEnergyCharacteristic &ch : chars) {
@@ -190,17 +200,15 @@ void tst_QLowEnergyDescriptor::tst_constructionDefault()
QVERIFY(!descriptor.isValid());
QCOMPARE(descriptor.value(), QByteArray());
QVERIFY(descriptor.uuid().isNull());
- QVERIFY(descriptor.handle() == 0);
QCOMPARE(descriptor.name(), QString());
- QCOMPARE(descriptor.type(), QBluetoothUuid::UnknownDescriptorType);
+ QCOMPARE(descriptor.type(), QBluetoothUuid::DescriptorType::UnknownDescriptorType);
QLowEnergyDescriptor copyConstructed(descriptor);
QVERIFY(!copyConstructed.isValid());
QCOMPARE(copyConstructed.value(), QByteArray());
QVERIFY(copyConstructed.uuid().isNull());
- QVERIFY(copyConstructed.handle() == 0);
QCOMPARE(copyConstructed.name(), QString());
- QCOMPARE(copyConstructed.type(), QBluetoothUuid::UnknownDescriptorType);
+ QCOMPARE(copyConstructed.type(), QBluetoothUuid::DescriptorType::UnknownDescriptorType);
QVERIFY(copyConstructed == descriptor);
QVERIFY(descriptor == copyConstructed);
@@ -218,9 +226,8 @@ void tst_QLowEnergyDescriptor::tst_constructionDefault()
QVERIFY(!assigned.isValid());
QCOMPARE(assigned.value(), QByteArray());
QVERIFY(assigned.uuid().isNull());
- QVERIFY(assigned.handle() == 0);
QCOMPARE(assigned.name(), QString());
- QCOMPARE(assigned.type(), QBluetoothUuid::UnknownDescriptorType);
+ QCOMPARE(assigned.type(), QBluetoothUuid::DescriptorType::UnknownDescriptorType);
QVERIFY(assigned == descriptor);
QVERIFY(descriptor == assigned);
@@ -237,22 +244,23 @@ void tst_QLowEnergyDescriptor::tst_assignCompare()
QLowEnergyDescriptor target;
QVERIFY(!target.isValid());
- QCOMPARE(target.type(), QBluetoothUuid::UnknownDescriptorType);
+ QCOMPARE(target.type(), QBluetoothUuid::DescriptorType::UnknownDescriptorType);
QCOMPARE(target.name(), QString());
- QCOMPARE(target.handle(), QLowEnergyHandle(0));
QCOMPARE(target.uuid(), QBluetoothUuid());
QCOMPARE(target.value(), QByteArray());
- int index = -1;
+ qsizetype index = 0;
+ bool valueFound = false;
QList<QLowEnergyDescriptor> targets;
const QList<QLowEnergyCharacteristic> chars = globalService->characteristics();
for (const QLowEnergyCharacteristic &ch : chars) {
if (!ch.descriptors().isEmpty()) {
targets = ch.descriptors();
- for (int i = 0; i < targets.size(); ++i) {
+ for (qsizetype i = 0; i < targets.size(); ++i) {
// try to get a descriptor we can read
- if (targets[i].type() == QBluetoothUuid::CharacteristicUserDescription) {
+ if (targets[i].type() == QBluetoothUuid::DescriptorType::CharacteristicUserDescription) {
index = i;
+ valueFound = true;
break;
}
}
@@ -263,16 +271,13 @@ void tst_QLowEnergyDescriptor::tst_assignCompare()
if (targets.isEmpty())
QSKIP("No descriptor found despite prior indication.");
- QVERIFY(index != -1);
-
// test assignment operator
target = targets[index];
QVERIFY(target.isValid());
- QVERIFY(target.type() != QBluetoothUuid::UnknownDescriptorType);
+ QVERIFY(target.type() != QBluetoothUuid::DescriptorType::UnknownDescriptorType);
QVERIFY(!target.name().isEmpty());
- QVERIFY(target.handle() > 0);
QVERIFY(!target.uuid().isNull());
- QVERIFY(!target.value().isEmpty());
+ QVERIFY(!valueFound || !target.value().isEmpty());
QVERIFY(target == targets[index]);
QVERIFY(targets[index] == target);
@@ -282,7 +287,6 @@ void tst_QLowEnergyDescriptor::tst_assignCompare()
QCOMPARE(target.isValid(), targets[index].isValid());
QCOMPARE(target.type(), targets[index].type());
QCOMPARE(target.name(), targets[index].name());
- QCOMPARE(target.handle(), targets[index].handle());
QCOMPARE(target.uuid(), targets[index].uuid());
QCOMPARE(target.value(), targets[index].value());
@@ -291,7 +295,6 @@ void tst_QLowEnergyDescriptor::tst_assignCompare()
QCOMPARE(copyConstructed.isValid(), targets[index].isValid());
QCOMPARE(copyConstructed.type(), targets[index].type());
QCOMPARE(copyConstructed.name(), targets[index].name());
- QCOMPARE(copyConstructed.handle(), targets[index].handle());
QCOMPARE(copyConstructed.uuid(), targets[index].uuid());
QCOMPARE(copyConstructed.value(), targets[index].value());
@@ -306,9 +309,8 @@ void tst_QLowEnergyDescriptor::tst_assignCompare()
QVERIFY(!target.isValid());
QCOMPARE(target.value(), QByteArray());
QVERIFY(target.uuid().isNull());
- QVERIFY(target.handle() == 0);
QCOMPARE(target.name(), QString());
- QCOMPARE(target.type(), QBluetoothUuid::UnknownDescriptorType);
+ QCOMPARE(target.type(), QBluetoothUuid::DescriptorType::UnknownDescriptorType);
QVERIFY(invalid == target);
QVERIFY(target == invalid);
@@ -320,7 +322,7 @@ void tst_QLowEnergyDescriptor::tst_assignCompare()
QVERIFY(targets[index] != target);
QVERIFY(target != targets[index]);
- if (targets.count() >= 2) {
+ if (targets.size() >= 2) {
QLowEnergyDescriptor second = targets[(index+1)%2];
// at least two descriptors
QVERIFY(!(targets[index] == second));
diff --git a/tests/auto/qlowenergyservice/CMakeLists.txt b/tests/auto/qlowenergyservice/CMakeLists.txt
new file mode 100644
index 00000000..eba5db0e
--- /dev/null
+++ b/tests/auto/qlowenergyservice/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qlowenergyservice Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qlowenergyservice LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qlowenergyservice
+ SOURCES
+ tst_qlowenergyservice.cpp
+ LIBRARIES
+ Qt::Bluetooth
+)
diff --git a/tests/auto/qlowenergyservice/qlowenergyservice.pro b/tests/auto/qlowenergyservice/qlowenergyservice.pro
deleted file mode 100644
index 6d074d82..00000000
--- a/tests/auto/qlowenergyservice/qlowenergyservice.pro
+++ /dev/null
@@ -1,6 +0,0 @@
-SOURCES += tst_qlowenergyservice.cpp
-TARGET = tst_qlowenergyservice
-CONFIG += testcase
-
-QT = core bluetooth testlib
-
diff --git a/tests/auto/qlowenergyservice/tst_qlowenergyservice.cpp b/tests/auto/qlowenergyservice/tst_qlowenergyservice.cpp
index 19fa059d..670a592d 100644
--- a/tests/auto/qlowenergyservice/tst_qlowenergyservice.cpp
+++ b/tests/auto/qlowenergyservice/tst_qlowenergyservice.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
diff --git a/tests/auto/qndeffilter/CMakeLists.txt b/tests/auto/qndeffilter/CMakeLists.txt
new file mode 100644
index 00000000..e7fb1e51
--- /dev/null
+++ b/tests/auto/qndeffilter/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qndeffilter LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qndeffilter
+ SOURCES
+ tst_qndeffilter.cpp
+ LIBRARIES
+ Qt::Nfc
+)
diff --git a/tests/auto/qndeffilter/tst_qndeffilter.cpp b/tests/auto/qndeffilter/tst_qndeffilter.cpp
new file mode 100644
index 00000000..90493e42
--- /dev/null
+++ b/tests/auto/qndeffilter/tst_qndeffilter.cpp
@@ -0,0 +1,485 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
+
+#include <QNdefFilter>
+#include <QNdefNfcSmartPosterRecord>
+#include <QNdefNfcTextRecord>
+#include <QNdefNfcUriRecord>
+#include <QNdefMessage>
+
+QT_USE_NAMESPACE
+
+class tst_QNdefFilter : public QObject
+{
+ Q_OBJECT
+private slots:
+ void construct();
+ void copyConstruct();
+ void assingmentOperator();
+
+ void clearFilter();
+
+ void orderMatch();
+
+ void appendRecord();
+ void appendRecord_data();
+
+ void appendRecordParameters();
+ void appendRecordParameters_data();
+
+ void appendRecordTemplate();
+ void appendRecordTemplate_data();
+
+ void match();
+ void match_data();
+};
+
+void tst_QNdefFilter::construct()
+{
+ QNdefFilter filter;
+ QCOMPARE(filter.recordCount(), 0);
+ QCOMPARE(filter.orderMatch(), false);
+}
+
+void tst_QNdefFilter::copyConstruct()
+{
+ QNdefFilter filter;
+ filter.setOrderMatch(true);
+ filter.appendRecord<QNdefNfcTextRecord>(1, 2);
+ filter.appendRecord(QNdefRecord::Empty, "", 0, 1);
+
+ QNdefFilter filterCopy(filter);
+ QCOMPARE(filterCopy.orderMatch(), true);
+ QCOMPARE(filterCopy.recordCount(), 2);
+ QNdefFilter::Record rec = filterCopy.recordAt(1);
+ QCOMPARE(rec.typeNameFormat, QNdefRecord::Empty);
+ QCOMPARE(rec.type, QByteArray());
+ QCOMPARE(rec.minimum, 0U);
+ QCOMPARE(rec.maximum, 1U);
+}
+
+void tst_QNdefFilter::assingmentOperator()
+{
+ QNdefFilter filter;
+ filter.setOrderMatch(true);
+ filter.appendRecord<QNdefNfcTextRecord>(1, 2);
+ filter.appendRecord(QNdefRecord::Empty, "", 0, 1);
+
+ QNdefFilter filterCopy;
+ filterCopy = filter;
+
+ QCOMPARE(filterCopy.orderMatch(), true);
+ QCOMPARE(filterCopy.recordCount(), 2);
+ QNdefFilter::Record rec = filterCopy.recordAt(1);
+ QCOMPARE(rec.typeNameFormat, QNdefRecord::Empty);
+ QCOMPARE(rec.type, QByteArray());
+ QCOMPARE(rec.minimum, 0U);
+ QCOMPARE(rec.maximum, 1U);
+}
+
+void tst_QNdefFilter::clearFilter()
+{
+ QNdefFilter filter;
+ filter.setOrderMatch(true);
+ filter.appendRecord<QNdefNfcTextRecord>(1, 2);
+ filter.appendRecord(QNdefRecord::Empty, "", 0, 1);
+
+ filter.clear();
+
+ QCOMPARE(filter.orderMatch(), false);
+ QCOMPARE(filter.recordCount(), 0);
+}
+
+void tst_QNdefFilter::orderMatch()
+{
+ QNdefFilter filter;
+ QCOMPARE(filter.orderMatch(), false);
+
+ filter.setOrderMatch(true);
+ QCOMPARE(filter.orderMatch(), true);
+
+ filter.setOrderMatch(false);
+ QCOMPARE(filter.orderMatch(), false);
+}
+
+void tst_QNdefFilter::appendRecord()
+{
+ QFETCH(QNdefRecord::TypeNameFormat, typeNameFormat);
+ QFETCH(QByteArray, type);
+ QFETCH(unsigned int, minimum);
+ QFETCH(unsigned int, maximum);
+ QFETCH(bool, result);
+
+ QNdefFilter filter;
+
+ const QNdefFilter::Record record { typeNameFormat, type, minimum, maximum };
+ QVERIFY(filter.appendRecord(record) == result);
+ const int desiredRecordCount = result ? 1 : 0;
+ QCOMPARE(filter.recordCount(), desiredRecordCount);
+}
+
+void tst_QNdefFilter::appendRecord_data()
+{
+ QTest::addColumn<QNdefRecord::TypeNameFormat>("typeNameFormat");
+ QTest::addColumn<QByteArray>("type");
+ QTest::addColumn<unsigned int>("minimum");
+ QTest::addColumn<unsigned int>("maximum");
+ QTest::addColumn<bool>("result");
+
+ constexpr struct {
+ const char *type;
+ QNdefRecord::TypeNameFormat format;
+ } inputs[] = {
+ { "Empty", QNdefRecord::Empty },
+ { "NfcRtd", QNdefRecord::NfcRtd },
+ { "Mime", QNdefRecord::Mime },
+ { "Uri", QNdefRecord::Uri},
+ { "ExternalRtd", QNdefRecord::ExternalRtd },
+ { "Unknown", QNdefRecord::Unknown }
+ };
+
+ for (auto [typeC, format] : inputs) {
+ const auto type = QByteArray::fromRawData(typeC, strlen(typeC));
+ QTest::addRow("%s; min < max", typeC) << format << type << 1u << 2u << true;
+ QTest::addRow("%s; min == max", typeC) << format << type << 2u << 2u << true;
+ QTest::addRow("%s; min > max", typeC) << format << type << 2u << 1u << false;
+ }
+}
+
+void tst_QNdefFilter::appendRecordParameters()
+{
+ QFETCH(QNdefRecord::TypeNameFormat, typeNameFormat);
+ QFETCH(QByteArray, type);
+ QFETCH(unsigned int, minimum);
+ QFETCH(unsigned int, maximum);
+ QFETCH(bool, result);
+
+ QNdefFilter filter;
+
+ QVERIFY(filter.appendRecord(typeNameFormat, type, minimum, maximum) == result);
+ const int desiredRecordCount = result ? 1 : 0;
+ QCOMPARE(filter.recordCount(), desiredRecordCount);
+}
+
+void tst_QNdefFilter::appendRecordParameters_data()
+{
+ appendRecord_data();
+}
+
+void tst_QNdefFilter::appendRecordTemplate()
+{
+ QFETCH(QByteArray, type);
+ QFETCH(unsigned int, minimum);
+ QFETCH(unsigned int, maximum);
+ QFETCH(bool, result);
+
+ QNdefFilter filter;
+ if (type == QByteArray("SmartPoster"))
+ QVERIFY(filter.appendRecord<QNdefNfcSmartPosterRecord>(minimum, maximum) == result);
+ else if (type == QByteArray("Text"))
+ QVERIFY(filter.appendRecord<QNdefNfcTextRecord>(minimum, maximum) == result);
+ else if (type == QByteArray("Uri"))
+ QVERIFY(filter.appendRecord<QNdefNfcUriRecord>(minimum, maximum) == result);
+
+ const int desiredRecordCount = result ? 1 : 0;
+ QCOMPARE(filter.recordCount(), desiredRecordCount);
+}
+
+void tst_QNdefFilter::appendRecordTemplate_data()
+{
+ QTest::addColumn<QByteArray>("type");
+ QTest::addColumn<unsigned int>("minimum");
+ QTest::addColumn<unsigned int>("maximum");
+ QTest::addColumn<bool>("result");
+
+ const QList<QByteArray> types {"SmartPoster", "Text", "Uri"};
+ for (const auto &type : types) {
+ QTest::newRow(type + "; min < max") << type << 1u << 2u << true;
+ QTest::newRow(type + "; min == max") << type << 2u << 2u << true;
+ QTest::newRow(type + "; min > max") << type << 2u << 1u << false;
+ }
+}
+
+void tst_QNdefFilter::match()
+{
+ QFETCH(QNdefFilter, filter);
+ QFETCH(QNdefMessage, message);
+ QFETCH(bool, result);
+
+ QCOMPARE(filter.match(message), result);
+}
+
+void tst_QNdefFilter::match_data()
+{
+ QTest::addColumn<QNdefFilter>("filter");
+ QTest::addColumn<QNdefMessage>("message");
+ QTest::addColumn<bool>("result");
+
+ QNdefFilter filter;
+ filter.appendRecord<QNdefNfcTextRecord>(1, 2);
+ filter.appendRecord(QNdefRecord::Mime, "image/png", 1, 1);
+ filter.appendRecord(QNdefRecord::Empty, "", 0, 100);
+
+ QNdefNfcTextRecord textRec;
+ textRec.setPayload("text");
+
+ QNdefRecord mimeRec;
+ mimeRec.setTypeNameFormat(QNdefRecord::Mime);
+ mimeRec.setType("image/png");
+ mimeRec.setPayload("some image should be here");
+
+ QNdefRecord emptyRec;
+ emptyRec.setTypeNameFormat(QNdefRecord::Empty);
+
+ {
+ QTest::addRow("empty filter, empty message, match")
+ << QNdefFilter() << QNdefMessage() << true;
+
+ QNdefMessage message;
+ message.push_back(emptyRec);
+
+ QTest::addRow("empty filter, non-empty message, no match")
+ << QNdefFilter() << message << false;
+
+ QTest::addRow("non-empty filter, empty message, no match")
+ << filter << QNdefMessage() << false;
+
+ QNdefFilter f;
+ f.appendRecord<QNdefNfcUriRecord>(0, 1);
+
+ QTest::addRow("filter with 0 or 1 rec, empty message, match")
+ << f << QNdefMessage() << true;
+
+ QNdefMessage uriMsg;
+ uriMsg.push_back(QNdefNfcUriRecord());
+
+ QTest::addRow("filter with 0 or 1 rec, one record, match") << f << uriMsg << true;
+
+ uriMsg.push_back(QNdefNfcUriRecord());
+
+ QTest::addRow("filter with 0 or 1 rec, too many records, no match") << f << uriMsg << false;
+ }
+
+ {
+ filter.setOrderMatch(false);
+
+ QNdefMessage message;
+ message.push_back(textRec);
+ message.push_back(mimeRec);
+
+ QTest::addRow("No optional records, no ordering, match") << filter << message << true;
+
+ message.push_back(emptyRec);
+ message.push_back(emptyRec);
+
+ QTest::addRow("Multiple records with optional, no ordering, match")
+ << filter << message << true;
+
+ filter.setOrderMatch(true);
+
+ QTest::addRow("Multiple records with optional, with ordering, match")
+ << filter << message << true;
+ }
+
+ {
+ filter.setOrderMatch(false);
+
+ QNdefMessage message;
+ message.push_back(mimeRec);
+ message.push_back(emptyRec);
+ message.push_back(textRec);
+ message.push_back(emptyRec);
+ message.push_back(textRec);
+
+ QTest::addRow("Random order, no ordering, match") << filter << message << true;
+
+ filter.setOrderMatch(true);
+ QTest::addRow("Random order, with ordering, no match") << filter << message << false;
+ }
+
+ {
+ filter.setOrderMatch(false);
+
+ QNdefRecord rec;
+ rec.setTypeNameFormat(QNdefRecord::NfcRtd);
+ rec.setType("image/png");
+ rec.setPayload("borken image with invalid format");
+
+ QNdefMessage message;
+ message.push_back(textRec);
+ message.push_back(rec);
+
+ QTest::addRow("TypeNameFormat mismatch, no ordering, no match")
+ << filter << message << false;
+
+ filter.setOrderMatch(true);
+ QTest::addRow("TypeNameFormat mismatch, with ordering, no match")
+ << filter << message << false;
+ }
+
+ {
+ filter.setOrderMatch(false);
+
+ QNdefRecord rec;
+ rec.setTypeNameFormat(QNdefRecord::Mime);
+ rec.setType("image/jpeg");
+ rec.setPayload("Good image with invalid type");
+
+ QNdefMessage message;
+ message.push_back(textRec);
+ message.push_back(rec);
+
+ QTest::addRow("Type mismatch, no ordering, no match") << filter << message << false;
+
+ filter.setOrderMatch(true);
+ QTest::addRow("Type mismatch, with ordering, no match") << filter << message << false;
+ }
+
+ {
+ filter.setOrderMatch(false);
+
+ QNdefMessage message;
+ message.push_back(QNdefNfcUriRecord());
+ message.push_back(textRec);
+ message.push_back(textRec);
+ message.push_back(mimeRec);
+ message.push_back(emptyRec);
+ message.push_back(emptyRec);
+
+ QTest::addRow("Type not from filter in the beginning, no ordering, no match")
+ << filter << message << false;
+
+ filter.setOrderMatch(true);
+
+ QTest::addRow("Type not from filter in the beginning, with ordering, no match")
+ << filter << message << false;
+ }
+
+ {
+ filter.setOrderMatch(false);
+
+ QNdefMessage message;
+ message.push_back(textRec);
+ message.push_back(textRec);
+ message.push_back(mimeRec);
+ message.push_back(emptyRec);
+ message.push_back(QNdefNfcUriRecord());
+ message.push_back(emptyRec);
+
+ QTest::addRow("Type not from filter in the middle, no ordering, no match")
+ << filter << message << false;
+
+ filter.setOrderMatch(true);
+
+ QTest::addRow("Type not from filter in the middle, with ordering, no match")
+ << filter << message << false;
+ }
+
+ {
+ filter.setOrderMatch(false);
+
+ QNdefMessage message;
+ message.push_back(textRec);
+ message.push_back(textRec);
+ message.push_back(mimeRec);
+ message.push_back(emptyRec);
+ message.push_back(emptyRec);
+ message.push_back(QNdefNfcUriRecord());
+
+ QTest::addRow("Type not from filter in the end, no ordering, no match")
+ << filter << message << false;
+
+ filter.setOrderMatch(true);
+
+ QTest::addRow("Type not from filter in the end, with ordering, no match")
+ << filter << message << false;
+ }
+
+ QNdefFilter repeatedFilter;
+ // These 2 consecutive QNdefNfcTextRecord's are the same as
+ // repeatedFilter.appendRecord<QNdefNfcTextRecord>(0, 2);
+ repeatedFilter.appendRecord<QNdefNfcTextRecord>(0, 1);
+ repeatedFilter.appendRecord<QNdefNfcTextRecord>(0, 1);
+ repeatedFilter.appendRecord(QNdefRecord::Mime, "", 1, 1);
+ repeatedFilter.appendRecord<QNdefNfcTextRecord>(1, 1);
+
+ {
+ repeatedFilter.setOrderMatch(false);
+
+ QNdefMessage message;
+ message.push_back(textRec);
+ message.push_back(textRec);
+ message.push_back(mimeRec);
+
+ QTest::addRow("Filter with repeated type format, no ordering, match")
+ << repeatedFilter << message << true;
+
+ repeatedFilter.setOrderMatch(true);
+
+ QTest::addRow("Filter with repeated type format, with ordering, no match")
+ << repeatedFilter << message << false;
+ }
+
+ {
+ repeatedFilter.setOrderMatch(false);
+
+ QNdefMessage message;
+ message.push_back(textRec);
+ message.push_back(mimeRec);
+ message.push_back(textRec);
+
+ QTest::addRow("Filter with repeated type format 2, no ordering, match")
+ << repeatedFilter << message << true;
+
+ repeatedFilter.setOrderMatch(true);
+
+ QTest::addRow("Filter with repeated type format 2, with ordering, match")
+ << repeatedFilter << message << true;
+ }
+
+ QNdefFilter repeatedFilter2;
+ repeatedFilter2.appendRecord<QNdefNfcTextRecord>(0, 2);
+ repeatedFilter2.appendRecord<QNdefNfcTextRecord>(1, 1);
+ repeatedFilter2.appendRecord(QNdefRecord::Mime, "", 1, 1);
+
+ {
+ repeatedFilter2.setOrderMatch(false);
+
+ QNdefMessage message;
+ message.push_back(textRec);
+ message.push_back(mimeRec);
+
+ QTest::addRow("Filter with repeated type format 3, no ordering, match")
+ << repeatedFilter2 << message << true;
+
+ repeatedFilter2.setOrderMatch(true);
+
+ QTest::addRow("Filter with repeated type format 3, with ordering, match")
+ << repeatedFilter2 << message << true;
+ }
+
+ {
+ repeatedFilter2.setOrderMatch(false);
+
+ QNdefMessage message;
+ message.push_back(textRec);
+ message.push_back(textRec);
+ message.push_back(textRec);
+ message.push_back(textRec);
+ message.push_back(mimeRec);
+
+ QTest::addRow("Filter with repeated type format 4, no ordering, no match")
+ << repeatedFilter2 << message << false;
+
+ repeatedFilter2.setOrderMatch(true);
+
+ QTest::addRow("Filter with repeated type format 4, with ordering, no match")
+ << repeatedFilter2 << message << false;
+ }
+}
+
+QTEST_MAIN(tst_QNdefFilter)
+
+#include "tst_qndeffilter.moc"
diff --git a/tests/auto/qndefmessage/CMakeLists.txt b/tests/auto/qndefmessage/CMakeLists.txt
new file mode 100644
index 00000000..6ed6fc2c
--- /dev/null
+++ b/tests/auto/qndefmessage/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qndefmessage Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qndefmessage LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qndefmessage
+ SOURCES
+ tst_qndefmessage.cpp
+ LIBRARIES
+ Qt::Nfc
+)
diff --git a/tests/auto/qndefmessage/qndefmessage.pro b/tests/auto/qndefmessage/qndefmessage.pro
deleted file mode 100644
index c1309387..00000000
--- a/tests/auto/qndefmessage/qndefmessage.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-SOURCES += tst_qndefmessage.cpp
-TARGET = tst_qndefmessage
-CONFIG += testcase
-
-QT = core nfc testlib
diff --git a/tests/auto/qndefmessage/tst_qndefmessage.cpp b/tests/auto/qndefmessage/tst_qndefmessage.cpp
index eb9bb507..d31f3b68 100644
--- a/tests/auto/qndefmessage/tst_qndefmessage.cpp
+++ b/tests/auto/qndefmessage/tst_qndefmessage.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -46,9 +21,13 @@ public:
~tst_QNdefMessage();
private slots:
- void tst_parse_data();
- void tst_parse();
- void messageParsingFromByteArray();
+ void equality();
+ void equality_data();
+ void parseSingleRecordMessage_data();
+ void parseSingleRecordMessage();
+ void parseCorruptedMessage();
+ void parseCorruptedMessage_data();
+ void parseComplexMessage();
};
tst_QNdefMessage::tst_QNdefMessage()
@@ -59,7 +38,82 @@ tst_QNdefMessage::~tst_QNdefMessage()
{
}
-void tst_QNdefMessage::tst_parse_data()
+void tst_QNdefMessage::equality()
+{
+ QFETCH(QNdefMessage, lhs);
+ QFETCH(QNdefMessage, rhs);
+ QFETCH(bool, result);
+
+ QCOMPARE(lhs == rhs, result);
+ QCOMPARE(rhs == lhs, result);
+}
+
+void tst_QNdefMessage::equality_data()
+{
+ QTest::addColumn<QNdefMessage>("lhs");
+ QTest::addColumn<QNdefMessage>("rhs");
+ QTest::addColumn<bool>("result");
+
+ QTest::newRow("empty vs empty") << QNdefMessage() << QNdefMessage() << true;
+ {
+ QNdefRecord rec;
+ rec.setTypeNameFormat(QNdefRecord::Empty);
+
+ QNdefMessage message;
+ message.push_back(rec);
+
+ QTest::newRow("empty vs empty record") << QNdefMessage() << message << true;
+ }
+ {
+ QNdefMessage message;
+ message.push_back(QNdefNfcTextRecord());
+
+ QTest::newRow("empty vs non-empty record") << QNdefMessage() << message << false;
+ }
+ {
+ QNdefMessage lhs;
+ lhs.push_back(QNdefNfcTextRecord());
+
+ QNdefMessage rhs;
+ rhs.push_back(QNdefNfcUriRecord());
+
+ QTest::newRow("different records") << lhs << rhs << false;
+ }
+ {
+ QNdefMessage lhs;
+ lhs.push_back(QNdefNfcTextRecord());
+ lhs.push_back(QNdefNfcUriRecord());
+
+ QNdefMessage rhs;
+ rhs.push_back(QNdefNfcUriRecord());
+
+ QTest::newRow("different amount of records") << lhs << rhs << false;
+ }
+ {
+ QNdefMessage lhs;
+ lhs.push_back(QNdefNfcTextRecord());
+ lhs.push_back(QNdefNfcUriRecord());
+
+ QNdefMessage rhs;
+ rhs.push_back(QNdefNfcUriRecord());
+ rhs.push_back(QNdefNfcTextRecord());
+
+ QTest::newRow("same records, different order") << lhs << rhs << false;
+ }
+ {
+ QNdefMessage lhs;
+ lhs.push_back(QNdefNfcTextRecord());
+ lhs.push_back(QNdefNfcUriRecord());
+
+ QNdefMessage rhs;
+ rhs.push_back(QNdefNfcTextRecord());
+ rhs.push_back(QNdefNfcUriRecord());
+
+ QTest::newRow("same records, same order") << lhs << rhs << true;
+ }
+}
+
+void tst_QNdefMessage::parseSingleRecordMessage_data()
{
QTest::addColumn<QByteArray>("data");
QTest::addColumn<QNdefMessage>("message");
@@ -106,12 +160,12 @@ void tst_QNdefMessage::tst_parse_data()
QByteArray data;
data.append(char(0xcd)); // MB=1, ME=1, IL=1, TNF=5
- data.append(char(type.length())); // TYPE LENGTH
- data.append(char((payload.length() >> 24) & 0xff)); // PAYLOAD LENGTH 3
- data.append(char((payload.length() >> 16) & 0xff)); // PAYLOAD LENGTH 2
- data.append(char((payload.length() >> 8) & 0xff)); // PAYLOAD LENGTH 1
- data.append(char((payload.length() >> 0) & 0xff)); // PAYLOAD LENGTH 0
- data.append(char(id.length())); // ID LENGTH
+ data.append(char(type.size())); // TYPE LENGTH
+ data.append(char((payload.size() >> 24) & 0xff)); // PAYLOAD LENGTH 3
+ data.append(char((payload.size() >> 16) & 0xff)); // PAYLOAD LENGTH 2
+ data.append(char((payload.size() >> 8) & 0xff)); // PAYLOAD LENGTH 1
+ data.append(char((payload.size() >> 0) & 0xff)); // PAYLOAD LENGTH 0
+ data.append(char(id.size())); // ID LENGTH
data.append(type);
data.append(id);
data.append(payload);
@@ -134,14 +188,14 @@ void tst_QNdefMessage::tst_parse_data()
QByteArray data;
data.append(char(0xbd)); // MB=1, CF=1, SR=1, IL=1, TNF=5
- data.append(char(type.length())); // TYPE LENGTH
+ data.append(char(type.size())); // TYPE LENGTH
data.append(char(1)); // PAYLOAD LENGTH
- data.append(char(id.length())); // ID LENGTH
+ data.append(char(id.size())); // ID LENGTH
data.append(type); // TYPE
data.append(id); // ID
data.append(payload.at(0)); // PAYLOAD[0]
- for (int i = 1; i < payload.length() - 1; ++i) {
+ for (int i = 1; i < payload.size() - 1; ++i) {
data.append(char(0x36)); // CF=1, SR=1, TNF=6
data.append(char(0)); // TYPE LENGTH
data.append(char(1)); // PAYLOAD LENGTH
@@ -151,7 +205,7 @@ void tst_QNdefMessage::tst_parse_data()
data.append(char(0x56)); // ME=1, SR=1, TNF=6
data.append(char(0)); // TYPE LENGTH
data.append(char(1)); // PAYLOAD LENGTH
- data.append(payload.at(payload.length() - 1)); // PAYLOAD[length - 1]
+ data.append(payload.at(payload.size() - 1)); // PAYLOAD[length - 1]
QNdefRecord record;
record.setTypeNameFormat(QNdefRecord::Unknown);
@@ -177,11 +231,11 @@ void tst_QNdefMessage::tst_parse_data()
QByteArray data;
data.append(char(0xc1)); // MB=1, ME=1, IL=0, TNF=1
- data.append(char(type.length())); // TYPE LENGTH
- data.append(char((payload.length() >> 24) & 0xff)); // PAYLOAD LENGTH 3
- data.append(char((payload.length() >> 16) & 0xff)); // PAYLOAD LENGTH 2
- data.append(char((payload.length() >> 8) & 0xff)); // PAYLOAD LENGTH 1
- data.append(char((payload.length() >> 0) & 0xff)); // PAYLOAD LENGTH 0
+ data.append(char(type.size())); // TYPE LENGTH
+ data.append(char((payload.size() >> 24) & 0xff)); // PAYLOAD LENGTH 3
+ data.append(char((payload.size() >> 16) & 0xff)); // PAYLOAD LENGTH 2
+ data.append(char((payload.size() >> 8) & 0xff)); // PAYLOAD LENGTH 1
+ data.append(char((payload.size() >> 0) & 0xff)); // PAYLOAD LENGTH 0
data.append(type);
data.append(payload);
@@ -211,11 +265,11 @@ void tst_QNdefMessage::tst_parse_data()
QByteArray data;
data.append(char(0xc1)); // MB=1, ME=1, IL=0, TNF=1
- data.append(char(type.length())); // TYPE LENGTH
- data.append(char((payload.length() >> 24) & 0xff)); // PAYLOAD LENGTH 3
- data.append(char((payload.length() >> 16) & 0xff)); // PAYLOAD LENGTH 2
- data.append(char((payload.length() >> 8) & 0xff)); // PAYLOAD LENGTH 1
- data.append(char((payload.length() >> 0) & 0xff)); // PAYLOAD LENGTH 0
+ data.append(char(type.size())); // TYPE LENGTH
+ data.append(char((payload.size() >> 24) & 0xff)); // PAYLOAD LENGTH 3
+ data.append(char((payload.size() >> 16) & 0xff)); // PAYLOAD LENGTH 2
+ data.append(char((payload.size() >> 8) & 0xff)); // PAYLOAD LENGTH 1
+ data.append(char((payload.size() >> 0) & 0xff)); // PAYLOAD LENGTH 0
data.append(type);
data.append(payload);
@@ -246,11 +300,11 @@ void tst_QNdefMessage::tst_parse_data()
QByteArray data;
data.append(char(0xc1));
- data.append(char(type.length()));
- data.append(char((payload.length() >> 24) & 0xff)); // PAYLOAD LENGTH 3
- data.append(char((payload.length() >> 16) & 0xff)); // PAYLOAD LENGTH 2
- data.append(char((payload.length() >> 8) & 0xff)); // PAYLOAD LENGTH 1
- data.append(char((payload.length() >> 0) & 0xff)); // PAYLOAD LENGTH 0
+ data.append(char(type.size()));
+ data.append(char((payload.size() >> 24) & 0xff)); // PAYLOAD LENGTH 3
+ data.append(char((payload.size() >> 16) & 0xff)); // PAYLOAD LENGTH 2
+ data.append(char((payload.size() >> 8) & 0xff)); // PAYLOAD LENGTH 1
+ data.append(char((payload.size() >> 0) & 0xff)); // PAYLOAD LENGTH 0
data.append(type);
data.append(payload);
@@ -279,11 +333,11 @@ void tst_QNdefMessage::tst_parse_data()
QByteArray data;
data.append(char(0xc1));
- data.append(char(type.length()));
- data.append(char((payload.length() >> 24) & 0xff)); // PAYLOAD LENGTH 3
- data.append(char((payload.length() >> 16) & 0xff)); // PAYLOAD LENGTH 2
- data.append(char((payload.length() >> 8) & 0xff)); // PAYLOAD LENGTH 1
- data.append(char((payload.length() >> 0) & 0xff)); // PAYLOAD LENGTH 0
+ data.append(char(type.size()));
+ data.append(char((payload.size() >> 24) & 0xff)); // PAYLOAD LENGTH 3
+ data.append(char((payload.size() >> 16) & 0xff)); // PAYLOAD LENGTH 2
+ data.append(char((payload.size() >> 8) & 0xff)); // PAYLOAD LENGTH 1
+ data.append(char((payload.size() >> 0) & 0xff)); // PAYLOAD LENGTH 0
data.append(type);
data.append(payload);
@@ -312,11 +366,11 @@ void tst_QNdefMessage::tst_parse_data()
QByteArray data;
data.append(char(0xc1));
- data.append(char(type.length()));
- data.append(char((payload.length() >> 24) & 0xff)); // PAYLOAD LENGTH 3
- data.append(char((payload.length() >> 16) & 0xff)); // PAYLOAD LENGTH 2
- data.append(char((payload.length() >> 8) & 0xff)); // PAYLOAD LENGTH 1
- data.append(char((payload.length() >> 0) & 0xff)); // PAYLOAD LENGTH 0
+ data.append(char(type.size()));
+ data.append(char((payload.size() >> 24) & 0xff)); // PAYLOAD LENGTH 3
+ data.append(char((payload.size() >> 16) & 0xff)); // PAYLOAD LENGTH 2
+ data.append(char((payload.size() >> 8) & 0xff)); // PAYLOAD LENGTH 1
+ data.append(char((payload.size() >> 0) & 0xff)); // PAYLOAD LENGTH 0
data.append(type);
data.append(payload);
@@ -336,6 +390,46 @@ void tst_QNdefMessage::tst_parse_data()
QByteArray::fromHex(QByteArray("55052b31323334353637383930")));
}
+ // Chunk payload - the NFC-RTD URI split into 3 chunks
+ {
+ const QByteArray type("U");
+ const QByteArray id("test");
+ QByteArray payload1;
+ payload1.append(char(0x05));
+ payload1.append("+123");
+
+ const QByteArray payload2("456");
+ const QByteArray payload3("7890");
+
+ QByteArray data;
+ data.append(char(0xB9)); // MB=1, ME=0, CF=1, SR=1, IL=1, TNF=1 (NFC-RTD)
+ data.append(type.size());
+ data.append(payload1.size() & 0xff); // length fits into 1 byte
+ data.append(id.size());
+ data.append(type);
+ data.append(id);
+ data.append(payload1);
+ data.append(char(0x36)); // MB=0, ME=0, CF=1, SR=1, IL=0, TNF=6 (Unchanged)
+ data.append(char(0x00));
+ data.append(payload2.size());
+ data.append(payload2);
+ data.append(char(0x56)); // MB=0, ME=1, CF=0, SR=1, IL=0, TNF=6 (Unchanged)
+ data.append(char(0x00));
+ data.append(payload3.size());
+ data.append(payload3);
+
+ QNdefRecord record;
+ record.setTypeNameFormat(QNdefRecord::NfcRtd);
+ record.setType(type);
+ record.setId(id);
+ record.setPayload(QByteArray("\005+1234567890", 12));
+ QList<QNdefRecord> recordList;
+ recordList.append(record);
+ QTest::newRow("chunk payloads nfc-rtd uri tel:+1234567890")
+ << data << QNdefMessage(recordList)
+ << (QVariantList() << QUrl(QStringLiteral("tel:+1234567890")));
+ }
+
// Truncated message
{
QByteArray type("U");
@@ -348,22 +442,22 @@ void tst_QNdefMessage::tst_parse_data()
QTest::newRow("truncated 1") << data << QNdefMessage() << QVariantList();
- data.append(char(type.length())); // TYPE LENGTH
+ data.append(char(type.size())); // TYPE LENGTH
QTest::newRow("truncated 2") << data << QNdefMessage() << QVariantList();
- data.append(char((payload.length() >> 24) & 0xff)); // PAYLOAD LENGTH 3
+ data.append(char((payload.size() >> 24) & 0xff)); // PAYLOAD LENGTH 3
QTest::newRow("truncated 3") << data << QNdefMessage() << QVariantList();
- data.append(char((payload.length() >> 16) & 0xff)); // PAYLOAD LENGTH 2
+ data.append(char((payload.size() >> 16) & 0xff)); // PAYLOAD LENGTH 2
QTest::newRow("truncated 4") << data << QNdefMessage() << QVariantList();
- data.append(char((payload.length() >> 8) & 0xff)); // PAYLOAD LENGTH 1
+ data.append(char((payload.size() >> 8) & 0xff)); // PAYLOAD LENGTH 1
QTest::newRow("truncated 5") << data << QNdefMessage() << QVariantList();
- data.append(char((payload.length() >> 0) & 0xff)); // PAYLOAD LENGTH 0
+ data.append(char((payload.size() >> 0) & 0xff)); // PAYLOAD LENGTH 0
QTest::newRow("truncated 6") << data << QNdefMessage() << QVariantList();
- data.append(char(id.length())); // ID LENGTH
+ data.append(char(id.size())); // ID LENGTH
QTest::newRow("truncated 7") << data << QNdefMessage() << QVariantList();
data.append(type);
@@ -378,7 +472,7 @@ void tst_QNdefMessage::tst_parse_data()
}
}
-void tst_QNdefMessage::tst_parse()
+void tst_QNdefMessage::parseSingleRecordMessage()
{
QFETCH(QByteArray, data);
QFETCH(QNdefMessage, message);
@@ -397,7 +491,7 @@ void tst_QNdefMessage::tst_parse()
QVERIFY(message == reparsedMessage);
QVERIFY(reparsedMessage == message);
- for (int i = 0; i < message.count(); ++i) {
+ for (qsizetype i = 0; i < message.size(); ++i) {
const QNdefRecord &record = message.at(i);
const QNdefRecord &parsedRecord = parsedMessage.at(i);
@@ -414,7 +508,7 @@ void tst_QNdefMessage::tst_parse()
QCOMPARE(textRecord.text(), parsedTextRecord.text());
QCOMPARE(textRecord.locale(), parsedTextRecord.locale());
- if (expectedData.count() == 2) {
+ if (expectedData.size() == 2) {
QCOMPARE(parsedTextRecord.text(), expectedData.at(0).toString());
QCOMPARE(parsedTextRecord.locale(), expectedData.at(1).toString());
}
@@ -424,7 +518,7 @@ void tst_QNdefMessage::tst_parse()
QCOMPARE(uriRecord.uri(), parsedUriRecord.uri());
- if (expectedData.count() == 1)
+ if (expectedData.size() == 1)
QCOMPARE(parsedUriRecord.uri(), expectedData.at(0).toUrl());
} else if (record.isRecordType<QNdefRecord>()) {
QVERIFY(record.isEmpty());
@@ -432,7 +526,175 @@ void tst_QNdefMessage::tst_parse()
}
}
-void tst_QNdefMessage::messageParsingFromByteArray()
+void tst_QNdefMessage::parseCorruptedMessage()
+{
+ // This test is needed to check that all the potential errors in the
+ // input data are handled correctly.
+
+ QFETCH(QByteArray, data);
+ QFETCH(QByteArray, warningMessage);
+
+ if (!warningMessage.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, warningMessage.constData());
+
+ QNdefMessage parsedMessage = QNdefMessage::fromByteArray(data);
+ // corrupted data always results in an empty message
+ QVERIFY(parsedMessage.isEmpty());
+}
+
+void tst_QNdefMessage::parseCorruptedMessage_data()
+{
+ QTest::addColumn<QByteArray>("data");
+ QTest::addColumn<QByteArray>("warningMessage");
+
+ {
+ QByteArray data;
+ data.append(char(0x50)); // MB=0, ME=1, SR=1
+ data.append(char(0)); // TYPE LENGTH
+ data.append(char(0)); // PAYLOAD LENGTH
+
+ const QByteArray warningMsg = "Haven't got message begin yet";
+
+ QTest::newRow("No message begin") << data << warningMsg;
+ }
+ {
+ QByteArray data;
+ data.append(char(0x90)); // MB=1, ME=0, SR=1
+ data.append(char(0)); // TYPE LENGTH
+ data.append(char(0)); // PAYLOAD LENGTH
+
+ const QByteArray warningMsg = "Malformed NDEF Message, missing begin or end";
+
+ QTest::newRow("No message end") << data << warningMsg;
+ }
+ {
+ QByteArray data;
+ data.append(char(0x90)); // MB=1, ME=0, SR=1
+ data.append(char(0)); // TYPE LENGTH
+ data.append(char(0)); // PAYLOAD LENGTH
+ data.append(char(0xd0)); // MB=1, ME=1, SR=1
+ data.append(char(0)); // TYPE LENGTH
+ data.append(char(0)); // PAYLOAD LENGTH
+
+ const QByteArray warningMsg = "Got message begin but already parsed some records";
+
+ QTest::newRow("Multiple message begin") << data << warningMsg;
+ }
+ {
+ QByteArray data;
+ data.append(char(0xB1)); // MB=1, ME=0, CF=1, SR=1, IL=0, TNF=1 (NFC-RTD)
+ data.append(char(0x01)); // type length
+ data.append(char(0x01)); // payload length
+ data.append('U'); // type
+ data.append('a'); // payload
+ data.append(char(0x76)); // MB=0, ME=1 (incorrect), CF=1, SR=1, IL=0, TNF=6 (Unchanged)
+ data.append(char(0x00)); // type length
+ data.append(char(0x01)); // payload length
+ data.append('b'); // payload
+ data.append(char(0x56)); // MB=0, ME=1, CF=0, SR=1, IL=0, TNF=6 (Unchanged)
+ data.append(char(0x00)); // type length
+ data.append(char(0x01)); // payload length
+ data.append('c'); // payload
+
+ const QByteArray warningMsg = "Got message end but already parsed final record";
+
+ QTest::newRow("Multiple message end") << data << warningMsg;
+ }
+ {
+ QByteArray data;
+ data.append(char(0xB1)); // MB=1, ME=0, CF=1, SR=1, IL=0, TNF=1 (NFC-RTD)
+ data.append(char(0x01)); // type length
+ data.append(char(0x01)); // payload length
+ data.append('U'); // type
+ data.append('a'); // payload
+ data.append(char(0x36)); // MB=0, ME=0, CF=1, SR=1, IL=0, TNF=6 (Unchanged)
+ data.append(char(0x00)); // type length
+ data.append(char(0x01)); // payload length
+ data.append('b'); // payload
+ data.append(char(0x51)); // MB=0, ME=1, CF=0, SR=1, IL=0, TNF=1 (NFC-RTD - incorrect)
+ data.append(char(0x00)); // type length
+ data.append(char(0x01)); // payload length
+ data.append('c'); // payload
+
+ const QByteArray warningMsg = "Partial chunk not empty, but TNF not 0x06 as expected";
+
+ QTest::newRow("Incorrect TNF in chunk") << data << warningMsg;
+ }
+ {
+ QByteArray data;
+ data.append(char(0xB1)); // MB=1, ME=0, CF=1, SR=1, IL=0, TNF=1 (NFC-RTD)
+ data.append(char(0x01)); // type length
+ data.append(char(0x01)); // payload length
+ data.append('U'); // type
+ data.append('a'); // payload
+ data.append(char(0x36)); // MB=0, ME=0, CF=1, SR=1, IL=0, TNF=6 (Unchanged)
+ data.append(char(0x01)); // type length (incorrect)
+ data.append(char(0x01)); // payload length
+ data.append('U'); // type (incorrect)
+ data.append('b'); // payload
+ data.append(char(0x56)); // MB=0, ME=1, CF=0, SR=1, IL=0, TNF=6 (Unchanged)
+ data.append(char(0x00)); // type length
+ data.append(char(0x01)); // payload length
+ data.append('c'); // payload
+
+ const QByteArray warningMsg = "Invalid chunked data, TYPE_LENGTH != 0";
+
+ QTest::newRow("Incorrect TYPE_LENGTH in chunk") << data << warningMsg;
+ }
+ {
+ QByteArray data;
+ data.append(char(0xB1)); // MB=1, ME=0, CF=1, SR=1, IL=0, TNF=1 (NFC-RTD)
+ data.append(char(0x01)); // type length
+ data.append(char(0x01)); // payload length
+ data.append('U'); // type
+ data.append('a'); // payload
+ data.append(char(0x3E)); // MB=0, ME=0, CF=1, SR=1, IL=1 (incorrect), TNF=6 (Unchanged)
+ data.append(char(0x00)); // type length
+ data.append(char(0x01)); // payload length
+ data.append(char(0x01)); // id length (incorrect)
+ data.append('i'); // id (incorrect)
+ data.append('b'); // payload
+ data.append(char(0x56)); // MB=0, ME=1, CF=0, SR=1, IL=0, TNF=6 (Unchanged)
+ data.append(char(0x00)); // type length
+ data.append(char(0x01)); // payload length
+ data.append('c'); // payload
+
+ const QByteArray warningMsg = "Invalid chunked data, IL != 0";
+
+ QTest::newRow("Incorrect IL in chunk") << data << warningMsg;
+ }
+ {
+ QByteArray data;
+ data.append(char(0xC8)); // MB=1, ME=1, CF=0, SR=0, IL=1, TNF=0
+ data.append(char(0)); // type legnth
+ data.append(char(0)); // payload length (incorrect, 4 bytes expected)
+
+ const QByteArray warningMsg = "Unexpected end of message";
+
+ QTest::newRow("Invalid header length") << data << warningMsg;
+ }
+ {
+ QByteArray data;
+ data.append(char(0xC1)); // MB=1, ME=1, CF=0, SR=0, IL=0, TNF=1
+ data.append(char(0x01)); // type legnth
+ data.append(char(0xFF)); // payload length 3
+ data.append(char(0xFF)); // payload length 2
+ data.append(char(0xFF)); // payload length 1
+ data.append(char(0xFF)); // payload length 0
+ data.append('U'); // type
+ data.append('a'); // payload
+
+ // In case of 32 bit the code path will be different from 64 bit, so
+ // the warning message is also different.
+ const QByteArray warningMsg = (sizeof(qsizetype) <= sizeof(quint32))
+ ? "Payload can't fit into QByteArray"
+ : "Unexpected end of message";
+
+ QTest::newRow("Max payload length") << data << warningMsg;
+ }
+}
+
+void tst_QNdefMessage::parseComplexMessage()
{
const QByteArray reference("1234567890");
QNdefMessage message;
diff --git a/tests/auto/qndefnfcsmartposterrecord/CMakeLists.txt b/tests/auto/qndefnfcsmartposterrecord/CMakeLists.txt
new file mode 100644
index 00000000..6776fa36
--- /dev/null
+++ b/tests/auto/qndefnfcsmartposterrecord/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qndefnfcsmartposterrecord Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qndefnfcsmartposterrecord LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qndefnfcsmartposterrecord
+ SOURCES
+ tst_qndefnfcsmartposterrecord.cpp
+ LIBRARIES
+ Qt::Nfc
+)
diff --git a/tests/auto/qndefnfcsmartposterrecord/qndefnfcsmartposterrecord.pro b/tests/auto/qndefnfcsmartposterrecord/qndefnfcsmartposterrecord.pro
deleted file mode 100644
index 52766cfd..00000000
--- a/tests/auto/qndefnfcsmartposterrecord/qndefnfcsmartposterrecord.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-SOURCES += tst_qndefnfcsmartposterrecord.cpp
-TARGET = tst_qndefnfcsmartposterrecord
-CONFIG += testcase
-
-QT = core nfc testlib
diff --git a/tests/auto/qndefnfcsmartposterrecord/tst_qndefnfcsmartposterrecord.cpp b/tests/auto/qndefnfcsmartposterrecord/tst_qndefnfcsmartposterrecord.cpp
index fdc1abc2..c5c5d88f 100644
--- a/tests/auto/qndefnfcsmartposterrecord/tst_qndefnfcsmartposterrecord.cpp
+++ b/tests/auto/qndefnfcsmartposterrecord/tst_qndefnfcsmartposterrecord.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Research In Motion
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Research In Motion
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -136,16 +111,12 @@ QString tst_QNdefNfcSmartPosterRecord::getTitle(const QString& locale)
void tst_QNdefNfcSmartPosterRecord::checkLocale(const QNdefNfcSmartPosterRecord& record, const QStringList& localeList)
{
- QList<QString> locales = _textRecords.keys();
-
- for (int i = 0; i < locales.size(); i++) {
- if (localeList.contains(locales[i])) {
- QVERIFY(record.hasTitle(locales[i]));
- }
-
- else {
- QVERIFY(!record.hasTitle(locales[i]));
- }
+ for (auto it = _textRecords.cbegin(), end = _textRecords.cend(); it != end; ++it) {
+ const QString &locale = it.key();
+ if (localeList.contains(locale))
+ QVERIFY(record.hasTitle(locale));
+ else
+ QVERIFY(!record.hasTitle(locale));
}
if (localeList.empty()) {
@@ -187,7 +158,7 @@ void tst_QNdefNfcSmartPosterRecord::tst_emptyRecord()
quint32 size = 0;
QCOMPARE(record.size(), size);
- QCOMPARE(record.typeInfo(), QByteArray());
+ QCOMPARE(record.typeInfo(), QString());
QVERIFY(record.isRecordType<QNdefNfcSmartPosterRecord>());
QVERIFY(!record.isRecordType<QNdefNfcTextRecord>());
@@ -229,6 +200,7 @@ void tst_QNdefNfcSmartPosterRecord::tst_titles()
QVERIFY(record.addTitle(deRecord));
QCOMPARE(record.titleCount(), 2);
+ QCOMPARE(record.titleRecord(1), deRecord);
{
QStringList locales;
locales << "en" << "de";
@@ -240,6 +212,7 @@ void tst_QNdefNfcSmartPosterRecord::tst_titles()
QVERIFY(record.addTitle(frRecord));
QCOMPARE(record.titleCount(), 3);
+ QCOMPARE(record.titleRecord(2), frRecord);
{
QStringList locales;
locales << "en" << "de" << "fr";
@@ -324,6 +297,7 @@ void tst_QNdefNfcSmartPosterRecord::tst_uri()
void tst_QNdefNfcSmartPosterRecord::tst_action()
{
QNdefNfcSmartPosterRecord record;
+ QVERIFY(!record.hasAction());
record.setAction(QNdefNfcSmartPosterRecord::DoAction);
QVERIFY(record.hasAction());
@@ -333,6 +307,10 @@ void tst_QNdefNfcSmartPosterRecord::tst_action()
QVERIFY(record.hasAction());
QCOMPARE(record.action(), QNdefNfcSmartPosterRecord::SaveAction);
+ record.setAction(QNdefNfcSmartPosterRecord::EditAction);
+ QVERIFY(record.hasAction());
+ QCOMPARE(record.action(), QNdefNfcSmartPosterRecord::EditAction);
+
record.setAction(QNdefNfcSmartPosterRecord::UnspecifiedAction);
QVERIFY(record.hasAction());
QCOMPARE(record.action(), QNdefNfcSmartPosterRecord::UnspecifiedAction);
@@ -341,6 +319,7 @@ void tst_QNdefNfcSmartPosterRecord::tst_action()
void tst_QNdefNfcSmartPosterRecord::tst_icon()
{
QNdefNfcSmartPosterRecord record;
+ QVERIFY(!record.hasIcon());
QNdefNfcIconRecord icon;
record.addIcon(icon);
@@ -366,6 +345,8 @@ void tst_QNdefNfcSmartPosterRecord::tst_icon()
QCOMPARE(record.iconCount(), 1);
QCOMPARE(record.icon(), QByteArray("icondata"));
QCOMPARE(record.icon(mimeType), QByteArray("icondata"));
+ // invalid type => empty data
+ QCOMPARE(record.icon(QByteArray("mime")), QByteArray());
QNdefNfcIconRecord icon2;
icon2.setData("iconrecorddata");
@@ -387,36 +368,49 @@ void tst_QNdefNfcSmartPosterRecord::tst_icon()
QCOMPARE(iconRecords[1], icon2);
QVERIFY(record.removeIcon(mimeType));
+ QVERIFY(!record.removeIcon(QByteArray("mime")));
QCOMPARE(record.iconCount(), 1);
iconRecords = record.iconRecords();
QCOMPARE(iconRecords.size(), 1);
QCOMPARE(iconRecords[0], icon2);
+ QVERIFY(record.removeIcon(icon2));
+ QVERIFY(!record.removeIcon(icon3)); // already removed
+ QCOMPARE(record.iconCount(), 0);
+
QList<QNdefNfcIconRecord> iconList;
QNdefNfcIconRecord testIcon;
testIcon.setData("testicondata");
testIcon.setType("test/data");
- iconList << testIcon;
+ iconList << testIcon << icon2;
record.setIcons(iconList);
- QCOMPARE(record.iconCount(), 1);
+ QCOMPARE(record.iconCount(), 2);
iconRecords = record.iconRecords();
- QCOMPARE(iconRecords.size(), 1);
+ QCOMPARE(iconRecords.size(), 2);
QCOMPARE(iconRecords[0], testIcon);
+ QCOMPARE(iconRecords[1], icon2);
}
void tst_QNdefNfcSmartPosterRecord::tst_size()
{
QNdefNfcSmartPosterRecord record;
+ QVERIFY(!record.hasSize());
+ QCOMPARE(record.size(), 0U);
quint32 size = 1024;
record.setSize(size);
QCOMPARE(record.size(), size);
QVERIFY(record.hasSize());
+ size = 0x12345678; // check that all bytes are stored correctly
+ record.setSize(size);
+ QCOMPARE(record.size(), size);
+ QVERIFY(record.hasSize());
+
size = 0;
record.setSize(size);
QCOMPARE(record.size(), size);
@@ -426,8 +420,10 @@ void tst_QNdefNfcSmartPosterRecord::tst_size()
void tst_QNdefNfcSmartPosterRecord::tst_typeInfo()
{
QNdefNfcSmartPosterRecord record;
+ QVERIFY(!record.hasTypeInfo());
+ QVERIFY(record.typeInfo().isEmpty());
- QByteArray typeInfo("typeinfo");
+ QString typeInfo("typeinfo");
record.setTypeInfo(typeInfo);
QCOMPARE(record.typeInfo(), typeInfo);
QVERIFY(record.hasTypeInfo());
@@ -436,6 +432,11 @@ void tst_QNdefNfcSmartPosterRecord::tst_typeInfo()
record.setTypeInfo(typeInfo);
QCOMPARE(record.typeInfo(), typeInfo);
QVERIFY(record.hasTypeInfo());
+
+ typeInfo = QString();
+ record.setTypeInfo(typeInfo);
+ QCOMPARE(record.typeInfo(), typeInfo);
+ QVERIFY(record.hasTypeInfo());
}
void tst_QNdefNfcSmartPosterRecord::tst_construct()
@@ -480,11 +481,11 @@ void tst_QNdefNfcSmartPosterRecord::tst_construct()
QVERIFY(iconRecords.value(1).data().isEmpty());
QVERIFY(sprecord.hasSize());
- quint32 size = 1024;
+ const quint32 size = 1024;
QCOMPARE(sprecord.size(), size);
QVERIFY(sprecord.hasTypeInfo());
- QCOMPARE(sprecord.typeInfo(), QByteArray("text/html"));
+ QCOMPARE(sprecord.typeInfo(), QString("text/html"));
QVERIFY(record == sprecord);
QVERIFY(!(record != sprecord));
@@ -531,7 +532,7 @@ void tst_QNdefNfcSmartPosterRecord::tst_downcast()
QByteArray spPayload = sprecord.payload();
// Check length is longer on the base
- QVERIFY(basePayload.length() > record.payload().length());
+ QVERIFY(basePayload.size() > record.payload().size());
// Check the payloads are the same
QCOMPARE(basePayload, spPayload);
diff --git a/tests/auto/qndefrecord/CMakeLists.txt b/tests/auto/qndefrecord/CMakeLists.txt
new file mode 100644
index 00000000..74b5bed2
--- /dev/null
+++ b/tests/auto/qndefrecord/CMakeLists.txt
@@ -0,0 +1,19 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qndefrecord Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qndefrecord LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qndefrecord
+ SOURCES
+ tst_qndefrecord.cpp
+ LIBRARIES
+ Qt::Nfc
+)
diff --git a/tests/auto/qndefrecord/qndefrecord.pro b/tests/auto/qndefrecord/qndefrecord.pro
deleted file mode 100644
index e87f8b62..00000000
--- a/tests/auto/qndefrecord/qndefrecord.pro
+++ /dev/null
@@ -1,5 +0,0 @@
-SOURCES += tst_qndefrecord.cpp
-TARGET = tst_qndefrecord
-CONFIG += testcase
-
-QT = core nfc testlib
diff --git a/tests/auto/qndefrecord/tst_qndefrecord.cpp b/tests/auto/qndefrecord/tst_qndefrecord.cpp
index 26e993b2..d6671296 100644
--- a/tests/auto/qndefrecord/tst_qndefrecord.cpp
+++ b/tests/auto/qndefrecord/tst_qndefrecord.cpp
@@ -1,37 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <qndefrecord.h>
#include <qndefnfctextrecord.h>
#include <qndefnfcurirecord.h>
-#include <qqmlndefrecord.h>
QT_USE_NAMESPACE
@@ -47,6 +21,9 @@ public:
private slots:
void tst_record();
+ void tst_comparison();
+ void tst_comparison_data();
+ void tst_isRecordType();
void tst_textRecord_data();
void tst_textRecord();
@@ -54,10 +31,8 @@ private slots:
void tst_uriRecord_data();
void tst_uriRecord();
- void tst_declarative_record_data();
- void tst_declarative_record();
-
- void tst_declarativeChangedSignals();
+ void tst_ndefRecord_data();
+ void tst_ndefRecord();
};
tst_QNdefRecord::tst_QNdefRecord()
@@ -85,11 +60,6 @@ void tst_QNdefRecord::tst_record()
QCOMPARE(record, QNdefRecord());
QVERIFY(!(record != QNdefRecord()));
-
- QQmlNdefRecord declRecord;
- QCOMPARE(declRecord.record(), record);
- QCOMPARE(declRecord.type(), QString());
- QCOMPARE(declRecord.typeNameFormat(), QQmlNdefRecord::Empty);
}
// test type name format
@@ -179,22 +149,113 @@ void tst_QNdefRecord::tst_record()
QVERIFY(record != QNdefRecord());
}
- // test comparison
+ // test clear
{
QNdefRecord record;
- record.setTypeNameFormat(QNdefRecord::ExternalRtd);
- record.setType("qt-project.org:test-rtd");
- record.setId("test id");
- record.setPayload("test payload");
+ record.setTypeNameFormat(QNdefRecord::NfcRtd);
+ record.setId("id");
+ record.setType("type");
+ record.setPayload("Some random data");
+
+ record.clear();
+ QCOMPARE(record.typeNameFormat(), QNdefRecord::Empty);
+ QVERIFY(record.id().isEmpty());
+ QVERIFY(record.type().isEmpty());
+ QVERIFY(record.payload().isEmpty());
+ QVERIFY(record.isEmpty());
+ }
+}
+
+void tst_QNdefRecord::tst_comparison()
+{
+ QFETCH(QNdefRecord, lhs);
+ QFETCH(QNdefRecord, rhs);
+ QFETCH(bool, result);
+
+ QCOMPARE(lhs == rhs, result);
+ QCOMPARE(lhs != rhs, !result);
+
+ QCOMPARE(rhs == lhs, result);
+ QCOMPARE(rhs != lhs, !result);
+}
+
+void tst_QNdefRecord::tst_comparison_data()
+{
+ QTest::addColumn<QNdefRecord>("lhs");
+ QTest::addColumn<QNdefRecord>("rhs");
+ QTest::addColumn<bool>("result");
+
+ QTest::newRow("default-constructed records") << QNdefRecord() << QNdefRecord() << true;
+ {
+ QNdefRecord rec;
+ rec.setTypeNameFormat(QNdefRecord::Empty);
+
+ QTest::newRow("default-constructed vs empty") << QNdefRecord() << rec << false;
+ }
+
+ QNdefRecord record;
+ record.setTypeNameFormat(QNdefRecord::NfcRtd);
+ record.setType("T");
+ record.setId("text-record");
+ record.setPayload("Some random text");
+
+ {
+ QNdefRecord lhs = record;
+ QNdefRecord rhs = record;
+ rhs.setTypeNameFormat(QNdefRecord::ExternalRtd);
+
+ QTest::newRow("typeNameFormat mismatch") << lhs << rhs << false;
+ }
+ {
+ QNdefRecord lhs = record;
+ QNdefRecord rhs = record;
+ rhs.setType("t");
+
+ QTest::newRow("type mismatch") << lhs << rhs << false;
+ }
+ {
+ QNdefRecord lhs = record;
+ QNdefRecord rhs = record;
+ rhs.setId("random id");
- QNdefRecord other;
- other.setTypeNameFormat(QNdefRecord::ExternalRtd);
- other.setType("qt-project.org:test-other-rtd");
- other.setId("test other id");
- other.setPayload("test other payload");
+ QTest::newRow("id mismatch") << lhs << rhs << false;
+ }
+ {
+ QNdefRecord lhs = record;
+ QNdefRecord rhs = record;
+ rhs.setPayload("another random text");
- QVERIFY(record != other);
+ QTest::newRow("payload mismatch") << lhs << rhs << false;
}
+ {
+ QNdefRecord lhs = record;
+ QNdefRecord rhs = record;
+
+ QTest::newRow("same records") << lhs << rhs << true;
+ }
+}
+
+class PngNdefRecord : public QNdefRecord
+{
+public:
+ PngNdefRecord() : QNdefRecord(QNdefRecord::Mime, "image/png") { }
+};
+
+class JpegNdefRecord : public QNdefRecord
+{
+public:
+ JpegNdefRecord() : QNdefRecord(QNdefRecord::Mime, "image/jpeg") { }
+};
+
+void tst_QNdefRecord::tst_isRecordType()
+{
+ QNdefRecord rec;
+ rec.setTypeNameFormat(QNdefRecord::Mime);
+ rec.setType("image/png");
+
+ QVERIFY(!rec.isRecordType<QNdefRecord>());
+ QVERIFY(!rec.isRecordType<JpegNdefRecord>());
+ QVERIFY(rec.isRecordType<PngNdefRecord>());
}
void tst_QNdefRecord::tst_textRecord_data()
@@ -239,14 +300,11 @@ void tst_QNdefRecord::tst_textRecord()
record.setText(text);
record.setEncoding(utf8 ? QNdefNfcTextRecord::Utf8 : QNdefNfcTextRecord::Utf16);
+ QCOMPARE(record.typeNameFormat(), QNdefRecord::NfcRtd);
+ QCOMPARE(record.type(), QByteArray("T"));
QCOMPARE(record.payload(), payload);
QVERIFY(record != QNdefRecord());
-
- QQmlNdefRecord declRecord(record);
- QCOMPARE(declRecord.record(), QNdefRecord(record));
- QCOMPARE(declRecord.type(), QString("T"));
- QCOMPARE(declRecord.typeNameFormat(), QQmlNdefRecord::NfcRtd);
}
// test getters
@@ -308,14 +366,11 @@ void tst_QNdefRecord::tst_uriRecord()
QNdefNfcUriRecord record;
record.setUri(QUrl(url));
+ QCOMPARE(record.typeNameFormat(), QNdefRecord::NfcRtd);
+ QCOMPARE(record.type(), QByteArray("U"));
QCOMPARE(record.payload(), payload);
QVERIFY(record != QNdefRecord());
-
- QQmlNdefRecord declRecord(record);
- QCOMPARE(declRecord.record(), QNdefRecord(record));
- QCOMPARE(declRecord.type(), QString("U"));
- QCOMPARE(declRecord.typeNameFormat(), QQmlNdefRecord::NfcRtd);
}
// test getters
@@ -347,7 +402,7 @@ void tst_QNdefRecord::tst_uriRecord()
}
}
-void tst_QNdefRecord::tst_declarative_record_data()
+void tst_QNdefRecord::tst_ndefRecord_data()
{
QTest::addColumn<QNdefRecord::TypeNameFormat>("typeNameFormat");
QTest::addColumn<QByteArray>("type");
@@ -359,9 +414,10 @@ void tst_QNdefRecord::tst_declarative_record_data()
QTest::newRow("Unknown") << QNdefRecord::Unknown << QByteArray("BLAHfoo");
QTest::newRow("Mime") << QNdefRecord::Mime << QByteArray("foobar");
QTest::newRow("ExternalRtd") << QNdefRecord::ExternalRtd << QByteArray("");
+ QTest::newRow("Uri") << QNdefRecord::Uri << QByteArray("example.com/uri");
}
-void tst_QNdefRecord::tst_declarative_record()
+void tst_QNdefRecord::tst_ndefRecord()
{
QFETCH(QNdefRecord::TypeNameFormat, typeNameFormat);
QFETCH(QByteArray, type);
@@ -372,101 +428,9 @@ void tst_QNdefRecord::tst_declarative_record()
record.setType(type);
QCOMPARE(record.typeNameFormat(), typeNameFormat);
QCOMPARE(record.type(), type);
-
- QQmlNdefRecord declRecord(record);
- QCOMPARE(declRecord.record(), record);
- QCOMPARE(declRecord.record().typeNameFormat(), typeNameFormat);
- QCOMPARE(declRecord.record().type(), type);
- QCOMPARE(declRecord.type(), QString(type));
- QCOMPARE(declRecord.typeNameFormat(), static_cast<QQmlNdefRecord::TypeNameFormat>(typeNameFormat));
-
- QQmlNdefRecord declRecord2;
- declRecord2.setRecord(record);
- QCOMPARE(declRecord2.record(), record);
- QCOMPARE(declRecord2.record().typeNameFormat(), typeNameFormat);
- QCOMPARE(declRecord2.record().type(), type);
- QCOMPARE(declRecord2.type(), QString(type));
- QCOMPARE(declRecord2.typeNameFormat(), static_cast<QQmlNdefRecord::TypeNameFormat>(typeNameFormat));
-
- QQmlNdefRecord declRecord3;
- declRecord3.setTypeNameFormat((QQmlNdefRecord::TypeNameFormat)typeNameFormat);
- declRecord3.setType(type);
- QCOMPARE(declRecord3.type(), QString(type));
- QCOMPARE(declRecord3.record().typeNameFormat(), typeNameFormat);
- QCOMPARE(declRecord3.record().type(), type);
- QCOMPARE(declRecord3.typeNameFormat(), static_cast<QQmlNdefRecord::TypeNameFormat>(typeNameFormat));
}
}
-void tst_QNdefRecord::tst_declarativeChangedSignals()
-{
- QQmlNdefRecord record;
- QSignalSpy typeSpy(&record, SIGNAL(typeChanged()));
- QSignalSpy tnfSpy(&record, SIGNAL(typeNameFormatChanged()));
- QSignalSpy recordSpy(&record, SIGNAL(recordChanged()));
-
- QCOMPARE(typeSpy.count(), 0);
- QCOMPARE(recordSpy.count(), 0);
-
- record.setType("U");
- record.setTypeNameFormat(QQmlNdefRecord::NfcRtd);
- QCOMPARE(typeSpy.count(), 1);
- QCOMPARE(tnfSpy.count(), 1);
- QCOMPARE(recordSpy.count(), 0);
- QCOMPARE(record.type(), QString("U"));
- QCOMPARE(record.record().type(), QByteArray("U"));
- QCOMPARE(record.record().typeNameFormat(), QNdefRecord::NfcRtd);
- QCOMPARE(record.typeNameFormat(), QQmlNdefRecord::NfcRtd);
-
- record.setType("U"); //same value, no signal
- QCOMPARE(typeSpy.count(), 1);
- QCOMPARE(tnfSpy.count(), 1);
- QCOMPARE(recordSpy.count(), 0);
- QCOMPARE(record.type(), QString("U"));
- QCOMPARE(record.record().type(), QByteArray("U"));
- QCOMPARE(record.record().typeNameFormat(), QNdefRecord::NfcRtd);
- QCOMPARE(record.typeNameFormat(), QQmlNdefRecord::NfcRtd);
-
- record.setType("blah");
- record.setType("blah2");
- record.setTypeNameFormat(QQmlNdefRecord::ExternalRtd);
- QCOMPARE(typeSpy.count(), 3);
- QCOMPARE(tnfSpy.count(), 2);
- QCOMPARE(recordSpy.count(), 0);
- QCOMPARE(record.type(), QString("blah2"));
- QCOMPARE(record.record().type(), QByteArray("blah2"));
- QCOMPARE(record.record().typeNameFormat(), QNdefRecord::ExternalRtd);
- QCOMPARE(record.typeNameFormat(), QQmlNdefRecord::ExternalRtd);
-
- record.setType("Rubbish");
- QCOMPARE(typeSpy.count(), 4);
- QCOMPARE(tnfSpy.count(), 2);
- QCOMPARE(recordSpy.count(), 0);
- QCOMPARE(record.type(), QString("Rubbish"));
- QCOMPARE(record.record().type(), QByteArray("Rubbish"));
- QCOMPARE(record.record().typeNameFormat(), QNdefRecord::ExternalRtd);
- QCOMPARE(record.typeNameFormat(), QQmlNdefRecord::ExternalRtd);
-
- record.setType("QQQQ");
- record.setTypeNameFormat(QQmlNdefRecord::Mime);
- QCOMPARE(typeSpy.count(), 5);
- QCOMPARE(tnfSpy.count(), 3);
- QCOMPARE(recordSpy.count(), 0);
- QCOMPARE(record.type(), QString("QQQQ"));
- QCOMPARE(record.record().type(), QByteArray("QQQQ"));
- QCOMPARE(record.record().typeNameFormat(), QNdefRecord::Mime);
- QCOMPARE(record.typeNameFormat(), QQmlNdefRecord::Mime);
-
- record.setRecord(QNdefRecord());
- QCOMPARE(typeSpy.count(), 5); //setting record -> no recordChanged signal
- QCOMPARE(tnfSpy.count(), 3);
- QCOMPARE(recordSpy.count(), 1);
- QCOMPARE(record.type(), QString(""));
- QCOMPARE(record.record().type(), QByteArray());
- QCOMPARE(record.record().typeNameFormat(), QNdefRecord::Empty);
- QCOMPARE(record.typeNameFormat(), QQmlNdefRecord::Empty);
-}
-
QTEST_MAIN(tst_QNdefRecord)
#include "tst_qndefrecord.moc"
diff --git a/tests/auto/qnearfieldmanager/CMakeLists.txt b/tests/auto/qnearfieldmanager/CMakeLists.txt
new file mode 100644
index 00000000..9fa74032
--- /dev/null
+++ b/tests/auto/qnearfieldmanager/CMakeLists.txt
@@ -0,0 +1,49 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qnearfieldmanager LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+if (NOT QT_FEATURE_private_tests)
+ return()
+endif()
+
+#####################################################################
+## tst_qnearfieldmanager Test:
+#####################################################################
+
+# Collect test data
+list(APPEND test_data "../nfcdata/Qt Labs Website Tag Type1.nfc")
+list(APPEND test_data "../nfcdata/Qt Website Tag Type1.nfc")
+
+qt_internal_add_test(tst_qnearfieldmanager
+ SOURCES
+ ../nfccommons/qnearfieldmanager_emulator.cpp ../nfccommons/qnearfieldmanager_emulator_p.h
+ ../nfccommons/qnearfieldtarget_emulator.cpp ../nfccommons/qnearfieldtarget_emulator_p.h
+ ../nfccommons/targetemulator.cpp ../nfccommons/targetemulator_p.h
+ ../nfccommons/qnearfieldtagtype1.cpp ../nfccommons/qnearfieldtagtype1_p.h
+ ../nfccommons/qnearfieldtagtype2.cpp ../nfccommons/qnearfieldtagtype2_p.h
+ ../nfccommons/qtlv.cpp ../nfccommons/qtlv_p.h
+ tst_qnearfieldmanager.cpp
+ DEFINES
+ SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}/../nfcdata"
+ INCLUDE_DIRECTORIES
+ ../nfccommons
+ LIBRARIES
+ Qt::NfcPrivate
+ TESTDATA ${test_data}
+)
+
+#### Keys ignored in scope 1:.:.:qnearfieldmanager.pro:<TRUE>:
+# _REQUIREMENTS = "contains(QT_CONFIG, private_tests)"
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qnearfieldmanager CONDITION builtin_testdata
+ DEFINES
+ BUILTIN_TESTDATA
+)
diff --git a/tests/auto/qnearfieldmanager/qnearfieldmanager.pro b/tests/auto/qnearfieldmanager/qnearfieldmanager.pro
deleted file mode 100644
index e01f9b84..00000000
--- a/tests/auto/qnearfieldmanager/qnearfieldmanager.pro
+++ /dev/null
@@ -1,29 +0,0 @@
-requires(contains(QT_CONFIG, private_tests))
-
-SOURCES += tst_qnearfieldmanager.cpp
-TARGET = tst_qnearfieldmanager
-CONFIG += testcase
-
-QT = core nfc-private testlib
-
-INCLUDEPATH += ../../../src/nfc
-VPATH += ../../../src/nfc
-
-HEADERS += \
- qnearfieldmanagervirtualbase_p.h \
- qnearfieldmanager_emulator_p.h \
- qnearfieldtarget_emulator_p.h \
- targetemulator_p.h
-
-SOURCES += \
- qnearfieldmanagervirtualbase.cpp \
- qnearfieldmanager_emulator.cpp \
- qnearfieldtarget_emulator.cpp \
- targetemulator.cpp
-
-DEFINES += SRCDIR=\\\"$$PWD/../nfcdata\\\"
-
-TESTDATA += "$$PWD/../nfcdata/Qt Labs Website Tag Type1.nfc" \
- "$$PWD/../nfcdata/Qt Website Tag Type1.nfc"
-
-builtin_testdata: DEFINES += BUILTIN_TESTDATA
diff --git a/tests/auto/qnearfieldmanager/tst_qnearfieldmanager.cpp b/tests/auto/qnearfieldmanager/tst_qnearfieldmanager.cpp
index c3c457e9..a902ac5d 100644
--- a/tests/auto/qnearfieldmanager/tst_qnearfieldmanager.cpp
+++ b/tests/auto/qnearfieldmanager/tst_qnearfieldmanager.cpp
@@ -1,39 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
-#include <private/qnearfieldmanager_emulator_p.h>
-#include <qnearfieldmanager.h>
-#include <qndefnfctextrecord.h>
-#include <qndefnfcurirecord.h>
-#include <qndefmessage.h>
-#include <qndefrecord.h>
+#include <qnearfieldmanager_emulator_p.h>
+#include <QtNfc/qnearfieldmanager.h>
+#include <QtNfc/qndefnfctextrecord.h>
+#include <QtNfc/qndefnfcurirecord.h>
+#include <QtNfc/qndefmessage.h>
+#include <QtNfc/qndefrecord.h>
QT_USE_NAMESPACE
@@ -52,18 +27,13 @@ public:
private slots:
void initTestCase();
- void targetDetected_data();
- void targetDetected();
-
- void unregisterNdefMessageHandler();
-
- void registerNdefMessageHandler();
+ void isSupported();
+ void isSupported_data();
- void registerNdefMessageHandler_type_data();
- void registerNdefMessageHandler_type();
+ void userInformation();
- void registerNdefMessageHandler_filter_data();
- void registerNdefMessageHandler_filter();
+ void targetDetected_data();
+ void targetDetected();
};
tst_QNearFieldManager::tst_QNearFieldManager()
@@ -79,202 +49,108 @@ void tst_QNearFieldManager::initTestCase()
QNearFieldManagerPrivateImpl *emulatorBackend = new QNearFieldManagerPrivateImpl;
QNearFieldManager manager(emulatorBackend, 0);
- QVERIFY(manager.isAvailable());
+ QVERIFY(manager.isEnabled());
}
-void tst_QNearFieldManager::targetDetected_data()
+void tst_QNearFieldManager::isSupported()
{
- QTest::addColumn<bool>("deleteTarget");
-
- QTest::newRow("AnyTarget") << false;
- QTest::newRow("NfcTagType1") << false;
- QTest::newRow("Delete Target") << true;
-}
-
-void tst_QNearFieldManager::targetDetected()
-{
- QFETCH(bool, deleteTarget);
+ QFETCH(QNearFieldTarget::AccessMethod, accessMethod);
+ QFETCH(bool, supported);
QNearFieldManagerPrivateImpl *emulatorBackend = new QNearFieldManagerPrivateImpl;
- QNearFieldManager manager(emulatorBackend, 0);
+ QNearFieldManager manager(emulatorBackend, nullptr);
- QSignalSpy targetDetectedSpy(&manager, SIGNAL(targetDetected(QNearFieldTarget*)));
- QSignalSpy targetLostSpy(&manager, SIGNAL(targetLost(QNearFieldTarget*)));
-
- manager.startTargetDetection();
-
- QTRY_VERIFY(!targetDetectedSpy.isEmpty());
-
- QNearFieldTarget *target = targetDetectedSpy.first().at(0).value<QNearFieldTarget *>();
-
- QSignalSpy disconnectedSpy(target, SIGNAL(disconnected()));
-
- QVERIFY(target);
-
- QVERIFY(!target->uid().isEmpty());
-
- if (!deleteTarget) {
- QTRY_VERIFY(!targetLostSpy.isEmpty());
-
- QNearFieldTarget *lostTarget = targetLostSpy.first().at(0).value<QNearFieldTarget *>();
-
- QCOMPARE(target, lostTarget);
-
- QVERIFY(!disconnectedSpy.isEmpty());
- } else {
- delete target;
-
- // wait for another targetDetected() without a targetLost() signal in between.
- targetDetectedSpy.clear();
- targetLostSpy.clear();
-
- QTRY_VERIFY(targetLostSpy.isEmpty() && !targetDetectedSpy.isEmpty());
- }
-
- manager.stopTargetDetection();
+ QCOMPARE(manager.isSupported(accessMethod), supported);
}
-void tst_QNearFieldManager::unregisterNdefMessageHandler()
+void tst_QNearFieldManager::isSupported_data()
{
- QNearFieldManagerPrivateImpl *emulatorBackend = new QNearFieldManagerPrivateImpl;
- QNearFieldManager manager(emulatorBackend, 0);
+ QTest::addColumn<QNearFieldTarget::AccessMethod>("accessMethod");
+ QTest::addColumn<bool>("supported");
- QVERIFY(!manager.unregisterNdefMessageHandler(-1));
- QVERIFY(!manager.unregisterNdefMessageHandler(0));
+ QTest::newRow("UnknownAccess") << QNearFieldTarget::UnknownAccess << false;
+ QTest::newRow("NdefAccess") << QNearFieldTarget::NdefAccess << true;
+ QTest::newRow("TagTypeSpecificAccess") << QNearFieldTarget::TagTypeSpecificAccess << false;
+ QTest::newRow("AnyAccess") << QNearFieldTarget::AnyAccess << true;
}
-class MessageListener : public QObject
-{
- Q_OBJECT
-
-signals:
- void matchedNdefMessage(const QNdefMessage &message, QNearFieldTarget *target);
-};
-
-void tst_QNearFieldManager::registerNdefMessageHandler()
+void tst_QNearFieldManager::userInformation()
{
QNearFieldManagerPrivateImpl *emulatorBackend = new QNearFieldManagerPrivateImpl;
- QNearFieldManager manager(emulatorBackend, 0);
+ QNearFieldManager manager(emulatorBackend, nullptr);
- MessageListener listener;
- QSignalSpy messageSpy(&listener, SIGNAL(matchedNdefMessage(QNdefMessage,QNearFieldTarget*)));
+ QSignalSpy spy(emulatorBackend, &QNearFieldManagerPrivateImpl::userInformationChanged);
- int id = manager.registerNdefMessageHandler(&listener,
- SIGNAL(matchedNdefMessage(QNdefMessage,QNearFieldTarget*)));
+ manager.startTargetDetection(QNearFieldTarget::AnyAccess);
- QVERIFY(id != -1);
+ const QString progressString("NFC target detection in progress");
+ manager.setUserInformation(progressString);
- QTRY_VERIFY(!messageSpy.isEmpty());
+ const QString errorString("Failed to detect NFC targets");
+ manager.stopTargetDetection(errorString);
- const QNdefMessage message = messageSpy.first().at(0).value<QNdefMessage>();
- QNearFieldTarget *target = messageSpy.first().at(1).value<QNearFieldTarget *>();
-
- QVERIFY(target);
-
- QVERIFY(manager.unregisterNdefMessageHandler(id));
+ QCOMPARE(spy.size(), 2);
+ QCOMPARE(spy.at(0).at(0).toString(), progressString);
+ QCOMPARE(spy.at(1).at(0).toString(), errorString);
}
-void tst_QNearFieldManager::registerNdefMessageHandler_type_data()
+void tst_QNearFieldManager::targetDetected_data()
{
- QTest::addColumn<QNdefRecord::TypeNameFormat>("typeNameFormat");
- QTest::addColumn<QByteArray>("type");
+ QTest::addColumn<QNearFieldTarget::AccessMethod>("accessMethod");
+ QTest::addColumn<bool>("deleteTarget");
- QTest::newRow("Image") << QNdefRecord::Mime << QByteArray("image/png");
- QTest::newRow("URI") << QNdefRecord::NfcRtd << QByteArray("U");
- QTest::newRow("Text") << QNdefRecord::NfcRtd << QByteArray("T");
+ QTest::newRow("UnknownAccess") << QNearFieldTarget::UnknownAccess << false;
+ QTest::newRow("NdefAccess, no delete") << QNearFieldTarget::NdefAccess << false;
+ QTest::newRow("AnyAccess, delete") << QNearFieldTarget::AnyAccess << true;
}
-void tst_QNearFieldManager::registerNdefMessageHandler_type()
+void tst_QNearFieldManager::targetDetected()
{
- QFETCH(QNdefRecord::TypeNameFormat, typeNameFormat);
- QFETCH(QByteArray, type);
+ QFETCH(QNearFieldTarget::AccessMethod, accessMethod);
+ QFETCH(bool, deleteTarget);
QNearFieldManagerPrivateImpl *emulatorBackend = new QNearFieldManagerPrivateImpl;
- QNearFieldManager manager(emulatorBackend, 0);
+ QNearFieldManager manager(emulatorBackend, nullptr);
- MessageListener listener;
- QSignalSpy messageSpy(&listener, SIGNAL(matchedNdefMessage(QNdefMessage,QNearFieldTarget*)));
+ QSignalSpy targetDetectedSpy(&manager, &QNearFieldManager::targetDetected);
+ QSignalSpy targetLostSpy(&manager, &QNearFieldManager::targetLost);
+ QSignalSpy detectionStoppedSpy(&manager, &QNearFieldManager::targetDetectionStopped);
- int id = manager.registerNdefMessageHandler(typeNameFormat, type, &listener,
- SIGNAL(matchedNdefMessage(QNdefMessage,QNearFieldTarget*)));
+ const bool started = manager.startTargetDetection(accessMethod);
- QVERIFY(id != -1);
+ if (started) {
+ QTRY_VERIFY(!targetDetectedSpy.isEmpty());
- QTRY_VERIFY(!messageSpy.isEmpty());
+ QNearFieldTarget *target = targetDetectedSpy.first().at(0).value<QNearFieldTarget *>();
- const QNdefMessage message = messageSpy.first().at(0).value<QNdefMessage>();
+ QSignalSpy disconnectedSpy(target, SIGNAL(disconnected()));
- bool hasRecord = false;
- for (const QNdefRecord &record : message) {
- if (record.typeNameFormat() == typeNameFormat && record.type() == type) {
- hasRecord = true;
- break;
- }
- }
+ QVERIFY(target);
- QVERIFY(hasRecord);
+ QVERIFY(!target->uid().isEmpty());
- QNearFieldTarget *target = messageSpy.first().at(1).value<QNearFieldTarget *>();
+ if (!deleteTarget) {
+ QTRY_VERIFY(!targetLostSpy.isEmpty());
- QVERIFY(target);
-}
+ QNearFieldTarget *lostTarget = targetLostSpy.first().at(0).value<QNearFieldTarget *>();
-void tst_QNearFieldManager::registerNdefMessageHandler_filter_data()
-{
- QTest::addColumn<QNdefFilter>("filter");
-
- QNdefFilter filter;
-
- QTest::newRow("Empty") << filter;
-
- filter.clear();
- filter.setOrderMatch(true);
- filter.appendRecord(QNdefRecord::Mime, "image/png");
- filter.appendRecord<QNdefNfcTextRecord>(2, 10);
- filter.appendRecord<QNdefNfcUriRecord>(1, 1);
- QTest::newRow("Image + Multiple Text + URI") << filter;
-
- filter.clear();
- filter.setOrderMatch(true);
- filter.appendRecord<QNdefNfcTextRecord>(1, 1);
- filter.appendRecord<QNdefNfcUriRecord>(1, 1);
- QTest::newRow("Text + URI") << filter;
-
- QNdefFilter::Record record;
-
- filter.clear();
- filter.setOrderMatch(false);
- filter.appendRecord<QNdefNfcUriRecord>(1, 1);
- record.typeNameFormat = QNdefRecord::NfcRtd;
- record.type = "T";
- record.minimum = 1;
- record.maximum = 1;
- filter.appendRecord(record);
- QTest::newRow("Unordered Text + URI") << filter;
-}
+ QCOMPARE(target, lostTarget);
-void tst_QNearFieldManager::registerNdefMessageHandler_filter()
-{
- QFETCH(QNdefFilter, filter);
+ QVERIFY(!disconnectedSpy.isEmpty());
+ } else {
+ delete target;
- QNearFieldManagerPrivateImpl *emulatorBackend = new QNearFieldManagerPrivateImpl;
- QNearFieldManager manager(emulatorBackend, 0);
+ // wait for another targetDetected() without a targetLost() signal in between.
+ targetDetectedSpy.clear();
+ targetLostSpy.clear();
- MessageListener listener;
- QSignalSpy messageSpy(&listener, SIGNAL(matchedNdefMessage(QNdefMessage,QNearFieldTarget*)));
-
- int id = manager.registerNdefMessageHandler(filter, &listener,
- SIGNAL(matchedNdefMessage(QNdefMessage,QNearFieldTarget*)));
-
- QVERIFY(id != -1);
-
- QTRY_VERIFY(!messageSpy.isEmpty());
-
- const QNdefMessage message = messageSpy.first().at(0).value<QNdefMessage>();
+ QTRY_VERIFY(targetLostSpy.isEmpty() && !targetDetectedSpy.isEmpty());
+ }
+ }
- QNearFieldTarget *target = messageSpy.first().at(1).value<QNearFieldTarget *>();
+ manager.stopTargetDetection();
- QVERIFY(target);
+ QCOMPARE(detectionStoppedSpy.size(), 1);
}
QTEST_MAIN(tst_QNearFieldManager)
diff --git a/tests/auto/qnearfieldtagtype1/CMakeLists.txt b/tests/auto/qnearfieldtagtype1/CMakeLists.txt
new file mode 100644
index 00000000..03189bfd
--- /dev/null
+++ b/tests/auto/qnearfieldtagtype1/CMakeLists.txt
@@ -0,0 +1,48 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qnearfieldtagtype1 LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+if (NOT QT_FEATURE_private_tests)
+ return()
+endif()
+
+#####################################################################
+## tst_qnearfieldtagtype1 Test:
+#####################################################################
+
+# Collect test data
+list(APPEND test_data "../nfcdata/Qt Labs Website Tag Type1.nfc")
+list(APPEND test_data "../nfcdata/Qt Website Tag Type1.nfc")
+
+qt_internal_add_test(tst_qnearfieldtagtype1
+ SOURCES
+ ../nfccommons/qnearfieldtarget_emulator.cpp ../nfccommons/qnearfieldtarget_emulator_p.h
+ ../nfccommons/targetemulator.cpp ../nfccommons/targetemulator_p.h
+ ../nfccommons/qnearfieldtagtype1.cpp ../nfccommons/qnearfieldtagtype1_p.h
+ ../nfccommons/qnearfieldtagtype2.cpp ../nfccommons/qnearfieldtagtype2_p.h
+ ../nfccommons/qtlv.cpp ../nfccommons/qtlv_p.h
+ tst_qnearfieldtagtype1.cpp
+ DEFINES
+ SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}/../nfcdata"
+ INCLUDE_DIRECTORIES
+ ../nfccommons
+ LIBRARIES
+ Qt::NfcPrivate
+ TESTDATA ${test_data}
+)
+
+#### Keys ignored in scope 1:.:.:qnearfieldtagtype1.pro:<TRUE>:
+# _REQUIREMENTS = "contains(QT_CONFIG, private_tests)"
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qnearfieldtagtype1 CONDITION builtin_testdata
+ DEFINES
+ BUILTIN_TESTDATA
+)
diff --git a/tests/auto/qnearfieldtagtype1/qnearfieldtagtype1.pro b/tests/auto/qnearfieldtagtype1/qnearfieldtagtype1.pro
deleted file mode 100644
index e765151d..00000000
--- a/tests/auto/qnearfieldtagtype1/qnearfieldtagtype1.pro
+++ /dev/null
@@ -1,29 +0,0 @@
-requires(contains(QT_CONFIG, private_tests))
-
-SOURCES += tst_qnearfieldtagtype1.cpp
-TARGET = tst_qnearfieldtagtype1
-CONFIG += testcase
-
-QT = core nfc-private testlib
-
-INCLUDEPATH += ../../../src/nfc
-VPATH += ../../../src/nfc
-
-HEADERS += \
- qnearfieldmanagervirtualbase_p.h \
- qnearfieldmanager_emulator_p.h \
- qnearfieldtarget_emulator_p.h \
- targetemulator_p.h
-
-SOURCES += \
- qnearfieldmanagervirtualbase.cpp \
- qnearfieldmanager_emulator.cpp \
- qnearfieldtarget_emulator.cpp \
- targetemulator.cpp
-
-DEFINES += SRCDIR=\\\"$$PWD/../nfcdata\\\"
-
-TESTDATA += "$$PWD/../nfcdata/Qt Labs Website Tag Type1.nfc" \
- "$$PWD/../nfcdata/Qt Website Tag Type1.nfc"
-
-builtin_testdata: DEFINES += BUILTIN_TESTDATA
diff --git a/tests/auto/qnearfieldtagtype1/tst_qnearfieldtagtype1.cpp b/tests/auto/qnearfieldtagtype1/tst_qnearfieldtagtype1.cpp
index fb7aa7ae..8f540589 100644
--- a/tests/auto/qnearfieldtagtype1/tst_qnearfieldtagtype1.cpp
+++ b/tests/auto/qnearfieldtagtype1/tst_qnearfieldtagtype1.cpp
@@ -1,38 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
-#include <private/qnearfieldmanager_emulator_p.h>
-#include <qnearfieldmanager.h>
-#include <qndefmessage.h>
-#include <private/qnearfieldtagtype1_p.h>
-#include <qndefnfctextrecord.h>
+#include <qnearfieldtarget_emulator_p.h>
+#include <qnearfieldtagtype1_p.h>
+
+#include <QtNfc/qndefmessage.h>
+#include <QtNfc/qndefnfctextrecord.h>
QT_USE_NAMESPACE
@@ -57,48 +32,45 @@ private slots:
private:
void waitForMatchingTarget();
- QNearFieldManagerPrivateImpl *emulatorBackend;
- QNearFieldManager *manager;
+ QObject *targetParent;
QNearFieldTagType1 *target;
};
tst_QNearFieldTagType1::tst_QNearFieldTagType1()
-: emulatorBackend(0), manager(0), target(0)
+: targetParent(0), target(0)
{
QDir::setCurrent(QLatin1String(SRCDIR));
qRegisterMetaType<QNdefMessage>();
+ qRegisterMetaType<TagBase *>();
qRegisterMetaType<QNearFieldTarget *>();
}
void tst_QNearFieldTagType1::init()
{
- emulatorBackend = new QNearFieldManagerPrivateImpl;
- manager = new QNearFieldManager(emulatorBackend, 0);
+ targetParent = new QObject();
+
+ TagActivator::instance()->initialize();
+ TagActivator::instance()->start();
}
void tst_QNearFieldTagType1::cleanup()
{
- emulatorBackend->reset();
+ TagActivator::instance()->reset();
- delete manager;
- manager = 0;
- emulatorBackend = 0;
+ delete targetParent;
+ targetParent = 0;
target = 0;
}
void tst_QNearFieldTagType1::waitForMatchingTarget()
{
- QSignalSpy targetDetectedSpy(manager, SIGNAL(targetDetected(QNearFieldTarget*)));
-
- manager->startTargetDetection();
+ TagActivator *activator = TagActivator::instance();
+ QSignalSpy targetDetectedSpy(activator, SIGNAL(tagActivated(TagBase*)));
QTRY_VERIFY(!targetDetectedSpy.isEmpty());
- target =
- qobject_cast<QNearFieldTagType1 *>(targetDetectedSpy.first().at(0).value<QNearFieldTarget *>());
-
- manager->stopTargetDetection();
+ target = new TagType1(targetDetectedSpy.first().at(0).value<TagBase *>(), targetParent);
QVERIFY(target);
@@ -108,6 +80,8 @@ void tst_QNearFieldTagType1::waitForMatchingTarget()
void tst_QNearFieldTagType1::staticMemoryModel()
{
waitForMatchingTarget();
+ if (QTest::currentTestFailed())
+ return;
QVERIFY(target->accessMethods() & QNearFieldTarget::TagTypeSpecificAccess);
@@ -120,7 +94,7 @@ void tst_QNearFieldTagType1::staticMemoryModel()
const QByteArray data = target->requestResponse(id).toByteArray();
- QCOMPARE(data.length(), 6);
+ QCOMPARE(data.size(), 6);
quint8 hr0 = data.at(0);
//quint8 hr1 = data.at(1);
@@ -139,7 +113,7 @@ void tst_QNearFieldTagType1::staticMemoryModel()
QVERIFY(target->waitForRequestCompleted(id));
const QByteArray data = target->requestResponse(id).toByteArray();
- QCOMPARE(data.length(), 122);
+ QCOMPARE(data.size(), 122);
// verify NfcTagType1.
QVERIFY(data.at(0) & 0x10);
@@ -174,8 +148,7 @@ void tst_QNearFieldTagType1::staticMemoryModel()
quint8 byte = target->requestResponse(id).toUInt();
id = target->writeByte(i, 0x55);
- QVERIFY(!target->waitForRequestCompleted(id,50));
-
+ QVERIFY(target->waitForRequestCompleted(id));
QVERIFY(!target->requestResponse(id).isValid());
id = target->readByte(i);
@@ -224,8 +197,7 @@ void tst_QNearFieldTagType1::staticMemoryModel()
quint8 byte = target->requestResponse(id).toUInt();
id = target->writeByte(i, 0x55);
- QVERIFY(!target->waitForRequestCompleted(id,50));
-
+ QVERIFY(target->waitForRequestCompleted(id));
QVERIFY(!target->requestResponse(id).isValid());
id = target->readByte(i);
@@ -245,6 +217,8 @@ void tst_QNearFieldTagType1::dynamicMemoryModel()
QList<QByteArray> seenIds;
forever {
waitForMatchingTarget();
+ if (QTest::currentTestFailed())
+ return;
QNearFieldTarget::RequestId id = target->readIdentification();
QVERIFY(target->waitForRequestCompleted(id));
@@ -272,7 +246,7 @@ void tst_QNearFieldTagType1::dynamicMemoryModel()
QCOMPARE(quint8(block.at(7)), quint8(0x00));
id = target->writeBlock(0x00, QByteArray(8, quint8(0x55)));
- QVERIFY(!target->waitForRequestCompleted(id,50));
+ QVERIFY(target->waitForRequestCompleted(id));
QVERIFY(!target->requestResponse(id).isValid());
QCOMPARE(target->uid(), block.left(7));
@@ -338,7 +312,7 @@ void tst_QNearFieldTagType1::dynamicMemoryModel()
QByteArray block = target->requestResponse(id).toByteArray();
id = target->writeBlock(i, QByteArray(8, quint8(0x55)));
- QVERIFY(!target->waitForRequestCompleted(id,50));
+ QVERIFY(target->waitForRequestCompleted(id));
QVERIFY(!target->requestResponse(id).isValid());
id = target->readBlock(i);
@@ -350,14 +324,17 @@ void tst_QNearFieldTagType1::dynamicMemoryModel()
for (int i = 0; i < 256; ++i) {
QNearFieldTarget::RequestId id = target->readBlock(i);
- QVERIFY(!target->waitForRequestCompleted(id,50));
+ QVERIFY(target->waitForRequestCompleted(id));
+ QVERIFY(!target->requestResponse(id).isValid());
id = target->writeBlock(i, QByteArray(8, quint8(0x55)));
- QVERIFY(!target->waitForRequestCompleted(id,50));
+ QVERIFY(target->waitForRequestCompleted(id));
+ QVERIFY(!target->requestResponse(id).isValid());
}
for (int i = 0; i < 16; ++i) {
QNearFieldTarget::RequestId id = target->readSegment(i);
- QVERIFY(!target->waitForRequestCompleted(id,50));
+ QVERIFY(target->waitForRequestCompleted(id));
+ QVERIFY(!target->requestResponse(id).isValid());
}
}
}
@@ -371,6 +348,8 @@ void tst_QNearFieldTagType1::ndefMessages()
QByteArray firstId;
forever {
waitForMatchingTarget();
+ if (QTest::currentTestFailed())
+ return;
QNearFieldTarget::RequestId id = target->readIdentification();
QVERIFY(target->waitForRequestCompleted(id));
@@ -403,7 +382,7 @@ void tst_QNearFieldTagType1::ndefMessages()
}
QList<QNdefMessage> ndefMessages;
- for (int i = 0; i < ndefMessageReadSpy.count(); ++i)
+ for (qsizetype i = 0; i < ndefMessageReadSpy.size(); ++i)
ndefMessages.append(ndefMessageReadSpy.at(i).first().value<QNdefMessage>());
QList<QNdefMessage> messages;
@@ -426,7 +405,6 @@ void tst_QNearFieldTagType1::ndefMessages()
requestCompletedSpy.clear();
errorSpy.clear();
- QSignalSpy ndefMessageWriteSpy(target, SIGNAL(ndefMessagesWritten()));
QNearFieldTarget::RequestId writeId = target->writeNdefMessages(messages);
QVERIFY(writeId.isValid());
@@ -440,8 +418,6 @@ void tst_QNearFieldTagType1::ndefMessages()
requestCompletedSpy.takeFirst().first().value<QNearFieldTarget::RequestId>();
}
- QVERIFY(!ndefMessageWriteSpy.isEmpty());
-
QVERIFY(target->hasNdefMessage());
ndefMessageReadSpy.clear();
@@ -462,7 +438,7 @@ void tst_QNearFieldTagType1::ndefMessages()
}
QList<QNdefMessage> storedMessages;
- for (int i = 0; i < ndefMessageReadSpy.count(); ++i)
+ for (qsizetype i = 0; i < ndefMessageReadSpy.size(); ++i)
storedMessages.append(ndefMessageReadSpy.at(i).first().value<QNdefMessage>());
QVERIFY(ndefMessages != storedMessages);
diff --git a/tests/auto/qnearfieldtagtype2/CMakeLists.txt b/tests/auto/qnearfieldtagtype2/CMakeLists.txt
new file mode 100644
index 00000000..cc6d6f32
--- /dev/null
+++ b/tests/auto/qnearfieldtagtype2/CMakeLists.txt
@@ -0,0 +1,48 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qnearfieldtagtype2 LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+if (NOT QT_FEATURE_private_tests)
+ return()
+endif()
+
+#####################################################################
+## tst_qnearfieldtagtype2 Test:
+#####################################################################
+
+# Collect test data
+list(APPEND test_data "nfcdata/Dynamic Empty Tag.nfc")
+list(APPEND test_data "nfcdata/Empty Tag.nfc")
+
+qt_internal_add_test(tst_qnearfieldtagtype2
+ SOURCES
+ ../nfccommons/qnearfieldtarget_emulator.cpp ../nfccommons/qnearfieldtarget_emulator_p.h
+ ../nfccommons/targetemulator.cpp ../nfccommons/targetemulator_p.h
+ ../nfccommons/qnearfieldtagtype1.cpp ../nfccommons/qnearfieldtagtype1_p.h
+ ../nfccommons/qnearfieldtagtype2.cpp ../nfccommons/qnearfieldtagtype2_p.h
+ ../nfccommons/qtlv.cpp ../nfccommons/qtlv_p.h
+ tst_qnearfieldtagtype2.cpp
+ DEFINES
+ SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}/nfcdata"
+ INCLUDE_DIRECTORIES
+ ../nfccommons
+ LIBRARIES
+ Qt::NfcPrivate
+ TESTDATA ${test_data}
+)
+
+#### Keys ignored in scope 1:.:.:qnearfieldtagtype2.pro:<TRUE>:
+# _REQUIREMENTS = "contains(QT_CONFIG, private_tests)"
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qnearfieldtagtype2 CONDITION builtin_testdata
+ DEFINES
+ BUILTIN_TESTDATA
+)
diff --git a/tests/auto/qnearfieldtagtype2/qnearfieldtagtype2.pro b/tests/auto/qnearfieldtagtype2/qnearfieldtagtype2.pro
deleted file mode 100644
index aa388312..00000000
--- a/tests/auto/qnearfieldtagtype2/qnearfieldtagtype2.pro
+++ /dev/null
@@ -1,29 +0,0 @@
-requires(contains(QT_CONFIG, private_tests))
-
-SOURCES += tst_qnearfieldtagtype2.cpp
-TARGET = tst_qnearfieldtagtype2
-CONFIG += testcase
-
-QT = core nfc-private testlib
-
-INCLUDEPATH += ../../../src/nfc
-VPATH += ../../../src/nfc
-
-HEADERS += \
- qnearfieldmanagervirtualbase_p.h \
- qnearfieldtarget_emulator_p.h \
- qnearfieldmanager_emulator_p.h \
- targetemulator_p.h
-
-SOURCES += \
- qnearfieldmanagervirtualbase.cpp \
- qnearfieldtarget_emulator.cpp \
- qnearfieldmanager_emulator.cpp \
- targetemulator.cpp
-
-DEFINES += SRCDIR=\\\"$$PWD/nfcdata\\\"
-
-TESTDATA += "$$PWD/nfcdata/Dynamic Empty Tag.nfc" \
- "$$PWD/nfcdata/Empty Tag.nfc"
-
-builtin_testdata: DEFINES += BUILTIN_TESTDATA
diff --git a/tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp b/tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp
index 456216b9..59b1dd27 100644
--- a/tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp
+++ b/tests/auto/qnearfieldtagtype2/tst_qnearfieldtagtype2.cpp
@@ -1,38 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNfc module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
-#include <private/qnearfieldmanager_emulator_p.h>
-#include <qnearfieldmanager.h>
-#include <qndefmessage.h>
-#include <private/qnearfieldtagtype2_p.h>
-#include <qndefnfctextrecord.h>
+#include <qnearfieldtarget_emulator_p.h>
+#include <qnearfieldtagtype2_p.h>
+#include <QtNfc/qndefmessage.h>
+#include <QtNfc/qndefnfctextrecord.h>
QT_USE_NAMESPACE
@@ -59,47 +33,45 @@ private slots:
private:
void waitForMatchingTarget();
- QNearFieldManagerPrivateImpl *emulatorBackend;
- QNearFieldManager *manager;
+ QObject *targetParent;
QNearFieldTagType2 *target;
};
tst_QNearFieldTagType2::tst_QNearFieldTagType2()
-: emulatorBackend(0), manager(0), target(0)
+: targetParent(0), target(0)
{
QDir::setCurrent(QLatin1String(SRCDIR));
qRegisterMetaType<QNdefMessage>();
+ qRegisterMetaType<TagBase *>();
qRegisterMetaType<QNearFieldTarget *>();
}
void tst_QNearFieldTagType2::init()
{
- emulatorBackend = new QNearFieldManagerPrivateImpl;
- manager = new QNearFieldManager(emulatorBackend, 0);
+ targetParent = new QObject();
+
+ TagActivator::instance()->initialize();
+ TagActivator::instance()->start();
}
void tst_QNearFieldTagType2::cleanup()
{
- emulatorBackend->reset();
+ TagActivator::instance()->reset();
- delete manager;
- manager = 0;
- emulatorBackend = 0;
+ delete targetParent;
+ targetParent = 0;
target = 0;
}
void tst_QNearFieldTagType2::waitForMatchingTarget()
{
- QSignalSpy targetDetectedSpy(manager, SIGNAL(targetDetected(QNearFieldTarget*)));
-
- manager->startTargetDetection();
+ TagActivator *activator = TagActivator::instance();
+ QSignalSpy targetDetectedSpy(activator, SIGNAL(tagActivated(TagBase*)));
QTRY_VERIFY(!targetDetectedSpy.isEmpty());
- target = qobject_cast<QNearFieldTagType2 *>(targetDetectedSpy.first().at(0).value<QNearFieldTarget *>());
-
- manager->stopTargetDetection();
+ target = new TagType2(targetDetectedSpy.first().at(0).value<TagBase *>(), targetParent);
QVERIFY(target);
@@ -109,6 +81,8 @@ void tst_QNearFieldTagType2::waitForMatchingTarget()
void tst_QNearFieldTagType2::staticMemoryModel()
{
waitForMatchingTarget();
+ if (QTest::currentTestFailed())
+ return;
QVERIFY(target->accessMethods() & QNearFieldTarget::TagTypeSpecificAccess);
@@ -170,6 +144,8 @@ void tst_QNearFieldTagType2::dynamicMemoryModel()
QList<QByteArray> seenIds;
forever {
waitForMatchingTarget();
+ if (QTest::currentTestFailed())
+ return;
QVERIFY(target->accessMethods() & QNearFieldTarget::TagTypeSpecificAccess);
@@ -271,6 +247,8 @@ void tst_QNearFieldTagType2::ndefMessages()
QByteArray firstId;
forever {
waitForMatchingTarget();
+ if (QTest::currentTestFailed())
+ return;
QNearFieldTarget::RequestId id = target->readBlock(0);
QVERIFY(target->waitForRequestCompleted(id));
@@ -295,7 +273,7 @@ void tst_QNearFieldTagType2::ndefMessages()
QTRY_VERIFY(!ndefMessageReadSpy.isEmpty());
QList<QNdefMessage> ndefMessages;
- for (int i = 0; i < ndefMessageReadSpy.count(); ++i)
+ for (qsizetype i = 0; i < ndefMessageReadSpy.size(); ++i)
ndefMessages.append(ndefMessageReadSpy.at(i).first().value<QNdefMessage>());
QList<QNdefMessage> messages;
@@ -315,10 +293,13 @@ void tst_QNearFieldTagType2::ndefMessages()
messages.append(message);
- QSignalSpy ndefMessageWriteSpy(target, SIGNAL(ndefMessagesWritten()));
- target->writeNdefMessages(messages);
+ QSignalSpy requestCompleteSpy(target, &QNearFieldTagType2::requestCompleted);
+ id = target->writeNdefMessages(messages);
- QTRY_VERIFY(!ndefMessageWriteSpy.isEmpty());
+ QTRY_VERIFY(!requestCompleteSpy.isEmpty());
+ const auto completedId =
+ requestCompleteSpy.takeFirst().first().value<QNearFieldTarget::RequestId>();
+ QCOMPARE(completedId, id);
QVERIFY(target->hasNdefMessage());
@@ -329,7 +310,7 @@ void tst_QNearFieldTagType2::ndefMessages()
QTRY_VERIFY(!ndefMessageReadSpy.isEmpty());
QList<QNdefMessage> storedMessages;
- for (int i = 0; i < ndefMessageReadSpy.count(); ++i)
+ for (qsizetype i = 0; i < ndefMessageReadSpy.size(); ++i)
storedMessages.append(ndefMessageReadSpy.at(i).first().value<QNdefMessage>());
QVERIFY(ndefMessages != storedMessages);
diff --git a/tests/bluetoothtestdevice/CMakeLists.txt b/tests/bluetoothtestdevice/CMakeLists.txt
new file mode 100644
index 00000000..e017eedf
--- /dev/null
+++ b/tests/bluetoothtestdevice/CMakeLists.txt
@@ -0,0 +1,74 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## bluetoothtestdevice Tool:
+#####################################################################
+
+cmake_minimum_required(VERSION 3.16...3.21)
+
+if(NOT TARGET Qt::Bluetooth)
+ # for standalone build
+ project(bluetoothtestdevice LANGUAGES CXX)
+
+ set(CMAKE_AUTOMOC ON)
+
+ find_package(Qt6 REQUIRED COMPONENTS Bluetooth Core)
+ if(ANDROID OR APPLE)
+ find_package(Qt6 REQUIRED COMPONENTS Gui)
+ endif()
+
+ qt_add_executable(
+ bluetoothtestdevice
+ bluetoothtestdevice.cpp
+ )
+
+else()
+
+ qt_internal_add_executable(bluetoothtestdevice
+ SOURCES
+ bluetoothtestdevice.cpp
+ )
+
+ if(MACOS)
+ # Explicitly link against the static permission plugin because tests
+ # currently don't have finalizers run for them except for iOS.
+ # TODO: Remove this when qtbase automatically runs finalizers for tests: QTBUG-112212
+ target_link_libraries(bluetoothtestdevice PRIVATE Qt6::QDarwinBluetoothPermissionPlugin)
+ endif()
+
+endif()
+
+set_target_properties(bluetoothtestdevice PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+if(APPLE)
+ # Ninja has trouble with relative paths, convert to absolute as a workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../shared ABSOLUTE)
+ if(IOS)
+ set_target_properties(bluetoothtestdevice PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.ios.plist"
+ )
+ else()
+ set_target_properties(bluetoothtestdevice PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.macos.plist"
+ )
+ endif()
+endif()
+
+target_link_libraries(
+ bluetoothtestdevice
+ PUBLIC
+ Qt::Core
+ Qt::Bluetooth
+)
+
+if(ANDROID OR APPLE)
+ target_link_libraries(
+ bluetoothtestdevice
+ PUBLIC
+ Qt::Gui
+ )
+endif()
diff --git a/tests/bluetoothtestdevice/bluetoothtestdevice.cpp b/tests/bluetoothtestdevice/bluetoothtestdevice.cpp
new file mode 100644
index 00000000..b5c32eed
--- /dev/null
+++ b/tests/bluetoothtestdevice/bluetoothtestdevice.cpp
@@ -0,0 +1,474 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QBluetoothLocalDevice>
+#include <QLatin1String>
+#include <QLoggingCategory>
+#include <QLowEnergyAdvertisingData>
+#include <QLowEnergyAdvertisingParameters>
+#include <QLowEnergyCharacteristicData>
+#include <QLowEnergyController>
+#include <QLowEnergyDescriptorData>
+#include <QLowEnergyServiceData>
+#include <QLowEnergyDescriptorData>
+#include <QTimer>
+
+#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN)
+#include <QGuiApplication>
+#else
+#include <QCoreApplication>
+#endif // Q_OS_ANDROID || Q_OS_IOS
+
+#if QT_CONFIG(permissions)
+#include <QtCore/qpermissions.h>
+#endif
+
+#include <thread>
+
+static const QLatin1String largeAttributeServiceUuid("1f85e37c-ac16-11eb-ae5c-93d3a763feed");
+static const QLatin1String largeAttributeCharUuid("40e4f68e-ac16-11eb-9956-cfe55a8c370c");
+static const QLatin1String largeAttributeDescUuid("44e4f68e-ac16-11eb-9956-cfe55a8c370c");
+static constexpr qsizetype largeAttributeSize{508}; // Size for char and desc values
+
+static const QLatin1String platformIdentifierServiceUuid("4a92cb7f-5031-4a09-8304-3e89413f458d");
+static const QLatin1String platformIdentifierCharUuid("6b0ecf7c-5f09-4c87-aaab-bb49d5d383aa");
+
+static const QLatin1String
+ notificationIndicationTestServiceUuid("bb137ac5-5716-4b80-873b-e2d11d29efe2");
+static const QLatin1String
+ notificationIndicationTestChar1Uuid("6da4d652-0248-478a-a5a8-1e2f076158cc");
+static const QLatin1String
+ notificationIndicationTestChar2Uuid("990930f0-b9cc-4c27-8c1b-ebc2bcae5c95");
+static const QLatin1String
+ notificationIndicationTestChar3Uuid("9a60486b-de5b-4e03-b914-4e158c0bd388");
+static const QLatin1String
+ notificationIndicationTestChar4Uuid("d92435d4-6c2e-43f8-a6be-bbb66b5a3e28");
+
+static const QLatin1String connectionCountServiceUuid("78c61a07-a0f9-4b92-be2d-2570d8dbf010");
+static const QLatin1String connectionCountCharUuid("9414ec2d-792f-46a2-a19e-186d0fb38a08");
+
+static const QLatin1String mtuServiceUuid("9a9483eb-cf4f-4c32-9a6b-794238d5b483");
+static const QLatin1String mtuCharUuid("960d7e2a-a850-4a70-8064-cd74e9ccb6ff");
+
+static const QLatin1String repeatedWriteServiceUuid("72b12a31-98ea-406d-a89d-2c932d11ff67");
+static const QLatin1String repeatedWriteTargetCharUuid("2192ee43-6d17-4e78-b286-db2c3b696833");
+static const QLatin1String repeatedWriteNotifyCharUuid("b3f9d1a2-3d55-49c9-8b29-e09cec77ff86");
+
+static void establishNotifyOnWriteConnection(QLowEnergyService *svc)
+{
+ // Make sure that the value from the repeatedWriteTargetCharUuid
+ // characteristic is writted to the repeatedWriteNotifyCharUuid
+ // characteristic
+ Q_ASSERT(svc->serviceUuid() == QBluetoothUuid(repeatedWriteServiceUuid));
+ QObject::connect(svc, &QLowEnergyService::characteristicChanged, svc,
+ [svc](const QLowEnergyCharacteristic &characteristic,
+ const QByteArray &newValue)
+ {
+ if (characteristic.uuid() == QBluetoothUuid(repeatedWriteTargetCharUuid)) {
+ auto notifyChar = svc->characteristic(QBluetoothUuid(repeatedWriteNotifyCharUuid));
+ svc->writeCharacteristic(notifyChar, newValue);
+ }
+ });
+}
+
+int main(int argc, char *argv[])
+{
+ qDebug() << "build:" << __DATE__ << __TIME__;
+ QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
+#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN)
+ QGuiApplication app(argc, argv);
+#else
+ QCoreApplication app(argc, argv);
+#endif // Q_OS_ANDROID || Q_OS_IOS
+
+#if QT_CONFIG(permissions)
+ // Check Bluetooth permission and request it if the app doesn't have it
+ auto permissionStatus = app.checkPermission(QBluetoothPermission{});
+ if (permissionStatus == Qt::PermissionStatus::Undetermined) {
+ app.requestPermission(QBluetoothPermission{},
+ [&permissionStatus](const QPermission &permission) {
+ qApp->exit(); // Exit the permission request processing started below
+ permissionStatus = permission.status();
+ });
+ // Process permission request
+ app.exec();
+ }
+ if (permissionStatus == Qt::PermissionStatus::Denied) {
+ qWarning("Bluetooth permission denied, exiting");
+ return -1;
+ }
+#endif
+
+ // prepare list of services
+ QList<QLowEnergyServiceData> serviceDefinitions;
+
+ int connectioncount = 0;
+ {
+ // connection count service
+ QLowEnergyServiceData serviceData;
+ serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
+ serviceData.setUuid(QBluetoothUuid(connectionCountServiceUuid));
+
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(connectionCountCharUuid));
+ size_t size = sizeof(int);
+ QByteArray initialValue(size, 0);
+ charData.setValue(initialValue);
+ charData.setValueLength(size, size);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read);
+
+ serviceData.addCharacteristic(charData);
+
+ serviceDefinitions << serviceData;
+ }
+
+ {
+ // mtu size service
+ QLowEnergyServiceData serviceData;
+ serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
+ serviceData.setUuid(QBluetoothUuid(mtuServiceUuid));
+
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(mtuCharUuid));
+ size_t size = sizeof(int);
+ int mtu = 23;
+ QByteArray initialValue((const char *)&mtu, sizeof(int));
+ charData.setValue(initialValue);
+ charData.setValueLength(size, size);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Notify);
+
+ serviceData.addCharacteristic(charData);
+
+ serviceDefinitions << serviceData;
+ }
+ {
+ // large attribute service
+ //
+ // This is a service offering a large characteristic and descriptor which can
+ // be read and written to
+ QLowEnergyServiceData serviceData;
+ serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
+ serviceData.setUuid(QBluetoothUuid(largeAttributeServiceUuid));
+
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(largeAttributeCharUuid));
+ QByteArray initialValue(largeAttributeSize, 0);
+ initialValue[0] = 0x0b;
+ charData.setValue(initialValue);
+ charData.setValueLength(largeAttributeSize, largeAttributeSize);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Write);
+
+
+ QByteArray descInitialValue(largeAttributeSize, 0);
+ descInitialValue[0] = 0xdd;
+ QLowEnergyDescriptorData descData(
+ QBluetoothUuid{largeAttributeDescUuid},
+ descInitialValue
+ );
+ descData.setWritePermissions(true);
+ descData.setReadPermissions(true);
+
+ charData.addDescriptor(descData);
+
+ serviceData.addCharacteristic(charData);
+ serviceDefinitions << serviceData;
+ }
+
+ {
+
+ // notification service
+ //
+ // This is a service which offers:
+ // - one characteristic which does not support notification or indication
+ // - one characteristic which does only support notification
+ // - one characteristic which does only support indication
+ // - one characteristic which supports both notification or indication
+ // to test their discovery
+ QLowEnergyServiceData serviceData;
+
+ serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
+ serviceData.setUuid(QBluetoothUuid(notificationIndicationTestServiceUuid));
+
+ {
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(notificationIndicationTestChar1Uuid));
+ QByteArray initialValue(8, 0);
+ initialValue[0] = 0x0b;
+ charData.setValue(initialValue);
+ charData.setValueLength(8, 8);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read);
+
+ serviceData.addCharacteristic(charData);
+ }
+ {
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(notificationIndicationTestChar2Uuid));
+ QByteArray initialValue(8, 0);
+ initialValue[0] = 0x0b;
+ charData.setValue(initialValue);
+ charData.setValueLength(8, 8);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Notify);
+
+ const QLowEnergyDescriptorData clientConfig(
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration,
+ QLowEnergyCharacteristic::CCCDDisable);
+ charData.addDescriptor(clientConfig);
+
+ serviceData.addCharacteristic(charData);
+ }
+ {
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(notificationIndicationTestChar3Uuid));
+ QByteArray initialValue(8, 0);
+ initialValue[0] = 0x0b;
+ charData.setValue(initialValue);
+ charData.setValueLength(8, 8);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Indicate);
+
+ const QLowEnergyDescriptorData clientConfig(
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration,
+ QLowEnergyCharacteristic::CCCDDisable);
+ charData.addDescriptor(clientConfig);
+
+ serviceData.addCharacteristic(charData);
+ }
+ {
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(notificationIndicationTestChar4Uuid));
+ QByteArray initialValue(8, 0);
+ initialValue[0] = 0x0b;
+ charData.setValue(initialValue);
+ charData.setValueLength(8, 8);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Notify
+ | QLowEnergyCharacteristic::PropertyType::Indicate);
+
+ const QLowEnergyDescriptorData clientConfig(
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration,
+ QLowEnergyCharacteristic::CCCDDisable);
+ charData.addDescriptor(clientConfig);
+
+ serviceData.addCharacteristic(charData);
+ }
+
+ serviceDefinitions << serviceData;
+ }
+
+ {
+ // server's platform identifier service
+ QLowEnergyServiceData serviceData;
+ serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
+ serviceData.setUuid(QBluetoothUuid(platformIdentifierServiceUuid));
+
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(platformIdentifierCharUuid));
+#if defined(Q_OS_ANDROID)
+ QByteArray platformIdentifier("android");
+#elif defined(QT_OS_WIN)
+ QByteArray platformIdentifier("windows");
+#elif defined(Q_OS_DARWIN)
+ QByteArray platformIdentifier("darwin");
+#elif defined(Q_OS_LINUX)
+ QByteArray platformIdentifier("linux");
+#else
+ QByteArray platformIdentifier("unspecified");
+#endif
+ qDebug() << "Server will report it is running on: " << platformIdentifier;
+ charData.setValue(platformIdentifier);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read);
+
+ serviceData.addCharacteristic(charData);
+
+ serviceDefinitions << serviceData;
+ }
+
+ {
+ // repeated characteristic write service
+ //
+ // This service offers an 8 bytes large characteristic which can
+ // be read and written. Once the value is updated, it writes the
+ // same value to the other characteristic, which notifies the client
+ // about its change. This way we can make sure that all write were
+ // successful and happened in the right order.
+ // We can't use one characteristics for writing and notification,
+ // because on most backends when the characteristics was written
+ // by the client, there will be no notification about it.
+ QLowEnergyServiceData serviceData;
+ serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
+ serviceData.setUuid(QBluetoothUuid(repeatedWriteServiceUuid));
+
+ {
+ // The characteristics to be written by the client.
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(repeatedWriteTargetCharUuid));
+ QByteArray initialValue(8, 0);
+ charData.setValue(initialValue);
+ charData.setValueLength(8, 8);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Write);
+
+ serviceData.addCharacteristic(charData);
+ }
+ {
+ // The characteristics written by the server,
+ // it will send notifications to the client.
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(repeatedWriteNotifyCharUuid));
+ QByteArray initialValue(8, 0);
+ charData.setValue(initialValue);
+ charData.setValueLength(8, 8);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Write
+ | QLowEnergyCharacteristic::PropertyType::Notify);
+
+ const QLowEnergyDescriptorData clientConfig(
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration,
+ QLowEnergyCharacteristic::CCCDDisable);
+ charData.addDescriptor(clientConfig);
+
+ serviceData.addCharacteristic(charData);
+ }
+
+ serviceDefinitions << serviceData;
+ }
+
+#ifndef Q_OS_IOS
+ auto localAdapters = QBluetoothLocalDevice::allDevices();
+ if (localAdapters.isEmpty()) {
+ qWarning() << "Bluetoothtestdevice did not find a local adapter";
+ return EXIT_FAILURE;
+ }
+ QBluetoothLocalDevice adapter(localAdapters.back().address());
+ adapter.setHostMode(QBluetoothLocalDevice::HostDiscoverable);
+#endif // Q_OS_IOS
+
+ // Advertising data
+ QLowEnergyAdvertisingData advertisingData;
+ advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral);
+ advertisingData.setIncludePowerLevel(true);
+ advertisingData.setLocalName("BluetoothTestDevice");
+ QList<QBluetoothUuid> serviceUuids;
+ for (const auto &serviceData : serviceDefinitions) {
+ serviceUuids << serviceData.uuid();
+ }
+ // leads to too large advertising data
+ // advertisingData.setServices(serviceUuids);
+
+ // start advertising
+#ifndef Q_OS_IOS
+ auto devices = QBluetoothLocalDevice::allDevices();
+ qDebug() << "advertising on" << devices.back().address();
+ const QScopedPointer<QLowEnergyController> leController(
+ QLowEnergyController::createPeripheral(devices.back().address()));
+#else
+ const QScopedPointer<QLowEnergyController> leController(
+ QLowEnergyController::createPeripheral());
+#endif // Q_OS_IOS
+
+ QObject::connect(leController.data(), &QLowEnergyController::errorOccurred,
+ [](QLowEnergyController::Error error) {
+ qDebug() << "Bluetoothtestdevice QLowEnergyController errorOccurred:" << error;
+ });
+
+ QObject::connect(leController.data(), &QLowEnergyController::stateChanged,
+ [](QLowEnergyController::ControllerState state) {
+ qDebug() << "Bluetoothtestdevice QLowEnergyController stateChanged:" << state;
+ });
+
+
+ QList<QSharedPointer<QLowEnergyService>> services;
+
+ for (const auto &serviceData : serviceDefinitions) {
+ services.emplaceBack(leController->addService(serviceData));
+ }
+
+ establishNotifyOnWriteConnection(services[5].get());
+
+ leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData,
+ advertisingData);
+
+
+ auto reconnect = [&connectioncount, &leController, advertisingData, &services, serviceDefinitions]() {
+ connectioncount++;
+ for (qsizetype i = 0; i < services.size(); ++i) {
+ services[i].reset(leController->addService(serviceDefinitions[i]));
+ }
+
+ establishNotifyOnWriteConnection(services[5].get());
+
+ {
+ // set connection counter
+ Q_ASSERT(services[0]->serviceUuid()
+ == QBluetoothUuid(connectionCountServiceUuid));
+ QByteArray value((const char *)&connectioncount, sizeof(int));
+ QLowEnergyCharacteristic characteristic = services[0]->characteristic(
+ QBluetoothUuid(connectionCountCharUuid));
+ Q_ASSERT(characteristic.isValid());
+ services[0]->writeCharacteristic(characteristic, value);
+ }
+
+ bool allValid = true;
+ for (const auto &service : services) {
+ allValid = allValid & !service.isNull();
+ }
+
+ if (allValid){
+ leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData,
+ advertisingData);
+ qDebug() << "starting advertising for " << connectioncount << "th time.";
+ }
+ else
+ qDebug() << "Cannot start advertising: Service not valid.";
+ };
+ QObject::connect(leController.data(), &QLowEnergyController::disconnected, reconnect);
+
+ QObject::connect(leController.data(), &QLowEnergyController::mtuChanged, [&services](int mtu) {
+ qDebug() << "MTU changed, callback called.";
+ Q_ASSERT(services[1]->serviceUuid() == QBluetoothUuid(mtuServiceUuid));
+ QByteArray value((const char *)&mtu, sizeof(int));
+ QLowEnergyCharacteristic characteristic =
+ services[1]->characteristic(QBluetoothUuid(mtuCharUuid));
+ Q_ASSERT(characteristic.isValid());
+ services[1]->writeCharacteristic(characteristic, value);
+ });
+
+ QTimer notificationTestTimer;
+ quint64 currentCharacteristicValue = 0;
+ const auto characteristicChanger = [&services, &currentCharacteristicValue]() {
+ QByteArray value((const char *)&currentCharacteristicValue, 8);
+
+ Q_ASSERT(services[3]->serviceUuid()
+ == QBluetoothUuid(notificationIndicationTestServiceUuid));
+ {
+ QLowEnergyCharacteristic characteristic = services[3]->characteristic(
+ QBluetoothUuid(notificationIndicationTestChar2Uuid));
+ Q_ASSERT(characteristic.isValid());
+ services[3]->writeCharacteristic(characteristic,
+ value); // Potentially causes notification.
+ }
+ {
+ QLowEnergyCharacteristic characteristic = services[3]->characteristic(
+ QBluetoothUuid(notificationIndicationTestChar3Uuid));
+ Q_ASSERT(characteristic.isValid());
+ services[3]->writeCharacteristic(characteristic,
+ value); // Potentially causes notification.
+ }
+ {
+ QLowEnergyCharacteristic characteristic = services[3]->characteristic(
+ QBluetoothUuid(notificationIndicationTestChar4Uuid));
+ Q_ASSERT(characteristic.isValid());
+ services[3]->writeCharacteristic(characteristic,
+ value); // Potentially causes notification.
+ }
+
+ ++currentCharacteristicValue;
+ };
+ QObject::connect(&notificationTestTimer, &QTimer::timeout, characteristicChanger);
+ notificationTestTimer.start(100);
+
+ return app.exec();
+}
diff --git a/tests/bttestui/Button.qml b/tests/bttestui/Button.qml
index a358e37e..004aca70 100644
--- a/tests/bttestui/Button.qml
+++ b/tests/bttestui/Button.qml
@@ -1,32 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-import QtQuick 2.0
+import QtQuick
Rectangle
{
diff --git a/tests/bttestui/CMakeLists.txt b/tests/bttestui/CMakeLists.txt
new file mode 100644
index 00000000..4daee3df
--- /dev/null
+++ b/tests/bttestui/CMakeLists.txt
@@ -0,0 +1,89 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## bttestui Binary:
+#####################################################################
+
+cmake_minimum_required(VERSION 3.16...3.21)
+
+# Resources:
+set(bttest_resource_files
+ "Button.qml"
+ "main.qml"
+)
+
+if(NOT TARGET Qt::Bluetooth)
+ # for standalone build
+ project(bttestui LANGUAGES CXX)
+
+ set(CMAKE_AUTOMOC ON)
+
+ find_package(Qt6 REQUIRED COMPONENTS Bluetooth Core Gui Quick)
+
+ qt_add_executable(bttestui
+ btlocaldevice.cpp btlocaldevice.h
+ main.cpp
+ )
+
+ target_link_libraries(bttestui PUBLIC
+ Qt::Bluetooth
+ Qt::Gui
+ Qt::Quick
+ )
+
+ qt_add_resources(bttestui "bttest"
+ PREFIX
+ "/"
+ FILES
+ ${bttest_resource_files}
+ )
+else()
+ # in-tree build
+ qt_internal_add_executable(bttestui
+ GUI
+ SOURCES
+ btlocaldevice.cpp btlocaldevice.h
+ main.cpp
+ LIBRARIES
+ Qt::Bluetooth
+ Qt::Gui
+ Qt::Quick
+ )
+
+ qt_internal_add_resource(bttestui "bttest"
+ PREFIX
+ "/"
+ FILES
+ ${bttest_resource_files}
+ )
+
+ if(MACOS)
+ # Explicitly link against the static permission plugin because tests
+ # currently don't have finalizers run for them except for iOS.
+ # TODO: Remove this when qtbase automatically runs finalizers for tests: QTBUG-112212
+ target_link_libraries(bttestui PRIVATE Qt6::QDarwinBluetoothPermissionPlugin)
+ endif()
+
+endif()
+
+set_target_properties(bttestui PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+if(APPLE)
+ # Ninja has trouble with relative paths, convert to absolute as a workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../shared ABSOLUTE)
+ if(IOS)
+ set_target_properties(bttestui PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.ios.plist"
+ )
+ else()
+ set_target_properties(bttestui PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.macos.plist"
+ )
+ endif()
+endif()
+
+
diff --git a/tests/bttestui/btlocaldevice.cpp b/tests/bttestui/btlocaldevice.cpp
index 55b99fc3..19e78bb3 100644
--- a/tests/bttestui/btlocaldevice.cpp
+++ b/tests/bttestui/btlocaldevice.cpp
@@ -1,38 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "btlocaldevice.h"
+#include <QCoreApplication>
#include <QDebug>
#include <QTimer>
-#ifdef Q_OS_ANDROID
-#include <QtAndroidExtras/QtAndroid>
-#endif
#include <QtBluetooth/QBluetoothServiceInfo>
+#include <QtBluetooth/QLowEnergyCharacteristicData>
+#include <QtBluetooth/QLowEnergyDescriptorData>
+#include <QtBluetooth/QLowEnergyAdvertisingParameters>
#define BTCHAT_DEVICE_ADDR "00:15:83:38:17:C3"
@@ -45,12 +21,80 @@
#define SOCKET_PROTOCOL QBluetoothServiceInfo::RfcommProtocol
//#define SOCKET_PROTOCOL QBluetoothServiceInfo::L2capProtocol
-BtLocalDevice::BtLocalDevice(QObject *parent) :
- QObject(parent), securityFlags(QBluetooth::NoSecurity)
+using namespace Qt::Literals::StringLiterals;
+// Main service used for testing read/write/notify
+static constexpr auto leServiceUuid{"10f5e37c-ac16-11eb-ae5c-93d3a763feed"_L1};
+static constexpr auto leCharUuid1{"11f4f68e-ac16-11eb-9956-cfe55a8ccafe"_L1};
+static constexpr auto leCharUuid2{"12f4f68e-ac16-11eb-9956-cfe55a8ccafe"_L1};
+// Service for testing the included services
+static constexpr auto leSecondServiceUuid{"20f5e37c-ac16-11eb-ae5c-93d3a763feed"_L1};
+static constexpr auto leSecondServiceCharUuid1{"21f4f68e-ac16-11eb-9956-cfe55a8ccafe"_L1};
+// Service for testing the secondary service and other miscellaneous
+static constexpr auto leThirdServiceUuid{"30f5e37c-ac16-11eb-ae5c-93d3a763feed"_L1};
+static constexpr auto leThirdServiceCharUuid1{"31f4f68e-ac16-11eb-9956-cfe55a8ccafe"_L1};
+
+// Used for finding a matching LE peripheral device. Typically the default BtTestUi is ok
+// when running against macOS/iOS/Linux peripheral, but with Android this needs to be adjusted
+// to device's name. We can't use bluetooth address for matching as the public address of the
+// peripheral may change
+static const auto leRemotePeriphreralDeviceName = "BtTestUi"_L1;
+static const qsizetype leCharacteristicSize = 4; // Set to 1...512 bytes
+static QByteArray leCharacteristicValue = QByteArray{leCharacteristicSize, 1};
+static QByteArray leDescriptorValue = "a descriptor value"_ba;
+static auto leSecondCharacteristicValue = QByteArray{leCharacteristicSize, 2};
+static quint8 leCharacteristicValueUpdate = 1;
+static char leDescriptorValueUpdate = 'b';
+
+// String tables to shorten the enum strings to fit the screen estate.
+// The values in the tables must be in same order as the corresponding enums
+static constexpr const char* controllerStateString[] = {
+ "Unconnected",
+ "Connecting",
+ "Connected",
+ "Discovering",
+ "Discovered",
+ "Closing",
+ "Advertising",
+};
+
+static constexpr const char* controllerErrorString[] = {
+ "None",
+ "UnknownError",
+ "UnknownRemDev",
+ "NetworkError",
+ "InvAdapter",
+ "ConnectionErr",
+ "AdvertisingErr",
+ "RemHostClosed",
+ "AuthError",
+ "MissingPerm",
+ "RssiError"
+};
+
+static constexpr const char* serviceStateString[] = {
+ "InvalidService",
+ "RemoteService",
+ "RemDiscovering",
+ "RemDiscovered",
+ "LocalService",
+};
+
+static constexpr const char* serviceErrorString[] = {
+ "None",
+ "Operation",
+ "CharWrite",
+ "DescWrite",
+ "Unknown",
+ "CharRead",
+ "DescRead",
+};
+
+BtLocalDevice::BtLocalDevice(QObject *parent)
+ : QObject(parent), securityFlags(QBluetooth::Security::NoSecurity)
{
localDevice = new QBluetoothLocalDevice(this);
- connect(localDevice, &QBluetoothLocalDevice::error,
- this, &BtLocalDevice::error);
+ connect(localDevice, &QBluetoothLocalDevice::errorOccurred, this,
+ &BtLocalDevice::errorOccurred);
connect(localDevice, &QBluetoothLocalDevice::hostModeStateChanged,
this, &BtLocalDevice::hostModeStateChanged);
connect(localDevice, &QBluetoothLocalDevice::pairingFinished,
@@ -59,19 +103,17 @@ BtLocalDevice::BtLocalDevice(QObject *parent) :
this, &BtLocalDevice::connected);
connect(localDevice, &QBluetoothLocalDevice::deviceDisconnected,
this, &BtLocalDevice::disconnected);
- connect(localDevice, &QBluetoothLocalDevice::pairingDisplayConfirmation,
- this, &BtLocalDevice::pairingDisplayConfirmation);
- connect(localDevice, &QBluetoothLocalDevice::pairingDisplayPinCode,
- this, &BtLocalDevice::pairingDisplayPinCode);
if (localDevice->isValid()) {
deviceAgent = new QBluetoothDeviceDiscoveryAgent(this);
connect(deviceAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
this, &BtLocalDevice::deviceDiscovered);
+ connect(deviceAgent, &QBluetoothDeviceDiscoveryAgent::deviceUpdated,
+ this, &BtLocalDevice::deviceUpdated);
connect(deviceAgent, &QBluetoothDeviceDiscoveryAgent::finished,
this, &BtLocalDevice::discoveryFinished);
- connect(deviceAgent, QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error),
- this, &BtLocalDevice::discoveryError);
+ connect(deviceAgent, &QBluetoothDeviceDiscoveryAgent::errorOccurred, this,
+ &BtLocalDevice::discoveryError);
connect(deviceAgent, &QBluetoothDeviceDiscoveryAgent::canceled,
this, &BtLocalDevice::discoveryCanceled);
@@ -82,14 +124,13 @@ BtLocalDevice::BtLocalDevice(QObject *parent) :
this, &BtLocalDevice::serviceDiscoveryFinished);
connect(serviceAgent, &QBluetoothServiceDiscoveryAgent::canceled,
this, &BtLocalDevice::serviceDiscoveryCanceled);
- connect(serviceAgent, QOverload<QBluetoothServiceDiscoveryAgent::Error>::of(&QBluetoothServiceDiscoveryAgent::error),
- this, &BtLocalDevice::serviceDiscoveryError);
+ connect(serviceAgent, &QBluetoothServiceDiscoveryAgent::errorOccurred, this,
+ &BtLocalDevice::serviceDiscoveryError);
socket = new QBluetoothSocket(SOCKET_PROTOCOL, this);
connect(socket, &QBluetoothSocket::stateChanged,
this, &BtLocalDevice::socketStateChanged);
- connect(socket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error),
- this, &BtLocalDevice::socketError);
+ connect(socket, &QBluetoothSocket::errorOccurred, this, &BtLocalDevice::socketError);
connect(socket, &QBluetoothSocket::connected, this, &BtLocalDevice::socketConnected);
connect(socket, &QBluetoothSocket::disconnected, this, &BtLocalDevice::socketDisconnected);
connect(socket, &QIODevice::readyRead, this, &BtLocalDevice::readData);
@@ -100,13 +141,7 @@ BtLocalDevice::BtLocalDevice(QObject *parent) :
server = new QBluetoothServer(SOCKET_PROTOCOL, this);
connect(server, &QBluetoothServer::newConnection, this, &BtLocalDevice::serverNewConnection);
- connect(server, QOverload<QBluetoothServer::Error>::of(&QBluetoothServer::error),
- this, &BtLocalDevice::serverError);
- } else {
- deviceAgent = nullptr;
- serviceAgent = nullptr;
- socket = nullptr;
- server = nullptr;
+ connect(server, &QBluetoothServer::errorOccurred, this, &BtLocalDevice::serverError);
}
}
@@ -120,9 +155,9 @@ BtLocalDevice::~BtLocalDevice()
}
}
-int BtLocalDevice::secFlags() const
+QBluetooth::SecurityFlags BtLocalDevice::secFlags() const
{
- return static_cast<int>(securityFlags);
+ return securityFlags;
}
void BtLocalDevice::setSecFlags(int newFlags)
@@ -137,15 +172,17 @@ void BtLocalDevice::setSecFlags(int newFlags)
QString BtLocalDevice::hostMode() const
{
- switch (localDevice->hostMode()) {
- case QBluetoothLocalDevice::HostDiscoverable:
- return QStringLiteral("HostMode: Discoverable");
- case QBluetoothLocalDevice::HostConnectable:
- return QStringLiteral("HostMode: Connectable");
- case QBluetoothLocalDevice::HostDiscoverableLimitedInquiry:
- return QStringLiteral("HostMode: DiscoverableLimit");
- case QBluetoothLocalDevice::HostPoweredOff:
- return QStringLiteral("HostMode: Powered Off");
+ if (localDevice) {
+ switch (localDevice->hostMode()) {
+ case QBluetoothLocalDevice::HostDiscoverable:
+ return QStringLiteral("HostMode: Discoverable");
+ case QBluetoothLocalDevice::HostConnectable:
+ return QStringLiteral("HostMode: Connectable");
+ case QBluetoothLocalDevice::HostDiscoverableLimitedInquiry:
+ return QStringLiteral("HostMode: DiscoverableLimit");
+ case QBluetoothLocalDevice::HostPoweredOff:
+ return QStringLiteral("HostMode: Powered Off");
+ }
}
return QStringLiteral("HostMode: <None>");
@@ -153,17 +190,16 @@ QString BtLocalDevice::hostMode() const
void BtLocalDevice::setHostMode(int newMode)
{
- localDevice->setHostMode(static_cast<QBluetoothLocalDevice::HostMode>(newMode));
+ if (localDevice)
+ localDevice->setHostMode(static_cast<QBluetoothLocalDevice::HostMode>(newMode));
}
void BtLocalDevice::requestPairingUpdate(bool isPairing)
{
QBluetoothAddress baddr(BTCHAT_DEVICE_ADDR);
- if (baddr.isNull())
+ if (!localDevice || baddr.isNull())
return;
-
-
if (isPairing) {
//toggle between authorized and non-authorized pairing to achieve better
//level of testing
@@ -177,7 +213,7 @@ void BtLocalDevice::requestPairingUpdate(bool isPairing)
localDevice->requestPairing(baddr, QBluetoothLocalDevice::Unpaired);
}
- for (int i = 0; i < foundTestServers.count(); i++) {
+ for (qsizetype i = 0; i < foundTestServers.size(); ++i) {
if (isPairing)
localDevice->requestPairing(foundTestServers.at(i).device().address(),
QBluetoothLocalDevice::Paired);
@@ -202,37 +238,18 @@ void BtLocalDevice::disconnected(const QBluetoothAddress &addr)
qDebug() << "Newly disconnected device" << addr.toString();
}
-void BtLocalDevice::pairingDisplayConfirmation(const QBluetoothAddress &address, const QString &pin)
-{
- qDebug() << "PairingDisplayConfirmation" << address << pin;
- QTimer::singleShot(3000, this, SLOT(confirmPairing()));
-}
-
-void BtLocalDevice::pairingDisplayPinCode(const QBluetoothAddress &address, const QString &pin)
-{
- qDebug() << "PairingDisplayPinCode" << address << pin;
-}
-
-void BtLocalDevice::confirmPairing()
-{
- static bool confirm = false;
- confirm = !confirm; //toggle
- qDebug() << "######" << "Sending pairing confirmation: " << confirm;
- localDevice->pairingConfirmation(confirm);
-}
-
void BtLocalDevice::cycleSecurityFlags()
{
- if (securityFlags.testFlag(QBluetooth::Secure))
- setSecFlags(QBluetooth::NoSecurity);
- else if (securityFlags.testFlag(QBluetooth::Encryption))
- setSecFlags(secFlags() | QBluetooth::Secure);
- else if (securityFlags.testFlag(QBluetooth::Authentication))
- setSecFlags(secFlags() | QBluetooth::Encryption);
- else if (securityFlags.testFlag(QBluetooth::Authorization))
- setSecFlags(secFlags() | QBluetooth::Authentication);
+ if (securityFlags.testFlag(QBluetooth::Security::Secure))
+ setSecFlags(QBluetooth::SecurityFlags(QBluetooth::Security::NoSecurity));
+ else if (securityFlags.testFlag(QBluetooth::Security::Encryption))
+ setSecFlags(secFlags() | QBluetooth::Security::Secure);
+ else if (securityFlags.testFlag(QBluetooth::Security::Authentication))
+ setSecFlags(secFlags() | QBluetooth::Security::Encryption);
+ else if (securityFlags.testFlag(QBluetooth::Security::Authorization))
+ setSecFlags(secFlags() | QBluetooth::Security::Authentication);
else
- setSecFlags(secFlags() | QBluetooth::Authorization);
+ setSecFlags(secFlags() | QBluetooth::Security::Authorization);
}
void BtLocalDevice::deviceDiscovered(const QBluetoothDeviceInfo &info)
@@ -255,12 +272,29 @@ void BtLocalDevice::deviceDiscovered(const QBluetoothDeviceInfo &info)
if (info.serviceClasses() & QBluetoothDeviceInfo::InformationService)
services += "Information|";
- services.truncate(services.length()-1); //cut last '/'
+ services.truncate(services.size()-1); //cut last '/'
qDebug() << "Found new device: " << info.name() << info.isValid() << info.address().toString()
<< info.rssi() << info.majorDeviceClass()
<< info.minorDeviceClass() << services;
+ // With LE we match the device by its name as the public bluetooth address can change
+ if (info.name() == leRemotePeriphreralDeviceName) {
+ qDebug() << "#### Matching LE peripheral device found";
+ leRemotePeripheralDevice = info;
+ latestRSSI = QByteArray::number(info.rssi());
+ emit leChanged();
+ }
+}
+void BtLocalDevice::deviceUpdated(const QBluetoothDeviceInfo &info,
+ QBluetoothDeviceInfo::Fields updateFields)
+{
+ if (info.name() == leRemotePeriphreralDeviceName
+ && updateFields & QBluetoothDeviceInfo::Field::RSSI) {
+ qDebug() << "#### LE peripheral RSSI updated during scan";
+ latestRSSI = QByteArray::number(info.rssi());
+ emit leChanged();
+ }
}
void BtLocalDevice::discoveryFinished()
@@ -347,8 +381,8 @@ void BtLocalDevice::serviceDiscovered(const QBluetoothServiceInfo &info)
bool matchingService =
(info.serviceUuid() == QBluetoothUuid(QString(TEST_SERVICE_UUID)));
#ifdef Q_OS_ANDROID
- if (QtAndroid::androidSdkVersion() >= 23) //bug introduced by Android 6.0.1
- matchingService = matchingService
+ // QTBUG-61392
+ matchingService = matchingService
|| (info.serviceUuid() == QBluetoothUuid(QString(TEST_REVERSE_SERVICE_UUID)));
#endif
@@ -357,7 +391,7 @@ void BtLocalDevice::serviceDiscovered(const QBluetoothServiceInfo &info)
{
//This is here to detect the test server for SPP testing later on
bool alreadyKnown = false;
- for (const QBluetoothServiceInfo& found : qAsConst(foundTestServers)) {
+ for (const QBluetoothServiceInfo& found : std::as_const(foundTestServers)) {
if (found.device().address() == info.device().address()) {
alreadyKnown = true;
break;
@@ -395,7 +429,7 @@ void BtLocalDevice::dumpServiceDiscovery()
qDebug() << "Device Discovery active:" << deviceAgent->isActive();
qDebug() << "Error:" << deviceAgent->error() << deviceAgent->errorString();
const QList<QBluetoothDeviceInfo> list = deviceAgent->discoveredDevices();
- qDebug() << "Discovered Devices:" << list.count();
+ qDebug() << "Discovered Devices:" << list.size();
for (const QBluetoothDeviceInfo &info : list)
qDebug() << info.name() << info.address().toString() << info.rssi();
@@ -404,14 +438,14 @@ void BtLocalDevice::dumpServiceDiscovery()
qDebug() << "Service Discovery active:" << serviceAgent->isActive();
qDebug() << "Error:" << serviceAgent->error() << serviceAgent->errorString();
const QList<QBluetoothServiceInfo> list = serviceAgent->discoveredServices();
- qDebug() << "Discovered Services:" << list.count();
+ qDebug() << "Discovered Services:" << list.size();
for (const QBluetoothServiceInfo &i : list) {
qDebug() << i.device().address().toString() << i.device().name() << i.serviceName();
}
qDebug() << "###### TestServer offered by:";
- for (const QBluetoothServiceInfo& found : qAsConst(foundTestServers)) {
+ for (const QBluetoothServiceInfo& found : std::as_const(foundTestServers)) {
qDebug() << found.device().name() << found.device().address().toString();
}
}
@@ -514,13 +548,14 @@ void BtLocalDevice::dumpSocketInformation()
qDebug() << "socket bytesAvailable()" << socket->bytesAvailable();
QString tmp;
switch (socket->error()) {
- case QBluetoothSocket::NoSocketError: tmp += "NoSocketError"; break;
- case QBluetoothSocket::UnknownSocketError: tmp += "UnknownSocketError"; break;
- case QBluetoothSocket::HostNotFoundError: tmp += "HostNotFoundError"; break;
- case QBluetoothSocket::ServiceNotFoundError: tmp += "ServiceNotFound"; break;
- case QBluetoothSocket::NetworkError: tmp += "NetworkError"; break;
- //case QBluetoothSocket::OperationError: tmp+= "OperationError"; break;
- case QBluetoothSocket::UnsupportedProtocolError: tmp += "UnsupportedProtocolError"; break;
+ case QBluetoothSocket::SocketError::NoSocketError: tmp += "NoSocketError"; break;
+ case QBluetoothSocket::SocketError::UnknownSocketError: tmp += "UnknownSocketError"; break;
+ case QBluetoothSocket::SocketError::HostNotFoundError: tmp += "HostNotFoundError"; break;
+ case QBluetoothSocket::SocketError::ServiceNotFoundError: tmp += "ServiceNotFound"; break;
+ case QBluetoothSocket::SocketError::NetworkError: tmp += "NetworkError"; break;
+ //case QBluetoothSocket::SocketError::OperationError: tmp+= "OperationError"; break;
+ case QBluetoothSocket::SocketError::UnsupportedProtocolError: tmp += "UnsupportedProtocolError"; break;
+ case QBluetoothSocket::SocketError::MissingPermissionsError: tmp += "MissingPermissionsError"; break;
default: tmp+= "Undefined"; break;
}
@@ -533,7 +568,7 @@ void BtLocalDevice::dumpSocketInformation()
void BtLocalDevice::writeData()
{
const char * testData = "ABCABC\n";
- if (socket && socket->state() == QBluetoothSocket::ConnectedState) {
+ if (socket && socket->state() == QBluetoothSocket::SocketState::ConnectedState) {
socket->write(testData);
}
for (QBluetoothSocket* client : serverSockets) {
@@ -549,7 +584,7 @@ void BtLocalDevice::readData()
qDebug() << ">> peer(" << socket->peerName() << socket->peerAddress()
<< socket->peerPort() << ") local("
<< socket->localName() << socket->localAddress() << socket->localPort()
- << ")>>" << QString::fromUtf8(line.constData(), line.length());
+ << ")>>" << QString::fromUtf8(line.constData(), line.size());
}
}
}
@@ -581,7 +616,7 @@ void BtLocalDevice::serverListenPort()
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,
@@ -589,7 +624,7 @@ void BtLocalDevice::serverListenPort()
classId.clear();
classId << QVariant::fromValue(QBluetoothUuid(QString(TEST_SERVICE_UUID)));
- classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort));
+ classId << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
serviceInfo.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classId);
// Service name, description and provider
@@ -604,20 +639,20 @@ void BtLocalDevice::serverListenPort()
// Service Discoverability
QBluetoothServiceInfo::Sequence browseSequence;
- browseSequence << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup));
+ browseSequence << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::PublicBrowseGroup));
serviceInfo.setAttribute(QBluetoothServiceInfo::BrowseGroupList, browseSequence);
// Protocol descriptor list
QBluetoothServiceInfo::Sequence protocolDescriptorList;
QBluetoothServiceInfo::Sequence protocol;
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::L2cap));
if (server->serverType() == QBluetoothServiceInfo::L2capProtocol)
protocol << QVariant::fromValue(server->serverPort());
protocolDescriptorList.append(QVariant::fromValue(protocol));
if (server->serverType() == QBluetoothServiceInfo::RfcommProtocol) {
protocol.clear();
- protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::ProtocolUuid::Rfcomm))
<< QVariant::fromValue(quint8(server->serverPort()));
protocolDescriptorList.append(QVariant::fromValue(protocol));
}
@@ -682,8 +717,7 @@ void BtLocalDevice::serverNewConnection()
connect(client, &QIODevice::readyRead, this, &BtLocalDevice::clientSocketReadyRead);
connect(client, &QBluetoothSocket::stateChanged,
this, &BtLocalDevice::socketStateChanged);
- connect(client, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error),
- this, &BtLocalDevice::socketError);
+ connect(client, &QBluetoothSocket::errorOccurred, this, &BtLocalDevice::socketError);
connect(client, &QBluetoothSocket::connected, this, &BtLocalDevice::socketConnected);
connect(client, &QBluetoothSocket::bytesWritten, this, [](qint64 bytesWritten){
qDebug() << "Bytes Written to Server socket:" << bytesWritten;
@@ -712,7 +746,7 @@ void BtLocalDevice::clientSocketReadyRead()
while (socket->canReadLine()) {
const QByteArray line = socket->readLine().trimmed();
- QString lineString = QString::fromUtf8(line.constData(), line.length());
+ QString lineString = QString::fromUtf8(line.constData(), line.size());
qDebug() << ">>(" << server->serverAddress() << server->serverPort() <<")>>"
<< lineString;
@@ -729,7 +763,7 @@ void BtLocalDevice::clientSocketReadyRead()
void BtLocalDevice::dumpServerInformation()
{
- static QBluetooth::SecurityFlags secFlag = QBluetooth::Authentication;
+ static QBluetooth::SecurityFlags secFlag = QBluetooth::Security::Authentication;
if (server) {
qDebug() << "*******************************";
qDebug() << "server port:" <<server->serverPort()
@@ -740,14 +774,14 @@ void BtLocalDevice::dumpServerInformation()
<< "hasPending:" << server->hasPendingConnections()
<< "maxPending:" << server->maxPendingConnections();
qDebug() << "security:" << server->securityFlags() << "Togling security flag";
- if (secFlag == QBluetooth::Authentication)
- secFlag = QBluetooth::Encryption;
+ if (secFlag == QBluetooth::SecurityFlags(QBluetooth::Security::Authentication))
+ secFlag = QBluetooth::Security::Encryption;
else
- secFlag = QBluetooth::Authentication;
+ secFlag = QBluetooth::Security::Authentication;
//server->setSecurityFlags(secFlag);
- for (const QBluetoothSocket *client : qAsConst(serverSockets)) {
+ for (const QBluetoothSocket *client : std::as_const(serverSockets)) {
qDebug() << "##" << client->localAddress().toString()
<< client->localName() << client->localPort();
qDebug() << "##" << client->peerAddress().toString()
@@ -756,13 +790,14 @@ void BtLocalDevice::dumpServerInformation()
qDebug() << "Pending bytes: " << client->bytesAvailable();
QString tmp;
switch (client->error()) {
- case QBluetoothSocket::NoSocketError: tmp += "NoSocketError"; break;
- case QBluetoothSocket::UnknownSocketError: tmp += "UnknownSocketError"; break;
- case QBluetoothSocket::HostNotFoundError: tmp += "HostNotFoundError"; break;
- case QBluetoothSocket::ServiceNotFoundError: tmp += "ServiceNotFound"; break;
- case QBluetoothSocket::NetworkError: tmp += "NetworkError"; break;
- case QBluetoothSocket::UnsupportedProtocolError: tmp += "UnsupportedProtocolError"; break;
- //case QBluetoothSocket::OperationError: tmp+= "OperationError"; break;
+ case QBluetoothSocket::SocketError::NoSocketError: tmp += "NoSocketError"; break;
+ case QBluetoothSocket::SocketError::UnknownSocketError: tmp += "UnknownSocketError"; break;
+ case QBluetoothSocket::SocketError::HostNotFoundError: tmp += "HostNotFoundError"; break;
+ case QBluetoothSocket::SocketError::ServiceNotFoundError: tmp += "ServiceNotFound"; break;
+ case QBluetoothSocket::SocketError::NetworkError: tmp += "NetworkError"; break;
+ case QBluetoothSocket::SocketError::UnsupportedProtocolError: tmp += "UnsupportedProtocolError"; break;
+ //case QBluetoothSocket::SocketError::OperationError: tmp+= "OperationError"; break;
+ case QBluetoothSocket::SocketError::MissingPermissionsError: tmp += "MissingPermissionsError"; break;
default: tmp += QString::number(static_cast<int>(client->error())); break;
}
@@ -771,12 +806,36 @@ void BtLocalDevice::dumpServerInformation()
}
}
+template <typename T>
+void printError(const QLatin1StringView name, T* ptr)
+{
+ if (!ptr)
+ return;
+ qDebug() << name << "error:" << ptr->error();
+}
+
+void BtLocalDevice::dumpErrors()
+{
+ qDebug() << "###### Errors";
+ printError("Device agent"_L1, deviceAgent);
+ printError("Service agent"_L1, serviceAgent);
+ printError("LE Central"_L1, leCentralController.get());
+ printError("LE Central Service"_L1, leCentralService.get());
+ printError("LE Peripheral"_L1, lePeripheralController.get());
+ if (!lePeripheralServices.isEmpty())
+ printError("LE Peripheral Service"_L1, lePeripheralServices[0].get());
+ printError("Socket"_L1, socket);
+ printError("Server"_L1, server);
+}
+
void BtLocalDevice::dumpInformation()
{
+ if (!localDevice)
+ return;
qDebug() << "###### default local device";
dumpLocalDevice(localDevice);
const QList<QBluetoothHostInfo> list = QBluetoothLocalDevice::allDevices();
- qDebug() << "Found local devices: " << list.count();
+ qDebug() << "Found local devices: " << list.size();
for (const QBluetoothHostInfo &info : list) {
qDebug() << " " << info.address().toString() << " " <<info.name();
}
@@ -826,17 +885,21 @@ void BtLocalDevice::dumpInformation()
QBluetoothServiceDiscoveryAgent validSAgent(localDevice->address());
validSAgent.start();
qDebug() << "######" << (validSAgent.error() == QBluetoothServiceDiscoveryAgent::NoError) << "(Expected: true)";
+
+ dumpLeInfo();
}
void BtLocalDevice::powerOn()
{
+ if (!localDevice)
+ return;
qDebug() << "Powering on";
localDevice->powerOn();
}
void BtLocalDevice::reset()
{
- emit error(static_cast<QBluetoothLocalDevice::Error>(1000));
+ emit errorOccurred(static_cast<QBluetoothLocalDevice::Error>(1000));
if (serviceAgent) {
serviceAgent->clear();
}
@@ -850,3 +913,682 @@ void BtLocalDevice::dumpLocalDevice(QBluetoothLocalDevice *dev)
qDebug() << " Address" << dev->address().toString();
qDebug() << " HostMode" << dev->hostMode();
}
+
+void BtLocalDevice::peripheralCreate()
+{
+ qDebug() << "######" << "LE create peripheral";
+ if (lePeripheralController) {
+ qDebug() << "Peripheral already existed";
+ return;
+ }
+
+ lePeripheralController.reset(QLowEnergyController::createPeripheral());
+ emit leChanged();
+
+ QObject::connect(lePeripheralController.get(), &QLowEnergyController::errorOccurred,
+ [this](QLowEnergyController::Error error) {
+ qDebug() << "QLowEnergyController peripheral errorOccurred:" << error;
+ emit leChanged();
+ });
+ QObject::connect(lePeripheralController.get(), &QLowEnergyController::stateChanged,
+ [this](QLowEnergyController::ControllerState state) {
+ qDebug() << "QLowEnergyController peripheral stateChanged:" << state;
+ emit leChanged();
+ });
+}
+
+void BtLocalDevice::peripheralAddServices()
+{
+ qDebug() << "######" << "LE add services";
+ if (!lePeripheralController) {
+ qDebug() << "Create peripheral first";
+ return;
+ }
+ if (lePeripheralServiceData.isEmpty()) {
+ // Create service data
+ {
+ QLowEnergyServiceData sd;
+ sd.setType(QLowEnergyServiceData::ServiceTypePrimary);
+ sd.setUuid(QBluetoothUuid(leServiceUuid));
+
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(leCharUuid1));
+ charData.setValue(leCharacteristicValue);
+ charData.setValueLength(leCharacteristicSize, leCharacteristicSize);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Write
+ | QLowEnergyCharacteristic::PropertyType::Notify
+ | QLowEnergyCharacteristic::ExtendedProperty);
+
+ const QLowEnergyDescriptorData clientConfig(
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration,
+ QLowEnergyCharacteristic::CCCDDisable);
+ charData.addDescriptor(clientConfig);
+
+ const QLowEnergyDescriptorData userDescription(
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription,
+ leDescriptorValue);
+ charData.addDescriptor(userDescription);
+
+ const QLowEnergyDescriptorData extendedProperties(
+ QBluetoothUuid::DescriptorType::CharacteristicExtendedProperties,
+ // From bluetooth specs: length 2 bytes
+ // bit 0: reliable write, bit 1: writable auxiliaries
+ QByteArray::fromHex("0300"));
+ charData.addDescriptor(extendedProperties);
+
+ sd.addCharacteristic(charData);
+
+ // Set another characteristic without notifications
+ QLowEnergyCharacteristicData secondCharData;
+ secondCharData.setUuid(QBluetoothUuid(leCharUuid2));
+ secondCharData.setValue(leSecondCharacteristicValue);
+ secondCharData.setValueLength(leCharacteristicSize, leCharacteristicSize);
+ secondCharData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Write);
+ sd.addCharacteristic(secondCharData);
+ lePeripheralServiceData << sd;
+ }
+ {
+ QLowEnergyServiceData sd;
+ sd.setType(QLowEnergyServiceData::ServiceTypePrimary);
+ sd.setUuid(QBluetoothUuid(leSecondServiceUuid));
+
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(leSecondServiceCharUuid1));
+ charData.setValue("second service char"_ba);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read);
+ sd.addCharacteristic(charData);
+ lePeripheralServiceData << sd;
+ }
+ {
+ QLowEnergyServiceData sd;
+ sd.setType(QLowEnergyServiceData::ServiceTypeSecondary);
+ sd.setUuid(QBluetoothUuid(leThirdServiceUuid));
+
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(leThirdServiceCharUuid1));
+ charData.setValue("third service char"_ba);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read);
+ sd.addCharacteristic(charData);
+ lePeripheralServiceData << sd;
+ }
+ }
+
+ Q_ASSERT(lePeripheralServiceData.size() == 3);
+ // Free previous services if any
+ lePeripheralServices.clear();
+ // Add first service, and then set the first service as the included service for the second
+ auto service = lePeripheralController->addService(lePeripheralServiceData[0]);
+ if (service) {
+ lePeripheralServiceData[1].setIncludedServices({service});
+ // Then add the services to controller
+ lePeripheralServices.emplaceBack(service);
+ lePeripheralServices.emplaceBack(
+ lePeripheralController->addService(lePeripheralServiceData[1]));
+ lePeripheralServices.emplaceBack(
+ lePeripheralController->addService(lePeripheralServiceData[2]));
+ }
+
+ emit leChanged();
+
+ if (lePeripheralServices.isEmpty()) {
+ qDebug() << "Peripheral service creation failed";
+ return;
+ }
+
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::characteristicWritten,
+ [](const QLowEnergyCharacteristic&, const QByteArray& value){
+ qDebug() << "LE peripheral service characteristic value written" << value;
+ });
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::characteristicRead,
+ [](const QLowEnergyCharacteristic&, const QByteArray& value){
+ qDebug() << "LE peripheral service characteristic value read" << value;
+ });
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::characteristicChanged,
+ [](const QLowEnergyCharacteristic&, const QByteArray& value){
+ qDebug() << "LE peripheral service characteristic value changed" << value;
+ });
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::descriptorRead,
+ [](const QLowEnergyDescriptor&, const QByteArray& value){
+ qDebug() << "LE peripheral service descriptor value read" << value;
+ });
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::descriptorWritten,
+ [](const QLowEnergyDescriptor&, const QByteArray& value){
+ qDebug() << "LE peripheral service descriptor value written" << value;
+ });
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::errorOccurred,
+ [this](QLowEnergyService::ServiceError error){
+ qDebug() << "LE peripheral service errorOccurred:" << error;
+ emit leChanged();
+ });
+ QObject::connect(lePeripheralServices[0].get(), &QLowEnergyService::stateChanged,
+ [this](QLowEnergyService::ServiceState state){
+ qDebug() << "LE peripheral service state changed:" << state;
+ emit leChanged();
+ });
+}
+
+void BtLocalDevice::peripheralStartAdvertising()
+{
+ qDebug() << "######" << "LE start advertising";
+ if (!lePeripheralController) {
+ qDebug() << "Create peripheral first";
+ return;
+ }
+
+ if (leAdvertisingData.localName().isEmpty()) {
+ // Create advertisement data
+ leAdvertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral);
+ leAdvertisingData.setIncludePowerLevel(true);
+ leAdvertisingData.setLocalName(leRemotePeriphreralDeviceName);
+
+ leAdvertisingData.setManufacturerData(0xCAFE, "maker");
+ // Here we use short unrelated UUID so we can fit both service UUID and manufacturer data
+ // into the advertisement. This is for testing purposes
+ leAdvertisingData.setServices(
+ {QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::AlertNotificationService)});
+ // May result in too big advertisement data, can be useful for testing such scenario
+ // leAdvertisingData.setServices({QBluetoothUuid(leServiceUuid)});
+ }
+ // Start advertising. For testing the advertising can be started without valid services
+ qDebug() << "Starting advertising, services are valid:" << !lePeripheralServiceData.isEmpty();
+ lePeripheralController->startAdvertising(QLowEnergyAdvertisingParameters{},
+ leAdvertisingData, leAdvertisingData);
+}
+
+void BtLocalDevice::peripheralStopAdvertising()
+{
+ qDebug() << "######" << "LE stop advertising";
+ if (!lePeripheralController) {
+ qDebug() << "Peripheral does not exist";
+ return;
+ }
+ lePeripheralController->stopAdvertising();
+}
+
+void BtLocalDevice::centralCharacteristicWrite()
+{
+ qDebug() << "######" << "LE central write characteristic";
+ if (!leCentralController || !leCentralService) {
+ qDebug() << "Central or central service does not exist";
+ return;
+ }
+ auto characteristic = leCentralService->characteristic(QBluetoothUuid(leCharUuid1));
+ if (characteristic.isValid()) {
+ // Update value at the beginning and end so we can check whole data is sent in large writes
+ // Value is offset'd with 100 to easily see which end did the write when testing
+ leCharacteristicValueUpdate += 1;
+ leCharacteristicValue[0] = leCharacteristicValueUpdate + 100;
+ leCharacteristicValue[leCharacteristicSize - 1] = leCharacteristicValueUpdate + 100;
+ qDebug() << " Central writes value:" << leCharacteristicValue;
+ leCentralService->writeCharacteristic(characteristic, leCharacteristicValue);
+ } else {
+ qDebug() << "Characteristic was invalid";
+ }
+}
+
+void BtLocalDevice::centralCharacteristicRead()
+{
+ qDebug() << "######" << "LE central read characteristic";
+ if (!leCentralController || !leCentralService) {
+ qDebug() << "Central or central service does not exist";
+ return;
+ }
+ auto characteristic = leCentralService->characteristic(QBluetoothUuid(leCharUuid1));
+ if (characteristic.isValid()) {
+ qDebug() << " Value before issuing read():" << characteristic.value();
+ leCentralService->readCharacteristic(characteristic);
+ } else {
+ qDebug() << "Characteristic was invalid";
+ }
+}
+
+void BtLocalDevice::centralDescriptorWrite()
+{
+ qDebug() << "######" << "LE central write descriptor";
+ if (!leCentralController || !leCentralService) {
+ qDebug() << "Central or central service does not exist";
+ return;
+ }
+ auto descriptor = leCentralService->characteristic(QBluetoothUuid(leCharUuid1))
+ .descriptor(QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
+
+ if (descriptor.isValid()) {
+ leDescriptorValue[0] = leDescriptorValueUpdate++;
+ qDebug() << " Central writes value: " << leDescriptorValue;
+ leCentralService->writeDescriptor(descriptor, leDescriptorValue);
+ } else {
+ qDebug() << "Descriptor was invalid";
+ }
+}
+
+void BtLocalDevice::centralDescriptorRead()
+{
+ qDebug() << "######" << "LE central read descriptor";
+ if (!leCentralController || !leCentralService) {
+ qDebug() << "Central or central service does not exist";
+ return;
+ }
+ auto descriptor = leCentralService->characteristic(QBluetoothUuid(leCharUuid1))
+ .descriptor(QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
+ if (descriptor.isValid()) {
+ qDebug() << " Value before issuing read():" << descriptor.value();
+ leCentralService->readDescriptor(descriptor);
+ } else {
+ qDebug() << "Descriptor was invalid";
+ }
+}
+
+
+void BtLocalDevice::peripheralCharacteristicWrite()
+{
+ qDebug() << "######" << "LE peripheral write characteristic";
+ if (!lePeripheralController || lePeripheralServices.isEmpty()) {
+ qDebug() << "Peripheral or peripheral service does not exist";
+ return;
+ }
+
+ auto characteristic = lePeripheralServices[0]->characteristic(QBluetoothUuid(leCharUuid1));
+ if (characteristic.isValid()) {
+ // Update value at the beginning and end so we can check whole data is sent in large writes
+ leCharacteristicValue[0] = ++leCharacteristicValueUpdate;
+ leCharacteristicValue[leCharacteristicSize - 1] = leCharacteristicValueUpdate;
+ qDebug() << " Peripheral writes value:" << leCharacteristicValue;
+ lePeripheralServices[0]->writeCharacteristic(characteristic, leCharacteristicValue);
+ } else {
+ qDebug() << "Characteristic was invalid";
+ }
+}
+
+void BtLocalDevice::peripheralCharacteristicRead()
+{
+ qDebug() << "######" << "LE peripheral read characteristic";
+ if (!lePeripheralController || lePeripheralServices.isEmpty()) {
+ qDebug() << "Peripheral or peripheral service does not exist";
+ return;
+ }
+ auto characteristic = lePeripheralServices[0]->characteristic(QBluetoothUuid(leCharUuid1));
+ if (characteristic.isValid())
+ qDebug() << " Value:" << characteristic.value();
+ else
+ qDebug() << "Characteristic was invalid";
+}
+
+void BtLocalDevice::peripheralDescriptorWrite()
+{
+ qDebug() << "######" << "LE peripheral write descriptor";
+ if (!lePeripheralController || lePeripheralServices.isEmpty()) {
+ qDebug() << "Peripheral or peripheral service does not exist";
+ return;
+ }
+ auto descriptor = lePeripheralServices[0]->characteristic(QBluetoothUuid(leCharUuid1))
+ .descriptor(QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
+
+ if (descriptor.isValid()) {
+ leDescriptorValue[0] = leDescriptorValueUpdate++;
+ qDebug() << " Peripheral writes value: " << leDescriptorValue;
+ lePeripheralServices[0]->writeDescriptor(descriptor, leDescriptorValue);
+ } else {
+ qDebug() << "Descriptor was invalid";
+ }
+}
+
+void BtLocalDevice::peripheralDescriptorRead()
+{
+ qDebug() << "######" << "LE peripheral read descriptor";
+ if (!lePeripheralController || lePeripheralServices.isEmpty()) {
+ qDebug() << "Peripheral or peripheral service does not exist";
+ return;
+ }
+ auto descriptor = lePeripheralServices[0]->characteristic(QBluetoothUuid(leCharUuid1))
+ .descriptor(QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
+ if (descriptor.isValid())
+ qDebug() << " Value:" << descriptor.value();
+ else
+ qDebug() << "Descriptor was invalid";
+}
+
+void BtLocalDevice::startLeDeviceDiscovery()
+{
+ qDebug() << "######" << "LE device discovery start for:" << leRemotePeriphreralDeviceName;
+ if (deviceAgent)
+ deviceAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
+}
+
+void BtLocalDevice::centralStartServiceDiscovery()
+{
+ qDebug() << "######" << "LE service discovery start";
+ if (!leCentralController) {
+ qDebug() << "Create and connect central first";
+ return;
+ }
+ leCentralController->discoverServices();
+}
+
+void BtLocalDevice::centralCreate()
+{
+ qDebug() << "######" << "Central create";
+ if (leCentralController) {
+ qDebug() << "Central already existed";
+ return;
+ }
+
+ if (!leRemotePeripheralDevice.isValid()) {
+ qDebug() << "Creation failed, needs successful LE device discovery first";
+ return;
+ }
+
+ if (deviceAgent && deviceAgent->isActive()) {
+ qDebug() << "###### Stopping device discovery agent";
+ deviceAgent->stop();
+ }
+
+ leCentralController.reset(QLowEnergyController::createCentral(leRemotePeripheralDevice));
+ emit leChanged();
+
+ if (!leCentralController) {
+ qDebug() << "LE Central creation failed";
+ return;
+ }
+
+ QObject::connect(leCentralController.get(), &QLowEnergyController::errorOccurred,
+ [](QLowEnergyController::Error error) {
+ qDebug() << "QLowEnergyController central errorOccurred:" << error;
+ });
+ QObject::connect(leCentralController.get(), &QLowEnergyController::discoveryFinished, []() {
+ qDebug() << "QLowEnergyController central service discovery finished";
+ });
+ QObject::connect(leCentralController.get(), &QLowEnergyController::serviceDiscovered,
+ [](const QBluetoothUuid &newService){
+ qDebug() << "QLowEnergyController central service discovered:" << newService;
+ });
+ QObject::connect(leCentralController.get(), &QLowEnergyController::stateChanged,
+ [this](QLowEnergyController::ControllerState state) {
+ qDebug() << "QLowEnergyController central stateChanged:" << state;
+ if (state == QLowEnergyController::UnconnectedState)
+ latestRSSI = "N/A"_ba;
+ emit leChanged();
+ });
+ QObject::connect(leCentralController.get(), &QLowEnergyController::rssiRead,
+ [this](qint16 rssi) {
+ qDebug() << "QLowEnergyController central RSSI updated:" << rssi;
+ latestRSSI = QByteArray::number(rssi);
+ emit leChanged();
+ });
+}
+
+void BtLocalDevice::centralDiscoverServiceDetails()
+{
+ qDebug() << "###### Discover Service details";
+ if (!leCentralController) {
+ qDebug() << "Central does not exist";
+ return;
+ }
+ leCentralService.reset(
+ leCentralController->createServiceObject(QBluetoothUuid(leServiceUuid)));
+ emit leChanged();
+ if (!leCentralService) {
+ qDebug() << "Service creation failed, cannot discover details";
+ return;
+ }
+ QObject::connect(leCentralService.get(), &QLowEnergyService::stateChanged,
+ [this](QLowEnergyService::ServiceState state){
+ qDebug() << "LE central service state changed:" << state;
+ emit leChanged();
+ });
+ QObject::connect(leCentralService.get(), &QLowEnergyService::characteristicWritten,
+ [](const QLowEnergyCharacteristic&, const QByteArray& value){
+ qDebug() << "LE central service characteristic value written" << value;
+ });
+ QObject::connect(leCentralService.get(), &QLowEnergyService::characteristicRead,
+ [](const QLowEnergyCharacteristic&, const QByteArray& value){
+ qDebug() << "LE central service characteristic value read" << value;
+ });
+ QObject::connect(leCentralService.get(), &QLowEnergyService::characteristicChanged,
+ [](const QLowEnergyCharacteristic&, const QByteArray& value){
+ qDebug() << "LE central service characteristic value changed" << value;
+ });
+ QObject::connect(leCentralService.get(), &QLowEnergyService::descriptorRead,
+ [](const QLowEnergyDescriptor&, const QByteArray& value){
+ qDebug() << "LE central service descriptor value read" << value;
+ });
+ QObject::connect(leCentralService.get(), &QLowEnergyService::descriptorWritten,
+ [this](const QLowEnergyDescriptor&, const QByteArray& value){
+ qDebug() << "LE central service descriptor value written" << value;
+ emit leChanged();
+ });
+ QObject::connect(leCentralService.get(), &QLowEnergyService::errorOccurred,
+ [](QLowEnergyService::ServiceError error){
+ qDebug() << "LE central service error occurred:" << error;
+ });
+ leCentralService->discoverDetails(QLowEnergyService::FullDiscovery);
+}
+
+void BtLocalDevice::centralConnect()
+{
+ qDebug() << "######" << "Central connect";
+ if (!leCentralController) {
+ qDebug() << "Create central first";
+ return;
+ }
+ leCentralController->connectToDevice();
+}
+
+void BtLocalDevice::dumpLeInfo()
+{
+ const auto controllerDump = [](QLowEnergyController* controller) {
+ qDebug() << " State:" << controller->state();
+ qDebug() << " Role:" << controller->role();
+ qDebug() << " Error:" << controller->error();
+ qDebug() << " ErrorString:" << controller->errorString();
+ qDebug() << " MTU:" << controller->mtu();
+ qDebug() << " Local Address:" << controller->localAddress();
+ qDebug() << " RemoteAddress:" << controller->remoteAddress();
+ qDebug() << " RemoteName:" << controller->remoteName();
+ qDebug() << " Services count:" << controller->services().size();
+ };
+ qDebug() << "######" << "LE Peripheral controller";
+ if (lePeripheralController)
+ controllerDump(lePeripheralController.get());
+
+ qDebug() << "######" << "LE Central controller";
+ if (leCentralController)
+ controllerDump(leCentralController.get());
+
+ qDebug() << "######" << "LE Found peripheral device";
+ if (leRemotePeripheralDevice.isValid()) {
+ qDebug() << " Name:" << leRemotePeripheralDevice.name();
+ qDebug() << " UUID:" << leRemotePeripheralDevice.deviceUuid();
+ qDebug() << " Address:" << leRemotePeripheralDevice.address();
+ }
+
+ const auto serviceDump = [](QLowEnergyService* service){
+ qDebug() << " Name:" << service->serviceName();
+ qDebug() << " Uuid:" << service->serviceUuid();
+ qDebug() << " Error:" << service->error();
+ auto characteristics = service->characteristics();
+ for (const auto& characteristic : characteristics) {
+ qDebug() << " Characteristic";
+ qDebug() << " Uuid" << characteristic.uuid();
+ qDebug() << " Value" << characteristic.value();
+
+ }
+ };
+
+ qDebug() << "######" << "LE Central-side service";
+ if (leCentralService)
+ serviceDump(leCentralService.get());
+
+ qDebug() << "######" << "LE Peripheral-side service";
+ if (!lePeripheralServices.isEmpty())
+ serviceDump(lePeripheralServices[0].get());
+}
+
+void BtLocalDevice::centralSubscribeUnsubscribe()
+{
+ qDebug() << "######" << "LE Central (Un)Subscribe";
+ if (!leCentralService) {
+ qDebug() << "Service object does not exist";
+ return;
+ }
+ auto characteristic = leCentralService->characteristic(QBluetoothUuid(leCharUuid1));
+ if (!characteristic.isValid()) {
+ qDebug() << "Characteristic is not valid";
+ return;
+ }
+
+ auto descriptor = characteristic.descriptor(
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
+ if (!descriptor.isValid()) {
+ qDebug() << "Descriptor is not valid";
+ return;
+ }
+ if (descriptor.value() == QByteArray::fromHex("0000")) {
+ qDebug() << " Subscribing notifications";
+ leCentralService->writeDescriptor(descriptor, QByteArray::fromHex("0100"));
+ } else {
+ qDebug() << " Unsubscribing notifications";
+ leCentralService->writeDescriptor(descriptor, QByteArray::fromHex("0000"));
+ }
+ emit leChanged();
+}
+
+void BtLocalDevice::centralDelete()
+{
+ qDebug() << "######" << "Delete central" << leCentralController.get();
+ leCentralController.reset(nullptr);
+ latestRSSI = "(N/A)"_ba;
+ emit leChanged();
+}
+
+void BtLocalDevice::centralDisconnect()
+{
+ qDebug() << "######" << "LE central disconnect";
+ if (!leCentralController) {
+ qDebug() << "Create central first";
+ return;
+ }
+ leCentralController->disconnectFromDevice();
+}
+
+void BtLocalDevice::peripheralDelete()
+{
+ qDebug() << "######" << "Delete peripheral" << lePeripheralController.get();
+ lePeripheralController.reset(nullptr);
+ emit leChanged();
+}
+
+void BtLocalDevice::peripheralDisconnect()
+{
+ qDebug() << "######" << "LE peripheral disconnect";
+ if (!lePeripheralController) {
+ qDebug() << "Create peripheral first";
+ return;
+ }
+ lePeripheralController->disconnectFromDevice();
+}
+
+bool BtLocalDevice::centralExists() const
+{
+ return leCentralController.get();
+}
+
+bool BtLocalDevice::centralSubscribed() const
+{
+ if (!leCentralService)
+ return false;
+
+ auto characteristic = leCentralService->characteristic(QBluetoothUuid(leCharUuid1));
+ if (!characteristic.isValid())
+ return false;
+
+ auto descriptor = characteristic.descriptor(
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
+ if (!descriptor.isValid())
+ return false;
+
+ return (descriptor.value() != QByteArray::fromHex("0000"));
+}
+
+QByteArray BtLocalDevice::centralState() const
+{
+ if (!leCentralController)
+ return "(N/A)"_ba;
+
+ return controllerStateString[leCentralController->state()];
+}
+
+QByteArray BtLocalDevice::centralServiceState() const
+{
+ if (!leCentralService)
+ return "(N/A)"_ba;
+
+ return serviceStateString[leCentralService->state()];
+}
+
+QByteArray BtLocalDevice::centralError() const
+{
+ if (!leCentralController)
+ return "(N/A)"_ba;
+
+ return controllerErrorString[leCentralController->error()];
+}
+
+QByteArray BtLocalDevice::centralServiceError() const
+{
+ if (!leCentralService)
+ return "(N/A)"_ba;
+
+ return serviceErrorString[leCentralService->error()];
+}
+
+void BtLocalDevice::centralReadRSSI() const
+{
+ qDebug() << "######" << "LE central readRSSI";
+ if (!leCentralController)
+ return;
+ leCentralController->readRssi();
+}
+
+QByteArray BtLocalDevice::centralRSSI() const
+{
+ return latestRSSI;
+}
+
+QByteArray BtLocalDevice::peripheralState() const
+{
+ if (!lePeripheralController)
+ return "(N/A)"_ba;
+
+ return controllerStateString[lePeripheralController->state()];
+}
+
+QByteArray BtLocalDevice::peripheralServiceState() const
+{
+ if (lePeripheralServices.isEmpty())
+ return "(N/A)"_ba;
+
+ return serviceStateString[lePeripheralServices[0]->state()];
+}
+
+QByteArray BtLocalDevice::peripheralError() const
+{
+ if (!lePeripheralController)
+ return "(N/A)"_ba;
+
+ return controllerErrorString[lePeripheralController->error()];
+}
+
+QByteArray BtLocalDevice::peripheralServiceError() const
+{
+ if (lePeripheralServices.isEmpty())
+ return "(N/A)"_ba;
+
+ return serviceErrorString[lePeripheralServices[0]->error()];
+}
+
+bool BtLocalDevice::peripheralExists() const
+{
+ return lePeripheralController.get();
+}
diff --git a/tests/bttestui/btlocaldevice.h b/tests/bttestui/btlocaldevice.h
index a6130b12..4e7a8223 100644
--- a/tests/bttestui/btlocaldevice.h
+++ b/tests/bttestui/btlocaldevice.h
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef BTLOCALDEVICE_H
#define BTLOCALDEVICE_H
@@ -35,6 +10,8 @@
#include <QtBluetooth/QBluetoothServer>
#include <QtBluetooth/QBluetoothServiceDiscoveryAgent>
#include <QtBluetooth/QBluetoothSocket>
+#include <QtBluetooth/QLowEnergyController>
+#include <QtBluetooth/QLowEnergyServiceData>
class BtLocalDevice : public QObject
{
@@ -43,22 +20,37 @@ public:
explicit BtLocalDevice(QObject *parent = 0);
~BtLocalDevice();
Q_PROPERTY(QString hostMode READ hostMode NOTIFY hostModeStateChanged)
- Q_PROPERTY(int secFlags READ secFlags WRITE setSecFlags
- NOTIFY secFlagsChanged)
+ Q_PROPERTY(int secFlags READ secFlags WRITE setSecFlags NOTIFY secFlagsChanged)
- int secFlags() const;
+ Q_PROPERTY(bool centralExists READ centralExists NOTIFY leChanged);
+ Q_PROPERTY(bool centralSubscribed READ centralSubscribed NOTIFY leChanged);
+ Q_PROPERTY(QByteArray centralState READ centralState NOTIFY leChanged);
+ Q_PROPERTY(QByteArray centralError READ centralError NOTIFY leChanged);
+ Q_PROPERTY(QByteArray centralServiceState READ centralServiceState NOTIFY leChanged);
+ Q_PROPERTY(QByteArray centralServiceError READ centralServiceError NOTIFY leChanged);
+ Q_PROPERTY(QByteArray centralRSSI READ centralRSSI NOTIFY leChanged);
+
+ Q_PROPERTY(QByteArray peripheralState READ peripheralState NOTIFY leChanged);
+ Q_PROPERTY(QByteArray peripheralError READ peripheralError NOTIFY leChanged);
+ Q_PROPERTY(QByteArray peripheralServiceState READ peripheralServiceState NOTIFY leChanged);
+ Q_PROPERTY(QByteArray peripheralServiceError READ peripheralServiceError NOTIFY leChanged);
+ Q_PROPERTY(bool peripheralExists READ peripheralExists NOTIFY leChanged);
+
+ QBluetooth::SecurityFlags secFlags() const;
void setSecFlags(int);
QString hostMode() const;
signals:
- void error(QBluetoothLocalDevice::Error error);
+ void errorOccurred(QBluetoothLocalDevice::Error error);
void hostModeStateChanged();
void socketStateUpdate(int foobar);
void secFlagsChanged();
+ bool leChanged(); // Same signal used for LE changes for simplicity
public slots:
//QBluetoothLocalDevice
void dumpInformation();
+ void dumpErrors();
void powerOn();
void reset();
void setHostMode(int newMode);
@@ -66,13 +58,12 @@ public slots:
void pairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing);
void connected(const QBluetoothAddress &addr);
void disconnected(const QBluetoothAddress &addr);
- void pairingDisplayConfirmation(const QBluetoothAddress &address, const QString &pin);
- void pairingDisplayPinCode(const QBluetoothAddress &address, const QString &pin);
- void confirmPairing();
void cycleSecurityFlags();
//QBluetoothDeviceDiscoveryAgent
void deviceDiscovered(const QBluetoothDeviceInfo &info);
+ void deviceUpdated(const QBluetoothDeviceInfo &info,
+ QBluetoothDeviceInfo::Fields updateFields);
void discoveryFinished();
void discoveryCanceled();
void discoveryError(QBluetoothDeviceDiscoveryAgent::Error error);
@@ -113,19 +104,69 @@ public slots:
void clientSocketReadyRead();
void dumpServerInformation();
+ //QLowEnergyController central
+ void centralCreate();
+ void centralConnect();
+ void centralStartServiceDiscovery();
+ void centralDiscoverServiceDetails();
+ void centralCharacteristicWrite();
+ void centralCharacteristicRead();
+ void centralDescriptorWrite();
+ void centralDescriptorRead();
+ void centralSubscribeUnsubscribe();
+ void centralDelete();
+ void centralDisconnect();
+ bool centralExists() const;
+ bool centralSubscribed() const;
+ QByteArray centralState() const;
+ QByteArray centralServiceState() const;
+ QByteArray centralError() const;
+ QByteArray centralServiceError() const;
+ void centralReadRSSI() const;
+ QByteArray centralRSSI() const;
+
+ //QLowEnergyController peripheral
+ void peripheralCreate();
+ void peripheralAddServices();
+ void peripheralStartAdvertising();
+ void peripheralStopAdvertising();
+ void peripheralCharacteristicRead();
+ void peripheralCharacteristicWrite();
+ void peripheralDescriptorRead();
+ void peripheralDescriptorWrite();
+ void peripheralDelete();
+ void peripheralDisconnect();
+ bool peripheralExists() const;
+ QByteArray peripheralState() const;
+ QByteArray peripheralServiceState() const;
+ QByteArray peripheralError() const;
+ QByteArray peripheralServiceError() const;
+
+ // QLowEnergyController misc
+ void startLeDeviceDiscovery();
+ void dumpLeInfo();
+
private:
void dumpLocalDevice(QBluetoothLocalDevice *dev);
- QBluetoothLocalDevice *localDevice;
- QBluetoothDeviceDiscoveryAgent *deviceAgent;
- QBluetoothServiceDiscoveryAgent *serviceAgent;
- QBluetoothSocket *socket;
- QBluetoothServer *server;
+ QBluetoothLocalDevice *localDevice = nullptr;
+ QBluetoothDeviceDiscoveryAgent *deviceAgent = nullptr;
+ QBluetoothServiceDiscoveryAgent *serviceAgent = nullptr;
+ QBluetoothSocket *socket = nullptr;
+ QBluetoothServer *server = nullptr;
QList<QBluetoothSocket *> serverSockets;
QBluetoothServiceInfo serviceInfo;
-
QList<QBluetoothServiceInfo> foundTestServers;
QBluetooth::SecurityFlags securityFlags;
+
+ std::unique_ptr<QLowEnergyController> leCentralController;
+ std::unique_ptr<QLowEnergyController> lePeripheralController;
+ std::unique_ptr<QLowEnergyService> leCentralService;
+ QLowEnergyAdvertisingData leAdvertisingData;
+ QList<QLowEnergyServiceData> lePeripheralServiceData;
+ QList<QSharedPointer<QLowEnergyService>> lePeripheralServices;
+ QBluetoothDeviceInfo leRemotePeripheralDevice;
+ QByteArray latestRSSI = "N/A";
};
#endif // BTLOCALDEVICE_H
diff --git a/tests/bttestui/bttest.qrc b/tests/bttestui/bttest.qrc
deleted file mode 100644
index bb3a7ad6..00000000
--- a/tests/bttestui/bttest.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>main.qml</file>
- <file>Button.qml</file>
- </qresource>
-</RCC>
diff --git a/tests/bttestui/bttestui.pro b/tests/bttestui/bttestui.pro
deleted file mode 100644
index ce582e66..00000000
--- a/tests/bttestui/bttestui.pro
+++ /dev/null
@@ -1,18 +0,0 @@
-TARGET = bttestui
-TEMPLATE = app
-
-SOURCES += main.cpp \
- btlocaldevice.cpp
-
-QT += quick bluetooth
-
-android: QT += androidextras
-
-OTHER_FILES += main.qml \
- Button.qml
-
-RESOURCES += \
- bttest.qrc
-
-HEADERS += \
- btlocaldevice.h
diff --git a/tests/bttestui/main.cpp b/tests/bttestui/main.cpp
index 35f95b6e..50d57847 100644
--- a/tests/bttestui/main.cpp
+++ b/tests/bttestui/main.cpp
@@ -1,30 +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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtGui/QGuiApplication>
#include <QtQml/QQmlEngine>
@@ -33,18 +8,39 @@
#include <QtCore/QLoggingCategory>
+#if QT_CONFIG(permissions)
+#include <QtCore/qpermissions.h>
+#endif
+
#include "btlocaldevice.h"
int main(int argc, char *argv[])
{
QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
QGuiApplication app(argc, argv);
- qmlRegisterType<BtLocalDevice>("Local", 5, 2, "BluetoothDevice");
+
+#if QT_CONFIG(permissions)
+ // Check Bluetooth permission and request it if the app doesn't have it
+ auto permissionStatus = app.checkPermission(QBluetoothPermission{});
+ if (permissionStatus == Qt::PermissionStatus::Undetermined) {
+ app.requestPermission(QBluetoothPermission{},
+ [&permissionStatus](const QPermission &permission) {
+ qApp->exit(); // Exit the permission request processing started below
+ permissionStatus = permission.status();
+ });
+ // Process permission request
+ app.exec();
+ }
+ if (permissionStatus == Qt::PermissionStatus::Denied) {
+ qWarning("Bluetooth permission denied, exiting");
+ return -1;
+ }
+#endif
+
+ qmlRegisterType<BtLocalDevice>("Local", 6, 5, "BluetoothDevice");
QQuickView view;
view.setSource(QStringLiteral("qrc:///main.qml"));
- view.setWidth(550);
- view.setHeight(550);
view.setResizeMode(QQuickView::SizeRootObjectToView);
QObject::connect(view.engine(), SIGNAL(quit()), qApp, SLOT(quit()));
diff --git a/tests/bttestui/main.qml b/tests/bttestui/main.qml
index 9c9d22d5..82688aef 100644
--- a/tests/bttestui/main.qml
+++ b/tests/bttestui/main.qml
@@ -1,269 +1,386 @@
-/****************************************************************************
-**
-** 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:GPL-EXCEPT$
-** 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 General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** 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-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-import QtQuick 2.0
-import Local 5.2
+import QtQuick
+import Local
-Rectangle {
- width: 360
- height: 360
+Flickable {
+ width: content.width
+ height: content.height
+ contentWidth: content.width
+ contentHeight: content.height
- BluetoothDevice {
- id: device
- function evaluateError(error)
- {
- switch (error) {
- case 0: return "Last Error: NoError"
- case 1: return "Last Error: Pairing Error"
- case 100: return "Last Error: Unknown Error"
- case 1000: return "Last Error: <None>"
- }
- }
+ Rectangle {
+ id: content
+ width: mainRow.implicitWidth
+ height: mainRow.implicitHeight
- function evaluateSocketState(s) {
- switch (s) {
- case 0: return "Socket: Unconnected";
- case 1: return "Socket: HostLookup";
- case 2: return "Socket: Connecting";
- case 3: return "Socket: Connected";
- case 4: return "Socket: Bound";
- case 5: return "Socket: Listening";
- case 6: return "Socket: Closing";
+ BluetoothDevice {
+ id: device
+ function evaluateError(error)
+ {
+ switch (error) {
+ case 0: return "Last Error: NoError"
+ case 1: return "Last Error: Pairing Error"
+ case 100: return "Last Error: Unknown Error"
+ case 1000: return "Last Error: <None>"
+ }
}
- return "Socket: <None>";
- }
+ function evaluateSocketState(s) {
+ switch (s) {
+ case 0: return "Socket: Unconnected";
+ case 1: return "Socket: HostLookup";
+ case 2: return "Socket: Connecting";
+ case 3: return "Socket: Connected";
+ case 4: return "Socket: Bound";
+ case 5: return "Socket: Listening";
+ case 6: return "Socket: Closing";
+ }
+ return "Socket: <None>";
+ }
- onError: errorText.text = evaluateError(error)
- onHostModeStateChanged: hostModeText.text = device.hostMode;
- onSocketStateUpdate : socketStateText.text = evaluateSocketState(foobar);
- }
-
- Text {
- id: errorText
- anchors.left: parent.left
- anchors.bottom: parent.bottom
- anchors.bottomMargin: 3
- text: "Last Error: <None>"
- }
- Text {
- id: hostModeText
- anchors.left: parent.left
- anchors.bottom: socketStateText.top
- anchors.bottomMargin: 3
- text: device.hostMode
- }
- Text {
- id: socketStateText
- anchors.left: parent.left
- anchors.bottom: errorText.top
- anchors.bottomMargin: 3
- text: device.evaluateSocketState(0)
- }
- Text {
- id: secFlagLabel; text: "SecFlags: "
- anchors.left: parent.left
- anchors.bottom: hostModeText.top
- anchors.bottomMargin: 3
- }
- Text {
- anchors.left: secFlagLabel.right
- anchors.bottom: hostModeText.top
- anchors.bottomMargin: 3
- text: device.secFlags
- }
- Row {
- anchors.top: parent.top
- anchors.left: parent.left
- anchors.margins: 4
+ onErrorOccurred: (error) => errorText.text = evaluateError(error)
+ onHostModeStateChanged: hostModeText.text = device.hostMode;
+ onSocketStateUpdate: (foobar) => socketStateText.text = evaluateSocketState(foobar);
+ }
- spacing: 8
- Column {
- spacing: 8
- Text{
- width: connectBtn.width
- horizontalAlignment: Text.AlignLeft
- font.pointSize: 12
- wrapMode: Text.WordWrap
- text: "Device Management"
- }
- Button {
+ Row {
+ id: mainRow
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.margins: 4
- buttonText: "PowerOn"
- onClicked: device.powerOn()
- }
- Button {
- buttonText: "PowerOff"
- onClicked: device.setHostMode(0)
- }
- Button {
- id: connectBtn
- buttonText: "Connectable"
- onClicked: device.setHostMode(1)
- }
- Button {
- buttonText: "Discover"
- onClicked: device.setHostMode(2)
- }
- Button {
- buttonText: "Pair"
- onClicked: device.requestPairingUpdate(true)
- }
- Button {
- buttonText: "Unpair"
- onClicked: device.requestPairingUpdate(false)
- }
- Button {
- buttonText: "Cycle SecFlag"
- onClicked: device.cycleSecurityFlags()
- }
- }
- Column {
spacing: 8
- Text{
- width: startFullSDiscBtn.width
- horizontalAlignment: Text.AlignLeft
- font.pointSize: 12
- wrapMode: Text.WordWrap
- text: "Device & Service Discovery"
- }
- Button {
- buttonText: "StartDDisc"
- onClicked: device.startDiscovery()
- }
- Button {
- buttonText: "StopDDisc"
- onClicked: device.stopDiscovery()
- }
- Button {
- buttonText: "StartMinSDisc"
- onClicked: device.startServiceDiscovery(true)
- }
- Button {
- id: startFullSDiscBtn
- buttonText: "StartFullSDisc"
- onClicked: device.startServiceDiscovery(false)
- }
- Button {
- id: startRemoteSDiscBtn
- buttonText: "StartRemSDisc"
- onClicked: device.startTargettedServiceDiscovery()
- }
- Button {
- buttonText: "StopSDisc"
- onClicked: device.stopServiceDiscovery();
- }
- Button {
- buttonText: "DumpSDisc"
- onClicked: device.dumpServiceDiscovery();
- }
+ Column {
+ spacing: 8
+ Text{
+ width: connectBtn.width
+ horizontalAlignment: Text.AlignLeft
+ font.pointSize: 12
+ wrapMode: Text.WordWrap
+ text: "Device Management"
+ }
+ Button {
- }
+ buttonText: "PowerOn"
+ onClicked: device.powerOn()
+ }
+ Button {
+ buttonText: "PowerOff"
+ onClicked: device.setHostMode(0)
+ }
+ Button {
+ id: connectBtn
+ buttonText: "Connectable"
+ onClicked: device.setHostMode(1)
+ }
+ Button {
+ buttonText: "Discover"
+ onClicked: device.setHostMode(2)
+ }
+ Button {
+ buttonText: "Pair"
+ onClicked: device.requestPairingUpdate(true)
+ }
+ Button {
+ buttonText: "Unpair"
+ onClicked: device.requestPairingUpdate(false)
+ }
+ Button {
+ buttonText: "Cycle SecFlag"
+ onClicked: device.cycleSecurityFlags()
+ }
+ Text {
+ id: errorText
+ text: "Last Error: <None>"
+ }
+ Text {
+ id: hostModeText
+ text: device.hostMode
+ }
+ Text {
+ id: socketStateText
+ text: device.evaluateSocketState(0)
+ }
+ Text {
+ id: secFlagLabel;
+ text: "SecFlags: " + device.secFlags
+ }
+ }
+ Column {
+ spacing: 8
+ Text{
+ width: startFullSDiscBtn.width
+ horizontalAlignment: Text.AlignLeft
+ font.pointSize: 12
+ wrapMode: Text.WordWrap
+ text: "Device & Service Discovery"
+ }
+ Button {
+ buttonText: "StartDDisc"
+ onClicked: device.startDiscovery()
+ }
+ Button {
+ buttonText: "StopDDisc"
+ onClicked: device.stopDiscovery()
+ }
+ Button {
+ buttonText: "StartMinSDisc"
+ onClicked: device.startServiceDiscovery(true)
+ }
+ Button {
+ id: startFullSDiscBtn
+ buttonText: "StartFullSDisc"
+ onClicked: device.startServiceDiscovery(false)
+ }
+ Button {
+ id: startRemoteSDiscBtn
+ buttonText: "StartRemSDisc"
+ onClicked: device.startTargettedServiceDiscovery()
+ }
+ Button {
+ buttonText: "StopSDisc"
+ onClicked: device.stopServiceDiscovery();
+ }
+ Button {
+ buttonText: "DumpSDisc"
+ onClicked: device.dumpServiceDiscovery();
+ }
- Column {
- spacing: 8
- Text{
- width: connectSearchBtn.width
- horizontalAlignment: Text.AlignLeft
- font.pointSize: 12
- wrapMode: Text.WordWrap
- text: "Client & Server Socket"
- }
- Button {
- buttonText: "SocketDump"
- onClicked: device.dumpSocketInformation()
- }
- Button {
- buttonText: "CConnect"
- onClicked: device.connectToService()
- }
- Button {
- id: connectSearchBtn
- buttonText: "ConnectSearch"
- onClicked: device.connectToServiceViaSearch()
- }
- Button {
- buttonText: "CDisconnect"
- onClicked: device.disconnectToService()
}
- Button {
- buttonText: "CClose"
- onClicked: device.closeSocket()
- }
+ Column {
+ spacing: 8
+ Text{
+ width: connectSearchBtn.width
+ horizontalAlignment: Text.AlignLeft
+ font.pointSize: 12
+ wrapMode: Text.WordWrap
+ text: "Client & Server Socket"
+ }
+ Button {
+ buttonText: "SocketDump"
+ onClicked: device.dumpSocketInformation()
+ }
+ Button {
+ buttonText: "CConnect"
+ onClicked: device.connectToService()
+ }
+ Button {
+ id: connectSearchBtn
+ buttonText: "ConnectSearch"
+ onClicked: device.connectToServiceViaSearch()
+ }
+ Button {
+ buttonText: "CDisconnect"
+ onClicked: device.disconnectToService()
+ }
- Button {
- buttonText: "CAbort"
- onClicked: device.abortSocket()
- }
- Button {
- //Write to all open sockets ABCABC\n
- buttonText: "CSWrite"
- onClicked: device.writeData()
- }
- Button {
- buttonText: "ServerDump"
- onClicked: device.dumpServerInformation()
- }
- Button {
- //Listen on server via port
- buttonText: "SListenPort"
- onClicked: device.serverListenPort()
- }
- Button {
- //Listen on server via uuid
- buttonText: "SListenUuid"
- onClicked: device.serverListenUuid()
- }
- Button {
- //Close Bluetooth server
- buttonText: "SClose"
- onClicked: device.serverClose()
- }
- }
- Column {
- spacing: 8
- Text{
- width: resetBtn.width
- horizontalAlignment: Text.AlignLeft
- font.pointSize: 12
- wrapMode: Text.WordWrap
- text: "Misc Controls"
- }
- Button {
- buttonText: "Dump"
- onClicked: device.dumpInformation()
- }
- Button {
- id: resetBtn
- buttonText: "Reset"
- onClicked: device.reset()
+ Button {
+ buttonText: "CClose"
+ onClicked: device.closeSocket()
+ }
+
+ Button {
+ buttonText: "CAbort"
+ onClicked: device.abortSocket()
+ }
+ Button {
+ //Write to all open sockets ABCABC\n
+ buttonText: "CSWrite"
+ onClicked: device.writeData()
+ }
+ Button {
+ buttonText: "ServerDump"
+ onClicked: device.dumpServerInformation()
+ }
+ Button {
+ //Listen on server via port
+ buttonText: "SListenPort"
+ onClicked: device.serverListenPort()
+ }
+ Button {
+ //Listen on server via uuid
+ buttonText: "SListenUuid"
+ onClicked: device.serverListenUuid()
+ }
+ Button {
+ //Close Bluetooth server
+ buttonText: "SClose"
+ onClicked: device.serverClose()
+ }
+ }
+ Column {
+ spacing: 8
+ Text{
+ width: centralBtn.width
+ horizontalAlignment: Text.AlignLeft
+ color: device.centralExists ? "blue" : "black"
+ font.bold: device.centralExists
+ font.pointSize: 12
+ wrapMode: Text.WordWrap
+ text: "Low Energy Central Controller"
+ }
+ Rectangle {
+ color: "lightsteelblue"
+ width: parent.width
+ height: centralInfo.height
+ clip: true
+ Column {
+ id: centralInfo
+ Text { text: "CState:" + device.centralState }
+ Text { text: "CError:" + device.centralError }
+ Text { text: "SState:" + device.centralServiceState }
+ Text { text: "SError:" + device.centralServiceError }
+ Text { text: "Subscribed: " + device.centralSubscribed }
+ Text { text: "RSSI: " + device.centralRSSI }
+ }
+ }
+ // The ordinal numbers below indicate the typical sequence
+ Button {
+ id: centralBtn
+ buttonText: "1 DeviceDiscovery"
+ onClicked: device.startLeDeviceDiscovery()
+ }
+ Button {
+ buttonText: "2 CreateCentral"
+ onClicked: device.centralCreate()
+ }
+ Button {
+ buttonText: "3 ConnectCentral"
+ onClicked: device.centralConnect()
+ }
+ Button {
+ buttonText: "4 ServiceDiscovery"
+ onClicked: device.centralStartServiceDiscovery()
+ }
+ Button {
+ buttonText: "5 ServiceDetails"
+ onClicked: device.centralDiscoverServiceDetails();
+ }
+ Button {
+ buttonText: "CharacteristicRead"
+ onClicked: device.centralCharacteristicRead()
+ }
+ Button {
+ buttonText: "CharacteristicWrite"
+ onClicked: device.centralCharacteristicWrite()
+ }
+ Button {
+ buttonText: "DescriptorRead"
+ onClicked: device.centralDescriptorRead()
+ }
+ Button {
+ buttonText: "DescriptorWrite"
+ onClicked: device.centralDescriptorWrite()
+ }
+ Button {
+ buttonText: "Sub/Unsubscribe"
+ onClicked: device.centralSubscribeUnsubscribe();
+ }
+ Button {
+ buttonText: "DeleteController"
+ onClicked: device.centralDelete()
+ }
+ Button {
+ buttonText: "Disconnect"
+ onClicked: device.centralDisconnect()
+ }
+ Button {
+ buttonText: "ReadRSSI"
+ onClicked: device.centralReadRSSI()
+ }
+ }
+ Column {
+ spacing: 8
+ Text{
+ width: centralBtn.width
+ horizontalAlignment: Text.AlignLeft
+ color: device.peripheralExists ? "blue" : "black"
+ font.bold: device.peripheralExists
+ font.pointSize: 12
+ wrapMode: Text.WordWrap
+ text: "Low Energy Peripheral Controller"
+ }
+ Rectangle {
+ color: "lightsteelblue"
+ width: parent.width
+ height: peripheralInfo.height
+ clip: true
+ Column {
+ id: peripheralInfo
+ Text { text: "CState: " + device.peripheralState }
+ Text { text: "CError: " + device.peripheralError }
+ Text { text: "SState: " + device.peripheralServiceState }
+ Text { text: "SError: " + device.peripheralServiceError }
+ }
+ }
+ Button {
+ buttonText: "1 CreatePeripheral"
+ onClicked: device.peripheralCreate()
+ }
+ Button {
+ buttonText: "2 AddServices"
+ onClicked: device.peripheralAddServices()
+ }
+ Button {
+ buttonText: "3 StartAdvertise"
+ onClicked: device.peripheralStartAdvertising()
+ }
+ Button {
+ buttonText: "StopAdvertise"
+ onClicked: device.peripheralStopAdvertising()
+ }
+ Button {
+ buttonText: "CharacteristicRead"
+ onClicked: device.peripheralCharacteristicRead()
+ }
+ Button {
+ buttonText: "CharacteristicWrite"
+ onClicked: device.peripheralCharacteristicWrite()
+ }
+ Button {
+ buttonText: "DescriptorRead"
+ onClicked: device.peripheralDescriptorRead()
+ }
+ Button {
+ buttonText: "DescriptorWrite"
+ onClicked: device.peripheralDescriptorWrite()
+ }
+ Button {
+ buttonText: "DeleteController"
+ onClicked: device.peripheralDelete()
+ }
+ Button {
+ buttonText: "Disconnect"
+ onClicked: device.peripheralDisconnect()
+ }
+ }
+ Column {
+ spacing: 8
+ Text{
+ width: resetBtn.width
+ horizontalAlignment: Text.AlignLeft
+ font.pointSize: 12
+ wrapMode: Text.WordWrap
+ text: "Misc Controls"
+ }
+ Button {
+ buttonText: "Dump"
+ onClicked: device.dumpInformation()
+ }
+ Button {
+ id: resetBtn
+ buttonText: "Reset"
+ onClicked: device.reset()
+ }
+ Button {
+ id: errorButton
+ buttonText: "Errors"
+ onClicked: device.dumpErrors()
+ }
}
}
}
diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt
new file mode 100644
index 00000000..47fdbfb8
--- /dev/null
+++ b/tests/manual/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(TARGET Qt::Bluetooth)
+ add_subdirectory(qlowenergycontroller)
+ add_subdirectory(qlowenergycontroller_peripheral)
+ add_subdirectory(examples/btscanner)
+endif()
+
diff --git a/tests/manual/examples/btscanner/CMakeLists.txt b/tests/manual/examples/btscanner/CMakeLists.txt
new file mode 100644
index 00000000..08bac2df
--- /dev/null
+++ b/tests/manual/examples/btscanner/CMakeLists.txt
@@ -0,0 +1,48 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(btscanner LANGUAGES CXX)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+ endif()
+
+qt_internal_add_manual_test(btscanner
+ GUI
+ SOURCES
+ device.cpp device.h device.ui
+ main.cpp
+ service.cpp service.h service.ui
+ LIBRARIES
+ Qt::Bluetooth
+ Qt::Core
+ Qt::Widgets
+ ENABLE_AUTOGEN_TOOLS
+ uic
+)
+
+if(MACOS)
+ # Explicitly link against the static permission plugin because tests
+ # currently don't have finalizers run for them except for iOS.
+ # TODO: Remove this when qtbase automatically runs finalizers for tests: QTBUG-112212
+ target_link_libraries(btscanner PRIVATE Qt6::QDarwinBluetoothPermissionPlugin)
+endif()
+
+set_target_properties(btscanner PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+if(APPLE)
+ if (IOS)
+ set_target_properties(btscanner PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist"
+ )
+ else()
+ # Using absolute path for shared plist files is a Ninja bug workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../examples/bluetooth/shared ABSOLUTE)
+ set_target_properties(btscanner PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.cmake.macos.plist"
+ )
+ endif()
+endif()
diff --git a/tests/manual/examples/btscanner/Info.plist b/tests/manual/examples/btscanner/Info.plist
new file mode 100644
index 00000000..49fd2191
--- /dev/null
+++ b/tests/manual/examples/btscanner/Info.plist
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>${ASSETCATALOG_COMPILER_APPICON_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${QMAKE_SHORT_VERSION}</string>
+ <key>CFBundleSignature</key>
+ <string>${QMAKE_PKGINFO_TYPEINFO}</string>
+ <key>CFBundleVersion</key>
+ <string>${QMAKE_FULL_VERSION}</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>MinimumOSVersion</key>
+ <string>${IPHONEOS_DEPLOYMENT_TARGET}</string>
+ <key>NSBluetoothAlwaysUsageDescription</key>
+ <string>Qt's BT scanner wants to access your Bluetooth adapter!</string>
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
diff --git a/examples/bluetooth/btscanner/btscanner.pro b/tests/manual/examples/btscanner/btscanner.pro
index 904ea5a8..3ef49969 100644
--- a/examples/bluetooth/btscanner/btscanner.pro
+++ b/tests/manual/examples/btscanner/btscanner.pro
@@ -9,6 +9,9 @@ SOURCES = \
device.cpp \
service.cpp
+ios: QMAKE_INFO_PLIST = Info.plist
+macos: QMAKE_INFO_PLIST = ../../../../examples/bluetooth/shared/Info.qmake.macos.plist
+
HEADERS = \
device.h \
service.h
diff --git a/tests/manual/examples/btscanner/device.cpp b/tests/manual/examples/btscanner/device.cpp
new file mode 100644
index 00000000..6d1f775f
--- /dev/null
+++ b/tests/manual/examples/btscanner/device.cpp
@@ -0,0 +1,182 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "device.h"
+#include "service.h"
+#include "ui_device.h"
+
+#include <QtBluetooth/qbluetoothaddress.h>
+#include <QtBluetooth/qbluetoothdevicediscoveryagent.h>
+#include <QtBluetooth/qbluetoothlocaldevice.h>
+
+#include <QtWidgets/qmenu.h>
+
+#if QT_CONFIG(permissions)
+#include <QtCore/qpermissions.h>
+#include <QtWidgets/qmessagebox.h>
+#include <QtWidgets/qapplication.h>
+#endif // QT_CONFIG(permissions)
+
+static QColor colorForPairing(QBluetoothLocalDevice::Pairing pairing)
+{
+ return pairing == QBluetoothLocalDevice::Paired
+ || pairing == QBluetoothLocalDevice::AuthorizedPaired
+ ? QColor(Qt::green) : QColor(Qt::red);
+}
+
+DeviceDiscoveryDialog::DeviceDiscoveryDialog(QWidget *parent) :
+ QDialog(parent),
+ localDevice(new QBluetoothLocalDevice(this)),
+ ui(new Ui::DeviceDiscovery)
+{
+#ifdef Q_OS_ANDROID
+ this->setWindowState(Qt::WindowMaximized);
+#endif
+ ui->setupUi(this);
+ ui->stopScan->setVisible(false);
+
+ // In case of multiple Bluetooth adapters it is possible to set the adapter
+ // to be used. Example code:
+ //
+ // QBluetoothAddress address("XX:XX:XX:XX:XX:XX");
+ // discoveryAgent = new QBluetoothDeviceDiscoveryAgent(address, this);
+
+ discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
+
+ connect(ui->scan, &QAbstractButton::clicked, this, &DeviceDiscoveryDialog::startScan);
+ connect(ui->stopScan, &QAbstractButton::clicked, this, &DeviceDiscoveryDialog::stopScan);
+
+ connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
+ this, &DeviceDiscoveryDialog::addDevice);
+ connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished,
+ this, &DeviceDiscoveryDialog::scanFinished);
+
+ connect(ui->list, &QListWidget::itemActivated,
+ this, &DeviceDiscoveryDialog::itemActivated);
+
+ connect(localDevice, &QBluetoothLocalDevice::hostModeStateChanged,
+ this, &DeviceDiscoveryDialog::hostModeStateChanged);
+
+ hostModeStateChanged(localDevice->hostMode());
+ // add context menu for devices to be able to pair device
+ ui->list->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui->list, &QWidget::customContextMenuRequested,
+ this, &DeviceDiscoveryDialog::displayPairingMenu);
+ connect(localDevice, &QBluetoothLocalDevice::pairingFinished,
+ this, &DeviceDiscoveryDialog::pairingDone);
+}
+
+DeviceDiscoveryDialog::~DeviceDiscoveryDialog()
+{
+ delete ui;
+}
+
+void DeviceDiscoveryDialog::addDevice(const QBluetoothDeviceInfo &info)
+{
+ const QString label = info.address().toString() + u' ' + info.name();
+ const auto items = ui->list->findItems(label, Qt::MatchExactly);
+ if (items.isEmpty()) {
+ QListWidgetItem *item = new QListWidgetItem(label);
+ QBluetoothLocalDevice::Pairing pairingStatus = localDevice->pairingStatus(info.address());
+ item->setForeground(colorForPairing(pairingStatus));
+ ui->list->addItem(item);
+ }
+}
+
+void DeviceDiscoveryDialog::startScan()
+{
+#if QT_CONFIG(permissions)
+ if (qApp->checkPermission(QBluetoothPermission{}) != Qt::PermissionStatus::Granted) {
+ QMessageBox::warning(this, tr("Missing permission"),
+ tr("Permission is needed to use Bluetooth. "\
+ "Please grant the permission to this "\
+ "application in the system settings."));
+ return;
+ }
+#endif // QT_CONFIG(permissions)
+ discoveryAgent->start();
+ ui->scan->setVisible(false);
+ ui->stopScan->setVisible(true);
+}
+
+void DeviceDiscoveryDialog::stopScan()
+{
+ discoveryAgent->stop();
+ scanFinished();
+}
+
+void DeviceDiscoveryDialog::scanFinished()
+{
+ ui->scan->setVisible(true);
+ ui->stopScan->setVisible(false);
+}
+
+void DeviceDiscoveryDialog::itemActivated(QListWidgetItem *item)
+{
+ const QString text = item->text();
+ const auto index = text.indexOf(' ');
+ if (index == -1)
+ return;
+
+ QBluetoothAddress address(text.left(index));
+ QString name(text.mid(index + 1));
+
+ ServiceDiscoveryDialog d(name, address);
+ d.exec();
+}
+
+void DeviceDiscoveryDialog::on_discoverable_clicked(bool clicked)
+{
+ if (clicked)
+ localDevice->setHostMode(QBluetoothLocalDevice::HostDiscoverable);
+ else
+ localDevice->setHostMode(QBluetoothLocalDevice::HostConnectable);
+}
+
+void DeviceDiscoveryDialog::on_power_clicked(bool clicked)
+{
+ if (clicked)
+ localDevice->powerOn();
+ else
+ localDevice->setHostMode(QBluetoothLocalDevice::HostPoweredOff);
+}
+
+void DeviceDiscoveryDialog::hostModeStateChanged(QBluetoothLocalDevice::HostMode mode)
+{
+ ui->power->setChecked(mode != QBluetoothLocalDevice::HostPoweredOff);
+ ui->discoverable->setChecked(mode == QBluetoothLocalDevice::HostDiscoverable);
+
+ const bool on = mode != QBluetoothLocalDevice::HostPoweredOff;
+ ui->scan->setEnabled(on);
+ ui->discoverable->setEnabled(on);
+}
+void DeviceDiscoveryDialog::displayPairingMenu(const QPoint &pos)
+{
+ if (ui->list->count() == 0)
+ return;
+ QMenu menu(this);
+ QAction *pairAction = menu.addAction("Pair");
+ QAction *removePairAction = menu.addAction("Remove Pairing");
+ QAction *chosenAction = menu.exec(ui->list->viewport()->mapToGlobal(pos));
+ QListWidgetItem *currentItem = ui->list->currentItem();
+
+ QString text = currentItem->text();
+ const auto index = text.indexOf(' ');
+ if (index == -1)
+ return;
+
+ QBluetoothAddress address (text.left(index));
+ if (chosenAction == pairAction) {
+ localDevice->requestPairing(address, QBluetoothLocalDevice::Paired);
+ } else if (chosenAction == removePairAction) {
+ localDevice->requestPairing(address, QBluetoothLocalDevice::Unpaired);
+ }
+}
+void DeviceDiscoveryDialog::pairingDone(const QBluetoothAddress &address,
+ QBluetoothLocalDevice::Pairing pairing)
+{
+ const auto items = ui->list->findItems(address.toString(), Qt::MatchContains);
+ const QColor color = colorForPairing(pairing);
+ for (auto *item : items)
+ item->setForeground(color);
+}
diff --git a/tests/manual/examples/btscanner/device.h b/tests/manual/examples/btscanner/device.h
new file mode 100644
index 00000000..389062bb
--- /dev/null
+++ b/tests/manual/examples/btscanner/device.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef DEVICE_H
+#define DEVICE_H
+
+#include <QtBluetooth/qbluetoothlocaldevice.h>
+
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_NAMESPACE
+class QBluetoothAddress;
+class QBluetoothDeviceDiscoveryAgent;
+class QBluetoothDeviceInfo;
+class QListWidgetItem;
+
+namespace Ui {
+ class DeviceDiscovery;
+}
+QT_END_NAMESPACE
+
+class DeviceDiscoveryDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ DeviceDiscoveryDialog(QWidget *parent = nullptr);
+ ~DeviceDiscoveryDialog();
+
+public slots:
+ void addDevice(const QBluetoothDeviceInfo &info);
+ void on_power_clicked(bool clicked);
+ void on_discoverable_clicked(bool clicked);
+ void displayPairingMenu(const QPoint &pos);
+ void pairingDone(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing);
+private slots:
+ void startScan();
+ void stopScan();
+ void scanFinished();
+ void itemActivated(QListWidgetItem *item);
+ void hostModeStateChanged(QBluetoothLocalDevice::HostMode mode);
+
+private:
+ QBluetoothDeviceDiscoveryAgent *discoveryAgent;
+ QBluetoothLocalDevice *localDevice;
+ Ui::DeviceDiscovery *ui;
+};
+
+#endif
diff --git a/examples/bluetooth/btscanner/device.ui b/tests/manual/examples/btscanner/device.ui
index 1f62dd96..fd86a358 100644
--- a/examples/bluetooth/btscanner/device.ui
+++ b/tests/manual/examples/btscanner/device.ui
@@ -47,16 +47,6 @@
</widget>
</item>
<item>
- <widget class="QCheckBox" name="inquiryType">
- <property name="text">
- <string>General Unlimited Inquiry</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="scan">
@@ -66,6 +56,13 @@
</widget>
</item>
<item>
+ <widget class="QPushButton" name="stopScan">
+ <property name="text">
+ <string>Stop scan</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QPushButton" name="clear">
<property name="text">
<string>Clear</string>
diff --git a/tests/manual/examples/btscanner/main.cpp b/tests/manual/examples/btscanner/main.cpp
new file mode 100644
index 00000000..8ed2e652
--- /dev/null
+++ b/tests/manual/examples/btscanner/main.cpp
@@ -0,0 +1,33 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "device.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtWidgets/qapplication.h>
+
+#if QT_CONFIG(permissions)
+#include <QtCore/qpermissions.h>
+#endif
+
+int main(int argc, char *argv[])
+{
+ // QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
+ QApplication app(argc, argv);
+ DeviceDiscoveryDialog d;
+
+ d.show();
+
+ // Check, and if needed, request a permission to use Bluetooth.
+#if QT_CONFIG(permissions)
+ const auto permissionStatus = app.checkPermission(QBluetoothPermission{});
+ if (permissionStatus == Qt::PermissionStatus::Undetermined) {
+ app.requestPermission(QBluetoothPermission{}, [](const QPermission &){
+ });
+ }
+ // Else means either 'Granted' or 'Denied' and both normally must be
+ // changed using the system's settings application.
+#endif // QT_CONFIG(permissions)
+
+ return app.exec();
+}
diff --git a/tests/manual/examples/btscanner/service.cpp b/tests/manual/examples/btscanner/service.cpp
new file mode 100644
index 00000000..aa6fe43c
--- /dev/null
+++ b/tests/manual/examples/btscanner/service.cpp
@@ -0,0 +1,62 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "service.h"
+#include "ui_service.h"
+
+#include <QtBluetooth/qbluetoothaddress.h>
+#include <QtBluetooth/qbluetoothlocaldevice.h>
+#include <QtBluetooth/qbluetoothservicediscoveryagent.h>
+#include <QtBluetooth/qbluetoothserviceinfo.h>
+#include <QtBluetooth/qbluetoothuuid.h>
+
+
+ServiceDiscoveryDialog::ServiceDiscoveryDialog(const QString &name,
+ const QBluetoothAddress &address, QWidget *parent)
+ : QDialog(parent), ui(new Ui::ServiceDiscovery)
+{
+ ui->setupUi(this);
+
+ //Using default Bluetooth adapter
+ QBluetoothLocalDevice localDevice;
+ QBluetoothAddress adapterAddress = localDevice.address();
+
+ // In case of multiple Bluetooth adapters it is possible to
+ // set which adapter will be used by providing MAC Address.
+ // Example code:
+ //
+ // QBluetoothAddress adapterAddress("XX:XX:XX:XX:XX:XX");
+ // discoveryAgent = new QBluetoothServiceDiscoveryAgent(adapterAddress, this);
+
+ discoveryAgent = new QBluetoothServiceDiscoveryAgent(adapterAddress, this);
+ discoveryAgent->setRemoteAddress(address);
+
+ setWindowTitle(name);
+
+ connect(discoveryAgent, &QBluetoothServiceDiscoveryAgent::serviceDiscovered,
+ this, &ServiceDiscoveryDialog::addService);
+ connect(discoveryAgent, &QBluetoothServiceDiscoveryAgent::finished,
+ ui->status, &QWidget::hide);
+
+ discoveryAgent->start();
+}
+
+ServiceDiscoveryDialog::~ServiceDiscoveryDialog()
+{
+ delete ui;
+}
+
+void ServiceDiscoveryDialog::addService(const QBluetoothServiceInfo &info)
+{
+ if (info.serviceName().isEmpty())
+ return;
+
+ QString line = info.serviceName();
+ if (!info.serviceDescription().isEmpty())
+ line.append("\n\t" + info.serviceDescription());
+ if (!info.serviceProvider().isEmpty())
+ line.append("\n\t" + info.serviceProvider());
+
+ ui->list->addItem(line);
+}
diff --git a/tests/manual/examples/btscanner/service.h b/tests/manual/examples/btscanner/service.h
new file mode 100644
index 00000000..1c84f38c
--- /dev/null
+++ b/tests/manual/examples/btscanner/service.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SERVICE_H
+#define SERVICE_H
+
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_NAMESPACE
+class QBluetoothAddress;
+class QBluetoothServiceDiscoveryAgent;
+class QBluetoothServiceInfo;
+
+namespace Ui {
+ class ServiceDiscovery;
+}
+QT_END_NAMESPACE
+
+class ServiceDiscoveryDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ ServiceDiscoveryDialog(const QString &name, const QBluetoothAddress &address,
+ QWidget *parent = nullptr);
+ ~ServiceDiscoveryDialog();
+
+public slots:
+ void addService(const QBluetoothServiceInfo &info);
+
+private:
+ QBluetoothServiceDiscoveryAgent *discoveryAgent;
+ Ui::ServiceDiscovery *ui;
+};
+
+#endif
diff --git a/examples/bluetooth/btscanner/service.ui b/tests/manual/examples/btscanner/service.ui
index 68ebc5dc..4ca12ee0 100644
--- a/examples/bluetooth/btscanner/service.ui
+++ b/tests/manual/examples/btscanner/service.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>400</width>
- <height>300</height>
+ <width>539</width>
+ <height>486</height>
</rect>
</property>
<property name="windowTitle">
@@ -25,50 +25,45 @@
</widget>
</item>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QPushButton" name="close">
- <property name="text">
- <string>Close</string>
- </property>
- </widget>
- </item>
- </layout>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Close</set>
+ </property>
+ </widget>
</item>
</layout>
</widget>
- <tabstops>
- <tabstop>list</tabstop>
- <tabstop>close</tabstop>
- </tabstops>
<resources/>
<connections>
<connection>
- <sender>close</sender>
- <signal>clicked()</signal>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
<receiver>ServiceDiscovery</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
- <x>350</x>
- <y>277</y>
+ <x>396</x>
+ <y>457</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>535</x>
+ <y>443</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ServiceDiscovery</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>339</x>
+ <y>464</y>
</hint>
<hint type="destinationlabel">
- <x>237</x>
- <y>269</y>
+ <x>535</x>
+ <y>368</y>
</hint>
</hints>
</connection>
diff --git a/tests/manual/qlowenergycontroller/CMakeLists.txt b/tests/manual/qlowenergycontroller/CMakeLists.txt
new file mode 100644
index 00000000..a1039a5b
--- /dev/null
+++ b/tests/manual/qlowenergycontroller/CMakeLists.txt
@@ -0,0 +1,68 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16...3.21)
+
+if(NOT TARGET Qt::Bluetooth)
+ # for standalone build (and the only way for iOS)
+ project(tst_qlowenergycontroller_device LANGUAGES CXX)
+
+ set(CMAKE_AUTOMOC ON)
+
+ find_package(Qt6 REQUIRED COMPONENTS Bluetooth Core Test Gui)
+
+ qt_add_executable(
+ tst_qlowenergycontroller_device
+ tst_qlowenergycontroller_device.cpp
+ )
+ target_link_libraries(
+ tst_qlowenergycontroller_device
+ PUBLIC
+ Qt::Core
+ Qt::Bluetooth
+ Qt::Test
+ Qt::Gui
+ )
+
+else()
+
+qt_internal_add_test(tst_qlowenergycontroller_device
+ SOURCES
+ tst_qlowenergycontroller_device.cpp
+ LIBRARIES
+ Qt::Bluetooth
+)
+
+qt_internal_extend_target(tst_qlowenergycontroller_device
+ CONDITION ANDROID AND NOT ANDROID_EMBEDDED
+ DEFINES
+ QT_ANDROID_BLUETOOTH
+)
+
+if(MACOS)
+ # Explicitly link against the static permission plugin because tests
+ # currently don't have finalizers run for them except for iOS.
+ # TODO: Remove this when qtbase automatically runs finalizers for tests: QTBUG-112212
+ target_link_libraries(tst_qlowenergycontroller_device PRIVATE Qt6::QDarwinBluetoothPermissionPlugin)
+endif()
+
+endif()
+
+set_target_properties(tst_qlowenergycontroller_device PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+if(APPLE)
+ # Ninja has trouble with relative paths, convert to absolute as a workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../shared ABSOLUTE)
+ if(IOS)
+ set_target_properties(tst_qlowenergycontroller_device PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.ios.plist"
+ )
+ else()
+ set_target_properties(tst_qlowenergycontroller_device PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.macos.plist"
+ )
+ endif()
+endif()
diff --git a/tests/manual/qlowenergycontroller/tst_qlowenergycontroller_device.cpp b/tests/manual/qlowenergycontroller/tst_qlowenergycontroller_device.cpp
new file mode 100644
index 00000000..e492363a
--- /dev/null
+++ b/tests/manual/qlowenergycontroller/tst_qlowenergycontroller_device.cpp
@@ -0,0 +1,945 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QObject>
+#include <QtGlobal>
+#include <QTest>
+#include <QBluetoothAddress>
+#include <QBluetoothDeviceDiscoveryAgent>
+#include <QSignalSpy>
+#include <QLowEnergyController>
+#include <QLoggingCategory>
+#include <QScopeGuard>
+#include <QBluetoothLocalDevice>
+
+#if QT_CONFIG(permissions)
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qpermissions.h>
+#include <QtCore/qnamespace.h>
+#endif
+
+static const QLatin1String largeAttributeServiceUuid("1f85e37c-ac16-11eb-ae5c-93d3a763feed");
+static const QLatin1String largeAttributeCharUuid("40e4f68e-ac16-11eb-9956-cfe55a8c370c");
+static const QLatin1String largeAttributeDescUuid("44e4f68e-ac16-11eb-9956-cfe55a8c370c");
+static constexpr qsizetype largeAttributeSize{508}; // Size for char and desc values
+
+static const QLatin1String platformIdentifierServiceUuid("4a92cb7f-5031-4a09-8304-3e89413f458d");
+static const QLatin1String platformIdentifierCharUuid("6b0ecf7c-5f09-4c87-aaab-bb49d5d383aa");
+
+static const QLatin1String
+ notificationIndicationTestServiceUuid("bb137ac5-5716-4b80-873b-e2d11d29efe2");
+static const QLatin1String
+ notificationIndicationTestChar1Uuid("6da4d652-0248-478a-a5a8-1e2f076158cc");
+static const QLatin1String
+ notificationIndicationTestChar2Uuid("990930f0-b9cc-4c27-8c1b-ebc2bcae5c95");
+static const QLatin1String
+ notificationIndicationTestChar3Uuid("9a60486b-de5b-4e03-b914-4e158c0bd388");
+static const QLatin1String
+ notificationIndicationTestChar4Uuid("d92435d4-6c2e-43f8-a6be-bbb66b5a3e28");
+
+static const QLatin1String connectionCountServiceUuid("78c61a07-a0f9-4b92-be2d-2570d8dbf010");
+static const QLatin1String connectionCountCharUuid("9414ec2d-792f-46a2-a19e-186d0fb38a08");
+
+static const QLatin1String repeatedWriteServiceUuid("72b12a31-98ea-406d-a89d-2c932d11ff67");
+static const QLatin1String repeatedWriteTargetCharUuid("2192ee43-6d17-4e78-b286-db2c3b696833");
+static const QLatin1String repeatedWriteNotifyCharUuid("b3f9d1a2-3d55-49c9-8b29-e09cec77ff86");
+
+
+// With the defines below some test cases are picked on at compile-time as opposed to runtime skips
+// to avoid the lengthy init() and clean() executions
+#if defined(QT_ANDROID_BLUETOOTH) || defined(QT_WINRT_BLUETOOTH) || defined(Q_OS_DARWIN)
+#define QT_BLUETOOTH_MTU_SUPPORTED
+#endif
+
+#if defined(QT_ANDROID_BLUETOOTH) || defined(Q_OS_DARWIN)
+#define QT_BLUETOOTH_RSSI_SUPPORTED
+#endif
+
+#if defined(QT_BLUETOOTH_MTU_SUPPORTED)
+static const QLatin1String mtuServiceUuid("9a9483eb-cf4f-4c32-9a6b-794238d5b483");
+static const QLatin1String mtuCharUuid("960d7e2a-a850-4a70-8064-cd74e9ccb6ff");
+#endif
+
+/*
+ * This class contains all unit tests for QLowEnergyController
+ * which require a remote device and can thus not run completely automated.
+ *
+ * This testcase acts as a bluetooth LE *client*.
+ * The counterpart *server* device is the "bluetoothtestdevice" in the same
+ * repository and it needs to be ran when this testcase is ran.
+ *
+ * The name of the server device needs to be adjusted in this code so that
+ * this LE client can find it. For example on macOS and Linux it is a generic
+ * "BluetoothTestDevice" where as on Android it is the device's bluetooth name
+ * set by the user. Please see the BTLE_SERVER_DEVICE_NAME below.
+ */
+class tst_qlowenergycontroller_device : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_qlowenergycontroller_device();
+ ~tst_qlowenergycontroller_device();
+private slots:
+ void initTestCase();
+ void init();
+ void cleanup();
+ void cleanupTestCase();
+
+ // Keep readServerPlatform as the first test, later tests
+ // may depend on its results.
+ void readServerPlatform();
+
+#if defined(QT_BLUETOOTH_MTU_SUPPORTED)
+ void checkMtuNegotiation();
+#endif
+#if defined(QT_BLUETOOTH_RSSI_SUPPORTED)
+ void rssiRead();
+#endif
+ void readWriteLargeCharacteristic();
+ void readWriteLargeDescriptor();
+ void readDuringServiceDiscovery();
+ void readNotificationAndIndicationProperty();
+ void testNotificationAndIndication();
+ void testRepeatedCharacteristicsWrite();
+
+public:
+ void checkconnectionCounter(std::unique_ptr<QLowEnergyController> &control);
+ static int connectionCounter;
+
+private:
+ void discoverTestServer();
+
+ std::unique_ptr<QBluetoothDeviceDiscoveryAgent> mDevAgent;
+ std::unique_ptr<QLowEnergyController> mController;
+ QBluetoothDeviceInfo mRemoteDeviceInfo;
+ QString mServerDeviceName;
+ QByteArray mServerPlatform;
+#if QT_CONFIG(permissions)
+ Qt::PermissionStatus permissionStatus = Qt::PermissionStatus::Undetermined;
+#endif
+};
+
+// connectionCounter is used to check that the server-side connect events
+// occur as expected. On the first time when the value is the initial "-1"
+// we read the current connection count from a service/characteristic providing it.
+// This way we don't need to always restart the server-side for testing
+int tst_qlowenergycontroller_device::connectionCounter = -1;
+
+tst_qlowenergycontroller_device::tst_qlowenergycontroller_device()
+{
+ QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
+#if QT_CONFIG(permissions)
+ // FIXME: Android has more specific BT permissions, fix when appropriate
+ // change is done in qtbase
+ permissionStatus = qApp->checkPermission(QBluetoothPermission{});
+ if (qApp->checkPermission(QBluetoothPermission{}) == Qt::PermissionStatus::Undetermined) {
+ QTestEventLoop loop;
+ qApp->requestPermission(QBluetoothPermission{}, [this, &loop](const QPermission &permission){
+ permissionStatus = permission.status();
+ loop.exitLoop();
+ });
+ if (permissionStatus == Qt::PermissionStatus::Undetermined)
+ loop.enterLoopMSecs(30000);
+ }
+#endif
+}
+
+tst_qlowenergycontroller_device::~tst_qlowenergycontroller_device() { }
+
+void tst_qlowenergycontroller_device::initTestCase()
+{
+#if QT_CONFIG(permissions)
+ if (permissionStatus != Qt::PermissionStatus::Granted)
+ QSKIP("This manual test requires Blutooth permissions granted.");
+#endif
+ qDebug() << "Testcase build time: " << __TIME__;
+ mDevAgent.reset(new QBluetoothDeviceDiscoveryAgent(this));
+ mDevAgent->setLowEnergyDiscoveryTimeout(75000);
+ mServerDeviceName = qEnvironmentVariable("BTLE_SERVER_DEVICE_NAME");
+ if (mServerDeviceName.isEmpty())
+ mServerDeviceName = QStringLiteral("BluetoothTestDevice");
+ qDebug() << "Using server device name for testing: " << mServerDeviceName;
+ qDebug() << "To change this set BTLE_SERVER_DEVICE_NAME environment variable";
+}
+
+void tst_qlowenergycontroller_device::discoverTestServer()
+{
+ mRemoteDeviceInfo = QBluetoothDeviceInfo(); // Invalidate whatever we had before
+ QSignalSpy finishedSpy(mDevAgent.get(), SIGNAL(finished()));
+ QSignalSpy canceledSpy(mDevAgent.get(), SIGNAL(canceled()));
+ // there should be no changes yet
+ QVERIFY(finishedSpy.isValid() && finishedSpy.isEmpty());
+ QVERIFY(canceledSpy.isValid() && canceledSpy.isEmpty());
+
+ QObject forLifeTime;
+ QObject::connect(mDevAgent.get(), &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
+ &forLifeTime, [&](const QBluetoothDeviceInfo& info) {
+ if (info.name() == mServerDeviceName) {
+ qDebug() << "Matching server device discovered, stopping device discovery agent";
+ mDevAgent->stop();
+ }
+ });
+
+ // Start device discovery
+ mDevAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
+ QTRY_VERIFY_WITH_TIMEOUT(!finishedSpy.isEmpty() || !canceledSpy.isEmpty(), 80000);
+
+ // Verify that we have found a matching server device
+ bool deviceFound = false;
+ const QList<QBluetoothDeviceInfo> infos = mDevAgent->discoveredDevices();
+ for (const QBluetoothDeviceInfo &info : infos) {
+ if (info.name() == mServerDeviceName) {
+ mRemoteDeviceInfo = info;
+ deviceFound = true;
+ qDebug() << "Found a matching server device" << info.name() << info.address();
+ break;
+ }
+ qDebug() << "Ignoring a non-matching device:" << info.name() << info.address();
+ }
+ QVERIFY2(deviceFound, "Cannot find remote device.");
+}
+
+
+void tst_qlowenergycontroller_device::init()
+{
+ // Connect to the test server. If unsuccessful, rediscover and retry.
+ // Rediscovery may be needed as the address of the remote can change and
+ // also at least Bluez backend recovers from its own internal errors
+ // more likely making the test less flaky
+ while (!mController || mController->state() != QLowEnergyController::ConnectedState) {
+ discoverTestServer();
+ QVERIFY(mRemoteDeviceInfo.isValid());
+ mController.reset(QLowEnergyController::createCentral(mRemoteDeviceInfo));
+ mController->connectToDevice();
+ QTRY_VERIFY_WITH_TIMEOUT(mController->state() != QLowEnergyController::ConnectingState, 45000);
+ if (mController->state() != QLowEnergyController::ConnectedState) {
+ mController.reset();
+ qDebug() << "Retrying connecting to the server in 5 seconds";
+ QTest::qWait(5000);
+ }
+ }
+ QCOMPARE(mController->state(), QLowEnergyController::ConnectedState);
+ QCOMPARE(mController->error(), QLowEnergyController::NoError);
+}
+
+void tst_qlowenergycontroller_device::cleanup()
+{
+ mController->disconnectFromDevice();
+
+ // Attempt a graceful close. If the test has already failed, the QTRY would exit immediately
+ if (!QTest::currentTestFailed())
+ QTRY_VERIFY_WITH_TIMEOUT(mController->state() ==
+ QLowEnergyController::UnconnectedState, 30000);
+ else
+ QTest::qWait(2000);
+
+ QCOMPARE(mController->state(), QLowEnergyController::UnconnectedState);
+ qDebug() << "Disconnected from remote device, waiting 5s before deleting controller.";
+ QTest::qWait(5000);
+ mController.reset();
+}
+
+void tst_qlowenergycontroller_device::cleanupTestCase() { }
+
+// The readServerPlatform should always be the first actual test function to execute.
+// It reads a characteristic where the server reports on which platform it runs on.
+// This information can then be used to adjust the test case's behavior accordingly;
+// different platforms support slightly different things.
+void tst_qlowenergycontroller_device::readServerPlatform()
+{
+ QVERIFY(mController->services().isEmpty());
+ mController->discoverServices();
+ QTRY_COMPARE(mController->state(), QLowEnergyController::DiscoveredState);
+ QCOMPARE(mController->error(), QLowEnergyController::NoError);
+
+ QSharedPointer<QLowEnergyService> service(
+ mController->createServiceObject(QBluetoothUuid(platformIdentifierServiceUuid)));
+ QVERIFY(service != nullptr);
+ service->discoverDetails(QLowEnergyService::FullDiscovery);
+ QTRY_COMPARE(service->state(), QLowEnergyService::ServiceState::RemoteServiceDiscovered);
+
+ auto characteristic = service->characteristic(QBluetoothUuid(platformIdentifierCharUuid));
+ mServerPlatform = characteristic.value();
+ qDebug() << "Server reported its running on: " << mServerPlatform;
+ QVERIFY(!mServerPlatform.isEmpty());
+}
+
+
+#if defined(QT_BLUETOOTH_MTU_SUPPORTED)
+void tst_qlowenergycontroller_device::checkMtuNegotiation()
+{
+ // service discovery, including MTU negotiation
+ qDebug() << "Client-side MTU after connect" << mController->mtu();
+ QVERIFY(mController->services().isEmpty());
+ mController->discoverServices();
+ QTRY_COMPARE(mController->state(), QLowEnergyController::DiscoveredState);
+ QCOMPARE(mController->error(), QLowEnergyController::NoError);
+
+ checkconnectionCounter(mController);
+
+ // now a larger MTU should have been negotiated
+ QTRY_VERIFY(mController->mtu() > 23);
+ qDebug() << "MTU after service discovery" << mController->mtu();
+
+ // check that central and peripheral agree on negotiated mtu
+ QSharedPointer<QLowEnergyService> service(
+ mController->createServiceObject(QBluetoothUuid(mtuServiceUuid)));
+ QVERIFY(service != nullptr);
+ service->discoverDetails(QLowEnergyService::FullDiscovery);
+ QTRY_COMPARE(service->state(), QLowEnergyService::ServiceState::RemoteServiceDiscovered);
+
+ auto characteristic = service->characteristic(QBluetoothUuid(mtuCharUuid));
+ int mtu;
+ memcpy(&mtu, characteristic.value().constData(), sizeof(int));
+ qDebug() << "MTU reported by server-side:" << mtu;
+ // Server-side mtu is not supported on all platforms
+ if (mServerPlatform != "linux" && mServerPlatform != "darwin")
+ QCOMPARE(mtu, mController->mtu());
+}
+#endif
+#undef QT_BLUETOOTH_MTU_SUPPORTED
+
+#if defined(QT_BLUETOOTH_RSSI_SUPPORTED)
+
+#define READ_AND_VERIFY_RSSI_VALUE \
+ errorSpy.clear(); \
+ rssiSpy.clear(); \
+ mController->readRssi(); \
+ QTRY_VERIFY(!rssiSpy.isEmpty()); \
+ QVERIFY(errorSpy.isEmpty()); \
+ rssi = rssiSpy.takeFirst().at(0).toInt(); \
+ QCOMPARE_GE(rssi, -127); \
+ QCOMPARE_LE(rssi, 127); \
+
+void tst_qlowenergycontroller_device::rssiRead()
+{
+ QSignalSpy errorSpy(mController.get(), &QLowEnergyController::errorOccurred);
+ QSignalSpy rssiSpy(mController.get(), &QLowEnergyController::rssiRead);
+ int rssi = 1000; // valid values are -127..127
+
+ // 1) Read RSSI in connected state
+ QCOMPARE(mController->state(), QLowEnergyController::ConnectedState);
+ READ_AND_VERIFY_RSSI_VALUE;
+ // Check that the value changes. This might seem flaky with stationary bluetooth
+ // devices but in practice the RSSI constantly fluctuates
+ const int initialRssi = rssi;
+ for (int attempt = 1; attempt < 20; attempt++) {
+ READ_AND_VERIFY_RSSI_VALUE;
+ QTest::qWait(200); // Provide a bit time for the RSSI to change
+ if (rssi != initialRssi)
+ break;
+ }
+ QVERIFY(rssi != initialRssi);
+
+ // 2) Read RSSI while discovering services
+ QVERIFY(mController->services().isEmpty());
+ mController->discoverServices();
+ QCOMPARE(mController->state(), QLowEnergyController::DiscoveringState);
+ READ_AND_VERIFY_RSSI_VALUE;
+
+ // 3) Read RSSI after services have been discovered
+ QTRY_COMPARE(mController->state(), QLowEnergyController::DiscoveredState);
+ READ_AND_VERIFY_RSSI_VALUE;
+
+ // 4) Read RSSI while discovering service details
+ QSharedPointer<QLowEnergyService> service(mController->createServiceObject(
+ QBluetoothUuid(repeatedWriteServiceUuid)));
+ QVERIFY(service != nullptr);
+ service->discoverDetails(QLowEnergyService::FullDiscovery);
+ QCOMPARE(service->state(), QLowEnergyService::ServiceState::RemoteServiceDiscovering);
+ READ_AND_VERIFY_RSSI_VALUE;
+
+ // 5) Read RSSI after service detail discovery
+ QTRY_COMPARE(service->state(), QLowEnergyService::ServiceState::RemoteServiceDiscovered);
+ READ_AND_VERIFY_RSSI_VALUE;
+
+ checkconnectionCounter(mController);
+
+ // 6) Read RSSI amidst characteristic reads and writes
+ QSignalSpy writeSpy(service.get(), &QLowEnergyService::characteristicWritten);
+ QSignalSpy readSpy(service.get(), &QLowEnergyService::characteristicRead);
+ auto characteristic = service->characteristic(QBluetoothUuid(repeatedWriteTargetCharUuid));
+ QByteArray value(8, 'a');
+ service->writeCharacteristic(characteristic, value);
+ READ_AND_VERIFY_RSSI_VALUE;
+ QTRY_VERIFY(!writeSpy.isEmpty());
+
+ service->readCharacteristic(characteristic);
+ READ_AND_VERIFY_RSSI_VALUE;
+ QTRY_VERIFY(!readSpy.isEmpty());
+
+ // A bit of stress-testing to check that read/write and
+ // RSSI reading don't interfere with one another
+ writeSpy.clear();
+ readSpy.clear();
+ rssiSpy.clear();
+ errorSpy.clear();
+ const int TIMES = 5;
+ for (int i = 0; i < TIMES; i++) {
+ mController->readRssi();
+ service->writeCharacteristic(characteristic, value);
+ mController->readRssi();
+ service->readCharacteristic(characteristic);
+ }
+ QTRY_COMPARE(writeSpy.size(), TIMES);
+ QTRY_COMPARE(readSpy.size(), TIMES);
+#if defined(Q_OS_ANDROID)
+ QTRY_COMPARE(rssiSpy.size(), TIMES * 2);
+#else
+ // On darwin several pending requests will get one callback
+ QTRY_COMPARE_GE(rssiSpy.size(), 1);
+#endif
+ QVERIFY(errorSpy.isEmpty());
+
+ // 7) Disconnect the device and verify we get error for RSSI read
+ errorSpy.clear();
+ rssiSpy.clear();
+ mController->disconnectFromDevice();
+ // First right after requesting disconnect
+ mController->readRssi();
+ QTRY_COMPARE(errorSpy.size(), 1);
+ QCOMPARE(errorSpy.takeFirst().at(0).value<QLowEnergyController::Error>(),
+ QLowEnergyController::Error::RssiReadError);
+ QCOMPARE(mController->error(), QLowEnergyController::Error::RssiReadError);
+ QVERIFY(rssiSpy.isEmpty());
+
+ // Then once the disconnection is complete
+ QTRY_COMPARE(mController->state(), QLowEnergyController::UnconnectedState);
+ errorSpy.clear();
+ mController->readRssi();
+ QTRY_COMPARE(errorSpy.size(), 1);
+ QCOMPARE(errorSpy.takeFirst().at(0).value<QLowEnergyController::Error>(),
+ QLowEnergyController::Error::RssiReadError);
+ QCOMPARE(mController->error(), QLowEnergyController::Error::RssiReadError);
+ QVERIFY(rssiSpy.isEmpty());
+}
+#endif
+#undef QT_BLUETOOTH_RSSI_SUPPORTED
+
+void tst_qlowenergycontroller_device::checkconnectionCounter(
+ std::unique_ptr<QLowEnergyController> &mController)
+{
+ // on darwin the server-side connect/disconnect events are not reported reliably
+ if (mServerPlatform == "darwin")
+ return;
+ QSharedPointer<QLowEnergyService> service(
+ mController->createServiceObject(QBluetoothUuid(connectionCountServiceUuid)));
+ QVERIFY(service != nullptr);
+ service->discoverDetails(QLowEnergyService::FullDiscovery);
+ QTRY_COMPARE(service->state(), QLowEnergyService::ServiceState::RemoteServiceDiscovered);
+
+ auto counterCharacteristic = service->characteristic(QBluetoothUuid(connectionCountCharUuid));
+ // If we have just started the test, read the current connection counter from the server.
+ // The connection counter is essentially the number of "connected" events the server
+ // has had.
+ if (connectionCounter == -1) {
+ memcpy(&connectionCounter, counterCharacteristic.value().constData(), sizeof(int));
+ qDebug() << "Connection counter initialized from the server to:" << connectionCounter;
+ } else {
+ connectionCounter++;
+ QByteArray value((const char *)&connectionCounter, sizeof(int));
+ QCOMPARE(counterCharacteristic.value(), value);
+ }
+}
+
+void tst_qlowenergycontroller_device::readWriteLargeCharacteristic()
+{
+ // This tests reading and writing a large characteristic value
+ //
+ // Most modern platforms cope with up-to 512 bytes. One exception is Bluez DBus peripheral,
+ // which may reject a write from client when going above 508 due to the way it internally
+ // checks the payload size (tested with Bluez 5.64).
+ //
+ // This test can also be used for testing long (aka prepared) writes & reads by setting
+ // the MTU to for example 50 bytes. Asking a specific MTU is platform-specific and
+ // there is no Qt API for it
+ QVERIFY(mController->services().isEmpty());
+ mController->discoverServices();
+ QTRY_COMPARE(mController->state(), QLowEnergyController::DiscoveredState);
+
+ checkconnectionCounter(mController);
+
+ QSharedPointer<QLowEnergyService> service(
+ mController->createServiceObject(QBluetoothUuid(largeAttributeServiceUuid)));
+ QVERIFY(service != nullptr);
+ service->discoverDetails(QLowEnergyService::SkipValueDiscovery);
+ QTRY_COMPARE(service->state(), QLowEnergyService::ServiceState::RemoteServiceDiscovered);
+
+ QSignalSpy readSpy(service.get(), &QLowEnergyService::characteristicRead);
+ QSignalSpy writtenSpy(service.get(), &QLowEnergyService::characteristicWritten);
+
+ // The service discovery skipped the values => check that the default values are all zeroes
+ auto characteristic = service->characteristic(QBluetoothUuid(largeAttributeCharUuid));
+ QVERIFY(characteristic.isValid());
+ QByteArray testArray(0);
+ qDebug() << "Initial large characteristic value:" << characteristic.value();
+ QCOMPARE(characteristic.value(), testArray);
+
+ // Read the characteristic value and verify it is the one the server-side sets (0x0b 0x00 ..)
+ service->readCharacteristic(characteristic);
+ QTRY_COMPARE(readSpy.size(), 1);
+ qDebug() << "Large characteristic value after read:" << characteristic.value();
+ testArray = QByteArray(largeAttributeSize, 0);
+ testArray[0] = 0x0b;
+ QCOMPARE(characteristic.value(), testArray);
+
+ // Write a new value to characteristic and read it back
+ for (int i = 0; i < largeAttributeSize; ++i) {
+ testArray[i] = i % 5;
+ }
+ service->writeCharacteristic(characteristic, testArray);
+ QCOMPARE(service->error(), QLowEnergyService::ServiceError::NoError);
+ QTRY_COMPARE(writtenSpy.size(), 1);
+
+ service->readCharacteristic(characteristic);
+ QTRY_COMPARE(readSpy.size(), 2);
+ qDebug() << "Large characteristic value after write/read:" << characteristic.value();
+ QCOMPARE(characteristic.value(), testArray);
+}
+
+void tst_qlowenergycontroller_device::readWriteLargeDescriptor()
+{
+ // This tests reading and writing a large descriptor value
+ QVERIFY(mController->services().isEmpty());
+ mController->discoverServices();
+ QTRY_COMPARE(mController->state(), QLowEnergyController::DiscoveredState);
+
+ checkconnectionCounter(mController);
+
+ QSharedPointer<QLowEnergyService> service(
+ mController->createServiceObject(QBluetoothUuid(largeAttributeServiceUuid)));
+ QVERIFY(service != nullptr);
+ service->discoverDetails(QLowEnergyService::FullDiscovery);
+ QTRY_COMPARE(service->state(), QLowEnergyService::ServiceState::RemoteServiceDiscovered);
+
+ QSignalSpy readSpy(service.get(), &QLowEnergyService::descriptorRead);
+ QSignalSpy writtenSpy(service.get(), &QLowEnergyService::descriptorWritten);
+
+ auto characteristic = service->characteristic(QBluetoothUuid(largeAttributeCharUuid));
+ QVERIFY(characteristic.isValid());
+ auto descriptor = characteristic.descriptor(QBluetoothUuid(largeAttributeDescUuid));
+ QVERIFY(descriptor.isValid());
+
+ QByteArray testArray = QByteArray(largeAttributeSize, 0);
+ testArray[0] = 0xdd;
+
+ // Read descriptor value and verify it is what the server set (0xdd 0x00 ..)
+ QVERIFY(readSpy.isEmpty());
+ QVERIFY(writtenSpy.isEmpty());
+ service->readDescriptor(descriptor);
+ QTRY_COMPARE(readSpy.size(), 1);
+ qDebug() << "Large descriptor value after read:" << descriptor.value();
+ QCOMPARE(descriptor.value(), testArray);
+
+ // Write a new value to descriptor and read it back
+ for (int i = 0; i < largeAttributeSize; ++i) {
+ testArray[i] = i % 5;
+ }
+ service->writeDescriptor(descriptor, testArray);
+ QCOMPARE(service->error(), QLowEnergyService::ServiceError::NoError);
+ QTRY_COMPARE(writtenSpy.size(), 1);
+
+ service->readDescriptor(descriptor);
+ QTRY_COMPARE(readSpy.size(), 2);
+ qDebug() << "Large descriptor value after write/read:" << descriptor.value();
+ QCOMPARE(descriptor.value(), testArray);
+}
+
+void tst_qlowenergycontroller_device::readDuringServiceDiscovery()
+{
+ QVERIFY(mController->services().isEmpty());
+ mController->discoverServices();
+ QTRY_COMPARE(mController->state(), QLowEnergyController::DiscoveredState);
+
+ checkconnectionCounter(mController);
+
+ QSharedPointer<QLowEnergyService> service(
+ mController->createServiceObject(QBluetoothUuid(largeAttributeServiceUuid)));
+ QVERIFY(service != nullptr);
+ service->discoverDetails(QLowEnergyService::FullDiscovery);
+ QTRY_COMPARE(service->state(), QLowEnergyService::ServiceState::RemoteServiceDiscovered);
+
+ QSignalSpy readSpy(service.get(), &QLowEnergyService::characteristicRead);
+ QSignalSpy writtenSpy(service.get(), &QLowEnergyService::characteristicWritten);
+ QCOMPARE(readSpy.size(), 0);
+ QCOMPARE(writtenSpy.size(), 0);
+
+ // Value that is initially set on the characteristic at the server-side (0x0b 0x00 ..)
+ QByteArray testArray(largeAttributeSize, 0);
+ testArray[0] = 0x0b;
+
+ // We did a full service discovery and should have an initial value to compare
+ auto characteristic = service->characteristic(QBluetoothUuid(largeAttributeCharUuid));
+ QByteArray valueFromServiceDiscovery = characteristic.value();
+ qDebug() << "Large characteristic value from service discovery:" << valueFromServiceDiscovery;
+ // On darwin the server does not restart (disconnect) in-between the case runs
+ // and the initial value may be from a previous test function
+ if (mServerPlatform != "darwin")
+ QCOMPARE(characteristic.value(), testArray);
+
+ // Check that the value from service discovery and explicit characteristic read match
+ service->readCharacteristic(characteristic);
+ QTRY_COMPARE(readSpy.size(), 1);
+ qDebug() << "Large characteristic value after read:" << characteristic.value();
+ QCOMPARE(characteristic.value(), valueFromServiceDiscovery);
+
+ // Write a new value to the characteristic and read it back
+ for (int i = 0; i < largeAttributeSize; ++i) {
+ testArray[i] = i % 5;
+ }
+ service->writeCharacteristic(characteristic, testArray);
+ QCOMPARE(service->error(), QLowEnergyService::ServiceError::NoError);
+ QTRY_COMPARE(writtenSpy.size(), 1);
+
+ service->readCharacteristic(characteristic);
+ QTRY_COMPARE(readSpy.size(), 2);
+ qDebug() << "Large characteristic value after write/read:" << characteristic.value();
+ QCOMPARE(characteristic.value(), testArray);
+}
+
+void tst_qlowenergycontroller_device::readNotificationAndIndicationProperty()
+{
+ // discover services
+ QVERIFY(mController->services().isEmpty());
+ mController->discoverServices();
+ QTRY_COMPARE(mController->state(), QLowEnergyController::DiscoveredState);
+
+ checkconnectionCounter(mController);
+
+ // check test service is available
+ QVERIFY(mController->services().contains(QBluetoothUuid(notificationIndicationTestServiceUuid)));
+
+ // get service object
+ QSharedPointer<QLowEnergyService> service(mController->createServiceObject(
+ QBluetoothUuid(notificationIndicationTestServiceUuid)));
+ QVERIFY(service != nullptr);
+ service->discoverDetails(QLowEnergyService::FullDiscovery);
+ QTRY_COMPARE(service->state(), QLowEnergyService::ServiceState::RemoteServiceDiscovered);
+
+ // check that all four characteristics are found
+ QCOMPARE(service->characteristics().size(), 4);
+
+ // check that properties are correctly set
+ auto notifyOrIndicate = QLowEnergyCharacteristic::PropertyType::Notify
+ | QLowEnergyCharacteristic::PropertyType::Indicate;
+ {
+ QLowEnergyCharacteristic characteristic =
+ service->characteristic(QBluetoothUuid(notificationIndicationTestChar1Uuid));
+ QCOMPARE(characteristic.properties() & notifyOrIndicate, 0);
+ }
+ {
+ QLowEnergyCharacteristic characteristic =
+ service->characteristic(QBluetoothUuid(notificationIndicationTestChar2Uuid));
+ QCOMPARE(characteristic.properties() & notifyOrIndicate,
+ QLowEnergyCharacteristic::PropertyType::Notify);
+ }
+ {
+ QLowEnergyCharacteristic characteristic =
+ service->characteristic(QBluetoothUuid(notificationIndicationTestChar3Uuid));
+ QCOMPARE(characteristic.properties() & notifyOrIndicate,
+ QLowEnergyCharacteristic::PropertyType::Indicate);
+ }
+ {
+ QLowEnergyCharacteristic characteristic =
+ service->characteristic(QBluetoothUuid(notificationIndicationTestChar4Uuid));
+ QCOMPARE(characteristic.properties() & notifyOrIndicate, notifyOrIndicate);
+ }
+}
+
+void tst_qlowenergycontroller_device::testNotificationAndIndication()
+{
+ // discover services
+ QVERIFY(mController->services().isEmpty());
+ mController->discoverServices();
+ QTRY_COMPARE(mController->state(), QLowEnergyController::DiscoveredState);
+
+ checkconnectionCounter(mController);
+
+ // get service object
+ QSharedPointer<QLowEnergyService> service(mController->createServiceObject(
+ QBluetoothUuid(notificationIndicationTestServiceUuid)));
+ QVERIFY(service != nullptr);
+ service->discoverDetails(QLowEnergyService::FullDiscovery);
+ QTRY_COMPARE(service->state(), QLowEnergyService::ServiceState::RemoteServiceDiscovered);
+
+ // Verify that notification works
+ {
+ QLowEnergyCharacteristic characteristic =
+ service->characteristic(QBluetoothUuid(notificationIndicationTestChar2Uuid));
+ auto notifyOrIndicate = QLowEnergyCharacteristic::PropertyType::Notify
+ | QLowEnergyCharacteristic::PropertyType::Indicate;
+ QCOMPARE(characteristic.properties() & notifyOrIndicate,
+ QLowEnergyCharacteristic::PropertyType::Notify);
+
+ // getting cccd
+ QLowEnergyDescriptor cccd = characteristic.clientCharacteristicConfiguration();
+ QVERIFY(cccd.isValid());
+
+ // write to cccd
+ bool cccdWritten = false;
+ QObject dummy; // for lifetime management
+ QObject::connect(
+ service.get(), &QLowEnergyService::descriptorWritten, &dummy,
+ [&cccdWritten](const QLowEnergyDescriptor &info, const QByteArray &) {
+ if (info.uuid()
+ == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration) {
+ cccdWritten = true;
+ }
+ });
+ service->writeDescriptor(cccd, QLowEnergyCharacteristic::CCCDEnableNotification);
+ QTRY_VERIFY(cccdWritten);
+
+ // notification should be enabled
+ auto oldvalue = characteristic.value();
+ QCOMPARE(characteristic.value(), oldvalue);
+ // wait for change
+ QTRY_VERIFY(characteristic.value() != oldvalue);
+ // wait again
+ oldvalue = characteristic.value();
+ QCOMPARE(characteristic.value(), oldvalue);
+ // wait for change
+ QTRY_VERIFY(characteristic.value() != oldvalue);
+
+ // disable notification
+ cccdWritten = false;
+ service->writeDescriptor(cccd, QLowEnergyCharacteristic::CCCDDisable);
+ QTRY_VERIFY(cccdWritten);
+
+ // wait for a moment in case there is a value change just happening,
+ // then check that there are no more notifications:
+ QTest::qWait(200);
+ oldvalue = characteristic.value();
+ for (int i = 0; i < 3; ++i) {
+ QTest::qWait(100);
+ QCOMPARE(characteristic.value(), oldvalue);
+ }
+ }
+
+ // Verify that indication works
+ {
+ QLowEnergyCharacteristic characteristic =
+ service->characteristic(QBluetoothUuid(notificationIndicationTestChar3Uuid));
+ auto notifyOrIndicate = QLowEnergyCharacteristic::PropertyType::Notify
+ | QLowEnergyCharacteristic::PropertyType::Indicate;
+ QCOMPARE(characteristic.properties() & notifyOrIndicate,
+ QLowEnergyCharacteristic::PropertyType::Indicate);
+
+ // getting cccd
+ QLowEnergyDescriptor cccd = characteristic.clientCharacteristicConfiguration();
+ QVERIFY(cccd.isValid());
+
+ // write to cccd
+ bool cccdWritten = false;
+ QObject dummy; // for lifetime management
+ QObject::connect(
+ service.get(), &QLowEnergyService::descriptorWritten, &dummy,
+ [&cccdWritten](const QLowEnergyDescriptor &info, const QByteArray &) {
+ if (info.uuid()
+ == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration) {
+ cccdWritten = true;
+ }
+ });
+ QByteArray newValue = QByteArray::fromHex("0200");
+ service->writeDescriptor(cccd, newValue);
+ QTRY_VERIFY(cccdWritten);
+
+ // indication should be enabled
+ auto oldvalue = characteristic.value();
+ QCOMPARE(characteristic.value(), oldvalue);
+ // wait for change
+ QTRY_VERIFY(characteristic.value() != oldvalue);
+ // wait again
+ oldvalue = characteristic.value();
+ QCOMPARE(characteristic.value(), oldvalue);
+ // wait for change
+ QTRY_VERIFY(characteristic.value() != oldvalue);
+
+ // disable indication
+ cccdWritten = false;
+ newValue = QByteArray::fromHex("0000");
+ service->writeDescriptor(cccd, newValue);
+ QTRY_VERIFY(cccdWritten);
+
+ // wait for a moment in case there is a value change just happening,
+ // then check that there are no more notifications:
+ QTest::qWait(200);
+ oldvalue = characteristic.value();
+ for (int i = 0; i < 3; ++i) {
+ QTest::qWait(100);
+ QCOMPARE(characteristic.value(), oldvalue);
+ }
+ }
+
+ // indication and notification works
+#if defined(Q_OS_LINUX)
+ // If the client (this testcase) is linux and the characteristic has both
+ // NTF & IND supported, the Bluez stack will try to enable both NTF & IND
+ // at the same time regardless of what we write to CCCD. Darwin server will
+ // reject this as an error (ATT error 0xf5, which is a reserved error)
+ if (mServerPlatform != "darwin")
+#endif
+ {
+ QLowEnergyCharacteristic characteristic =
+ service->characteristic(QBluetoothUuid(notificationIndicationTestChar4Uuid));
+ auto notifyOrIndicate = QLowEnergyCharacteristic::PropertyType::Notify
+ | QLowEnergyCharacteristic::PropertyType::Indicate;
+ QCOMPARE(characteristic.properties() & notifyOrIndicate, notifyOrIndicate);
+
+ // getting cccd
+ QLowEnergyDescriptor cccd = characteristic.clientCharacteristicConfiguration();
+ QVERIFY(cccd.isValid());
+
+ // write to cccd
+ bool cccdWritten = false;
+ QObject dummy; // for lifetime management
+ QObject::connect(
+ service.get(), &QLowEnergyService::descriptorWritten, &dummy,
+ [&cccdWritten](const QLowEnergyDescriptor &info, const QByteArray &) {
+ if (info.uuid()
+ == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration) {
+ cccdWritten = true;
+ }
+ });
+ QByteArray newValue = QByteArray::fromHex("0100");
+ service->writeDescriptor(cccd, newValue);
+ QTRY_VERIFY(cccdWritten);
+
+ // notification should be enabled
+ auto oldvalue = characteristic.value();
+ QCOMPARE(characteristic.value(), oldvalue);
+ // wait for change
+ QTRY_VERIFY(characteristic.value() != oldvalue);
+ // wait again
+ oldvalue = characteristic.value();
+ QCOMPARE(characteristic.value(), oldvalue);
+ // wait for change
+ QTRY_VERIFY(characteristic.value() != oldvalue);
+
+ // disable notification
+ cccdWritten = false;
+ newValue = QByteArray::fromHex("0000");
+ service->writeDescriptor(cccd, newValue);
+ QTRY_VERIFY(cccdWritten);
+
+ // wait for a moment in case there is a value change just happening,
+ // then check that there are no more notifications:
+ QTest::qWait(200);
+ oldvalue = characteristic.value();
+ for (int i = 0; i < 3; ++i) {
+ QTest::qWait(100);
+ QCOMPARE(characteristic.value(), oldvalue);
+ }
+
+ newValue = QByteArray::fromHex("0200");
+ service->writeDescriptor(cccd, newValue);
+ QTRY_VERIFY(cccdWritten);
+
+ // indication should be enabled
+ oldvalue = characteristic.value();
+ QCOMPARE(characteristic.value(), oldvalue);
+ // wait for change
+ QTRY_VERIFY(characteristic.value() != oldvalue);
+ // wait again
+ oldvalue = characteristic.value();
+ QCOMPARE(characteristic.value(), oldvalue);
+ // wait for change
+ QTRY_VERIFY(characteristic.value() != oldvalue);
+
+ // disable indication
+ cccdWritten = false;
+ newValue = QByteArray::fromHex("0000");
+ service->writeDescriptor(cccd, newValue);
+ QTRY_VERIFY(cccdWritten);
+
+ // wait for a moment in case there is a value change just happening,
+ // then check that there are no more indications:
+ QTest::qWait(200);
+ oldvalue = characteristic.value();
+ for (int i = 0; i < 3; ++i) {
+ QTest::qWait(100);
+ QCOMPARE(characteristic.value(), oldvalue);
+ }
+ }
+}
+
+void tst_qlowenergycontroller_device::testRepeatedCharacteristicsWrite()
+{
+ // This test generates multiple consecutive writes to the same characteristic
+ // and waits for the notifications (on other characteristic) with the same
+ // values. After that it verifies that the received values are the same (and
+ // in the same order) as written values. The server writes each received
+ // value to a notifying characteristic, which allows us to perform the check.
+
+ // Discover services
+ QVERIFY(mController->services().isEmpty());
+ mController->discoverServices();
+ QTRY_COMPARE(mController->state(), QLowEnergyController::DiscoveredState);
+
+ checkconnectionCounter(mController);
+
+ // Get service object.
+ QSharedPointer<QLowEnergyService> service(mController->createServiceObject(
+ QBluetoothUuid(repeatedWriteServiceUuid)));
+ QVERIFY(service != nullptr);
+ service->discoverDetails(QLowEnergyService::FullDiscovery);
+ QTRY_COMPARE(service->state(), QLowEnergyService::ServiceState::RemoteServiceDiscovered);
+
+ // Enable notification.
+ QLowEnergyCharacteristic notifyChar =
+ service->characteristic(QBluetoothUuid(repeatedWriteNotifyCharUuid));
+ const auto notifyOrIndicate = QLowEnergyCharacteristic::PropertyType::Notify
+ | QLowEnergyCharacteristic::PropertyType::Indicate;
+ QCOMPARE(notifyChar.properties() & notifyOrIndicate,
+ QLowEnergyCharacteristic::PropertyType::Notify);
+
+ QLowEnergyDescriptor cccd = notifyChar.clientCharacteristicConfiguration();
+ QVERIFY(cccd.isValid());
+
+ QObject dummy; // for lifetime management
+ bool cccdWritten = false;
+ connect(service.get(), &QLowEnergyService::descriptorWritten, &dummy,
+ [&cccdWritten](const QLowEnergyDescriptor &info, const QByteArray &) {
+ if (info.uuid()
+ == QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration) {
+ cccdWritten = true;
+ }
+ });
+ service->writeDescriptor(cccd, QLowEnergyCharacteristic::CCCDEnableNotification);
+ QTRY_VERIFY(cccdWritten);
+
+ // Track the notifications of value changes.
+ QList<QByteArray> receivedValues;
+ connect(service.get(), &QLowEnergyService::characteristicChanged, &dummy,
+ [&receivedValues](const QLowEnergyCharacteristic &characteristic,
+ const QByteArray &value)
+ {
+ if (characteristic.uuid() == QBluetoothUuid(repeatedWriteNotifyCharUuid)) {
+ receivedValues.push_back(value);
+ }
+ });
+
+ // Write characteristics multiple times. This shouldn't crash, and all
+ // values should be written. We use the notifications to track it.
+ receivedValues.clear();
+ QList<QByteArray> sentValues;
+ QLowEnergyCharacteristic writeChar =
+ service->characteristic(QBluetoothUuid(repeatedWriteTargetCharUuid));
+ static const int totalWrites = 50;
+ QByteArray value(8, 0);
+ for (int i = 0; i < totalWrites; ++i) {
+ value[0] += 1;
+ value[7] += 1;
+ service->writeCharacteristic(writeChar, value);
+ sentValues.push_back(value);
+ }
+
+ // We expect to get notifications about all writes.
+ // We set a large timeout to be on a safe side.
+ QTRY_COMPARE_WITH_TIMEOUT(receivedValues.size(), totalWrites, 60000);
+ QCOMPARE(receivedValues, sentValues);
+}
+
+QTEST_MAIN(tst_qlowenergycontroller_device)
+
+#include "tst_qlowenergycontroller_device.moc"
diff --git a/tests/manual/qlowenergycontroller_peripheral/CMakeLists.txt b/tests/manual/qlowenergycontroller_peripheral/CMakeLists.txt
new file mode 100644
index 00000000..377e2dd3
--- /dev/null
+++ b/tests/manual/qlowenergycontroller_peripheral/CMakeLists.txt
@@ -0,0 +1,67 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16...3.21)
+
+if(NOT TARGET Qt::Bluetooth)
+ # for standalone build (and the only way for iOS)
+ project(tst_qlowenergycontroller_peripheral LANGUAGES CXX)
+
+ set(CMAKE_AUTOMOC ON)
+
+ find_package(Qt6 REQUIRED COMPONENTS Bluetooth Core Test Gui)
+
+ qt_add_executable(tst_qlowenergycontroller_peripheral
+ tst_qlowenergycontroller_peripheral.cpp
+ )
+ target_link_libraries(tst_qlowenergycontroller_peripheral
+ PUBLIC
+ Qt::Core
+ Qt::Bluetooth
+ Qt::Test
+ Qt::Gui
+ )
+
+else()
+
+ qt_internal_add_test(tst_qlowenergycontroller_peripheral
+ SOURCES
+ tst_qlowenergycontroller_peripheral.cpp
+ LIBRARIES
+ Qt::Bluetooth
+ )
+
+ qt_internal_extend_target(tst_qlowenergycontroller_peripheral
+ CONDITION ANDROID AND NOT ANDROID_EMBEDDED
+ DEFINES
+ QT_ANDROID_BLUETOOTH
+ )
+
+ if(MACOS)
+ # Explicitly link against the static permission plugin because tests
+ # currently don't have finalizers run for them except for iOS.
+ # TODO: Remove this when qtbase automatically runs finalizers for tests: QTBUG-112212
+ target_link_libraries(tst_qlowenergycontroller_peripheral
+ PRIVATE Qt6::QDarwinBluetoothPermissionPlugin)
+ endif()
+
+endif()
+
+set_target_properties(tst_qlowenergycontroller_peripheral PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+if(APPLE)
+ # Ninja has trouble with relative paths, convert to absolute as a workaround
+ get_filename_component(SHARED_PLIST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../shared ABSOLUTE)
+ if(IOS)
+ set_target_properties(tst_qlowenergycontroller_peripheral PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.ios.plist"
+ )
+ else()
+ set_target_properties(tst_qlowenergycontroller_peripheral PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST "${SHARED_PLIST_DIR}/Info.macos.plist"
+ )
+ endif()
+endif()
diff --git a/tests/manual/qlowenergycontroller_peripheral/tst_qlowenergycontroller_peripheral.cpp b/tests/manual/qlowenergycontroller_peripheral/tst_qlowenergycontroller_peripheral.cpp
new file mode 100644
index 00000000..061f614e
--- /dev/null
+++ b/tests/manual/qlowenergycontroller_peripheral/tst_qlowenergycontroller_peripheral.cpp
@@ -0,0 +1,167 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QTest>
+
+#include <QBluetoothLocalDevice>
+#include <QLowEnergyController>
+#include <QLowEnergyServiceData>
+#include <QLowEnergyCharacteristicData>
+#include <QLowEnergyDescriptorData>
+
+#if QT_CONFIG(permissions)
+#include <QtTest/qtesteventloop.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qpermissions.h>
+#include <QtCore/qnamespace.h>
+#endif // permissions
+
+using namespace Qt::Literals::StringLiterals;
+
+static constexpr auto leServiceUuid{"10f5e37c-ac16-11eb-ae5c-93d3a763feed"_L1};
+static constexpr auto leCharUuid1{"11f4f68e-ac16-11eb-9956-cfe55a8ccafe"_L1};
+static const qsizetype leCharacteristicSize = 4; // Set to 1...512 bytes
+static QByteArray leCharacteristicValue = QByteArray{leCharacteristicSize, 1};
+static QByteArray leDescriptorValue = "a descriptor value"_ba;
+
+class tst_qlowenergycontroller_peripheral : public QObject
+{
+ Q_OBJECT
+private slots:
+ void initTestCase();
+ void init();
+ void cleanup();
+
+ void localCharacteristicReadAfterUpdate();
+ void localDescriptorReadAfterUpdate();
+
+private:
+ QBluetoothHostInfo mDevice;
+ std::unique_ptr<QLowEnergyController> mController;
+ QList<QSharedPointer<QLowEnergyService>> mServices;
+};
+
+void tst_qlowenergycontroller_peripheral::initTestCase()
+{
+#ifndef Q_OS_IOS
+ auto devices = QBluetoothLocalDevice::allDevices();
+ if (devices.isEmpty())
+ QSKIP("Failed to find local adapter");
+ else
+ mDevice = devices.back();
+#endif // Q_OS_IOS
+
+#if QT_CONFIG(permissions)
+ Qt::PermissionStatus permissionStatus = qApp->checkPermission(QBluetoothPermission{});
+ // FIXME: Android will add more specific BT permissions, fix when appropriate
+ // change is in qtbase.
+ if (qApp->checkPermission(QBluetoothPermission{}) == Qt::PermissionStatus::Undetermined) {
+ QTestEventLoop loop;
+ qApp->requestPermission(QBluetoothPermission{}, [&permissionStatus, &loop](const QPermission &permission){
+ permissionStatus = permission.status();
+ loop.exitLoop();
+ });
+ if (permissionStatus == Qt::PermissionStatus::Undetermined)
+ loop.enterLoopMSecs(30000);
+ }
+ if (permissionStatus != Qt::PermissionStatus::Granted)
+ QSKIP("This manual test requires Blutooth permissions granted.");
+#endif // permissions
+}
+
+void tst_qlowenergycontroller_peripheral::init()
+{
+ QList<QLowEnergyServiceData> serviceDefinitions;
+
+ QLowEnergyServiceData sd;
+ sd.setType(QLowEnergyServiceData::ServiceTypePrimary);
+ sd.setUuid(QBluetoothUuid(leServiceUuid));
+
+ QLowEnergyCharacteristicData charData;
+ charData.setUuid(QBluetoothUuid(leCharUuid1));
+ charData.setValue(leCharacteristicValue);
+ charData.setValueLength(leCharacteristicSize, leCharacteristicSize);
+ charData.setProperties(QLowEnergyCharacteristic::PropertyType::Read
+ | QLowEnergyCharacteristic::PropertyType::Write
+ | QLowEnergyCharacteristic::PropertyType::Notify
+ | QLowEnergyCharacteristic::ExtendedProperty);
+
+ const QLowEnergyDescriptorData clientConfig(
+ QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration,
+ QLowEnergyCharacteristic::CCCDDisable);
+ charData.addDescriptor(clientConfig);
+
+ const QLowEnergyDescriptorData userDescription(
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription,
+ leDescriptorValue);
+ charData.addDescriptor(userDescription);
+
+ const QLowEnergyDescriptorData extendedProperties(
+ QBluetoothUuid::DescriptorType::CharacteristicExtendedProperties,
+ // From bluetooth specs: length 2 bytes
+ // bit 0: reliable write, bit 1: writable auxiliaries
+ QByteArray::fromHex("0300"));
+ charData.addDescriptor(extendedProperties);
+
+ sd.addCharacteristic(charData);
+
+ serviceDefinitions << sd;
+
+
+#ifndef Q_OS_IOS
+ mController.reset(QLowEnergyController::createPeripheral(mDevice.address()));
+#else
+ mController.reset(QLowEnergyController::createPeripheral());
+#endif // Q_OS_IOS
+ QVERIFY(mController);
+
+ for (const auto &serviceData : serviceDefinitions) {
+ mServices.emplaceBack(mController->addService(serviceData));
+ }
+}
+
+void tst_qlowenergycontroller_peripheral::cleanup()
+{
+ if (mController)
+ mController->stopAdvertising();
+
+ mController.reset();
+ mServices.clear();
+}
+
+void tst_qlowenergycontroller_peripheral::localCharacteristicReadAfterUpdate()
+{
+#ifdef Q_OS_WINDOWS
+ QSKIP("Windows does not support peripheral");
+#endif
+ auto characteristic = mServices[0]->characteristic(QBluetoothUuid(leCharUuid1));
+ QVERIFY(characteristic.isValid());
+ const auto initialValue = characteristic.value();
+ auto newValue = initialValue;
+ newValue[0] = newValue[0] + 1;
+ mServices[0]->writeCharacteristic(characteristic, newValue);
+ QTRY_COMPARE(characteristic.value(), newValue);
+}
+
+void tst_qlowenergycontroller_peripheral::localDescriptorReadAfterUpdate()
+{
+#ifdef Q_OS_WINDOWS
+ QSKIP("Windows does not support peripheral");
+#elif defined Q_OS_DARWIN
+ QSKIP("Apple devices do not support descriptor value update");
+#endif
+ auto characteristic = mServices[0]->characteristic(QBluetoothUuid(leCharUuid1));
+ QVERIFY(characteristic.isValid());
+ auto descriptor = characteristic.descriptor(
+ QBluetoothUuid::DescriptorType::CharacteristicUserDescription);
+ QVERIFY(descriptor.isValid());
+ const auto initialValue = descriptor.value();
+ auto newValue = initialValue;
+ newValue[0] = newValue[0] + 1;
+ mServices[0]->writeDescriptor(descriptor, newValue);
+ QCOMPARE(descriptor.value(), newValue);
+}
+
+QTEST_MAIN(tst_qlowenergycontroller_peripheral)
+
+#include "tst_qlowenergycontroller_peripheral.moc"
diff --git a/tests/shared/Info.ios.plist b/tests/shared/Info.ios.plist
new file mode 100644
index 00000000..8dc7f08e
--- /dev/null
+++ b/tests/shared/Info.ios.plist
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDisplayName</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>NSBluetoothAlwaysUsageDescription</key>
+ <string>BT test component wants to access your bluetooth adapter</string>
+ <key>UILaunchStoryboardName</key>
+ <string>LaunchScreen</string>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
diff --git a/tests/shared/Info.macos.plist b/tests/shared/Info.macos.plist
new file mode 100644
index 00000000..7c18450d
--- /dev/null
+++ b/tests/shared/Info.macos.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+ <key>NSBluetoothAlwaysUsageDescription</key>
+ <string>BT test component wants to access your bluetooth adapter</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/shared/bttestutil_p.h b/tests/shared/bttestutil_p.h
new file mode 100644
index 00000000..fb58c6b1
--- /dev/null
+++ b/tests/shared/bttestutil_p.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef BTTESTUTIL_P_H
+#define BTTESTUTIL_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/qcoreapplication.h>
+
+#ifdef Q_OS_ANDROID
+#include <QtCore/QJniObject>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+bool androidBluetoothEmulator()
+{
+#ifdef Q_OS_ANDROID
+ // QTBUG-106614, the Android-12+ emulator (API level 31+) emulates bluetooth.
+ // We need to skip tests on the CI to avoid timeouts when Android waits for bluetooth
+ // permission confirmation from the user. Currently the check below skips generally
+ // on emulator though, not only on CI
+ if (QNativeInterface::QAndroidApplication::sdkVersion() >= 31) {
+ const auto property = QJniObject::fromString("ro.kernel.qemu");
+ const char sysPropsClass[] = "android/os/SystemProperties";
+ const auto isQemu = QJniObject::callStaticObjectMethod<jstring>(
+ sysPropsClass, "get", property.object<jstring>());
+ if (isQemu.toString() == "1")
+ return true;
+ }
+#endif
+ return false;
+}
+
+QT_END_NAMESPACE
+
+#endif // BTTESTUTIL_P_H
diff --git a/tests/tests.pro b/tests/tests.pro
deleted file mode 100644
index e96b928c..00000000
--- a/tests/tests.pro
+++ /dev/null
@@ -1,4 +0,0 @@
-TEMPLATE = subdirs
-SUBDIRS += auto
-
-qtHaveModule(bluetooth):qtHaveModule(quick): SUBDIRS += bttestui