9#include <QCoreApplication>
10#include <QtCore/QLoggingCategory>
11#include <QtBluetooth/QBluetoothAddress>
12#include <QtBluetooth/QBluetoothDeviceInfo>
13#include <QtCore/QJniEnvironment>
14#include <QtCore/private/qandroidextras_p.h>
31 adapterAddress(deviceAdapter),
38 if (!adapter.isValid())
39 qCWarning(QT_BT_ANDROID) <<
"Device does not support Bluetooth";
47 if (leScanner.isValid())
48 leScanner.setField<jlong>(
"qtObject",
reinterpret_cast<jlong
>(
nullptr));
51 receiver->unregisterReceiver();
70void QBluetoothDeviceDiscoveryAgentPrivate::classicDiscoveryStartFail()
74 errorString = QBluetoothDeviceDiscoveryAgent::tr(
"Classic Discovery cannot be started");
75 emit q->errorOccurred(lastError);
79bool QBluetoothDeviceDiscoveryAgentPrivate::setErrorIfPowerOff()
83 const int state = adapter.callMethod<jint>(
"getState");
87 errorString = QBluetoothDeviceDiscoveryAgent::tr(
"Device is powered off");
88 emit q->errorOccurred(lastError);
115 if (!adapter.isValid()) {
116 qCWarning(QT_BT_ANDROID) <<
"Device does not support Bluetooth";
118 errorString = QBluetoothDeviceDiscoveryAgent::tr(
"Device does not support Bluetooth");
119 emit q->errorOccurred(lastError);
123 if (!adapterAddress.isNull()
124 && adapter.callMethod<jstring>(
"getAddress").toString()
125 != adapterAddress.toString()) {
126 qCWarning(QT_BT_ANDROID) <<
"Incorrect local adapter passed.";
128 errorString = QBluetoothDeviceDiscoveryAgent::tr(
"Passed address is not a local device.");
129 emit q->errorOccurred(lastError);
133 if (setErrorIfPowerOff())
138 <<
"Search not possible due to missing QBluetoothPermission::Access permission";
139 errorString = QBluetoothDeviceDiscoveryAgent::tr(
140 "Failed to start device discovery due to missing permissions.");
142 emit q->errorOccurred(lastError);
145 qCDebug(QT_BT_ANDROID) <<
"QBluetoothPermission::Access permission available";
148 bool locationTurnedOn =
true;
149 const QJniObject locString = QJniObject::getStaticObjectField(
150 "android/content/Context",
"LOCATION_SERVICE",
"Ljava/lang/String;");
153 QJniObject(QNativeInterface::QAndroidApplication::context()).callMethod<jobject>(
155 locString.object<jstring>());
157 if (locService.isValid()) {
158 if (QNativeInterface::QAndroidApplication::sdkVersion() >= 28) {
159 locationTurnedOn = bool(locService.callMethod<jboolean>(
"isLocationEnabled"));
163 locService.callMethod<QtJniTypes::List>(
"getProviders",
true);
165 if (listOfEnabledProviders.isValid()) {
166 int size = listOfEnabledProviders.callMethod<jint>(
"size");
167 locationTurnedOn =
size > 0;
168 qCDebug(QT_BT_ANDROID) <<
size <<
"enabled location providers detected.";
173 if (!locationTurnedOn) {
174 qCWarning(QT_BT_ANDROID) <<
"Search not possible due to turned off Location service";
176 errorString = QBluetoothDeviceDiscoveryAgent::tr(
"Location service turned off. Search is not possible.");
177 emit q->errorOccurred(lastError);
181 qCDebug(QT_BT_ANDROID) <<
"Location turned on";
187 qRegisterMetaType<QBluetoothDeviceInfo>();
195 discoveredDevices.
clear();
199 const bool success = adapter.callMethod<jboolean>(
"startDiscovery");
201 qCDebug(QT_BT_ANDROID) <<
"Classic Discovery cannot be started";
206 classicDiscoveryStartFail();
211 if (!deviceDiscoveryStartTimeout) {
218 deviceDiscoveryStartTimeout =
new QTimer(
this);
220 deviceDiscoveryStartTimeout->setSingleShot(
true);
224 deviceDiscoveryStartAttemptsLeft -= 1;
225 qCWarning(QT_BT_ANDROID) <<
"Discovery start not received, attempts left:"
226 << deviceDiscoveryStartAttemptsLeft;
228 if (setErrorIfPowerOff())
232 if (deviceDiscoveryStartAttemptsLeft <= 0) {
233 qCWarning(QT_BT_ANDROID) <<
"Classic device discovery failed to start";
234 (
void)adapter.callMethod<jboolean>(
"cancelDiscovery");
238 if (deviceDiscoveryStartAttemptsLeft > 0 &&
239 adapter.callMethod<jboolean>(
"startDiscovery"))
240 deviceDiscoveryStartTimeout->start();
242 classicDiscoveryStartFail();
244 startLowEnergyScan();
248 deviceDiscoveryStartTimeout->start();
251 <<
"QBluetoothDeviceDiscoveryAgentPrivate::start() - Classic search successfully started.";
258 startLowEnergyScan();
266 pendingStart =
false;
268 if (deviceDiscoveryStartTimeout)
269 deviceDiscoveryStartTimeout->stop();
282 pendingCancel =
true;
283 bool success = adapter.callMethod<jboolean>(
"cancelDiscovery");
286 errorString = QBluetoothDeviceDiscoveryAgent::tr(
"Discovery cannot be stopped");
287 emit q->errorOccurred(lastError);
295void QBluetoothDeviceDiscoveryAgentPrivate::processSdpDiscoveryFinished()
305 if (pendingCancel && !pendingStart) {
307 pendingCancel =
false;
309 }
else if (pendingStart) {
310 pendingStart = pendingCancel =
false;
311 start(requestedMethods);
314 if (setErrorIfPowerOff())
323 startLowEnergyScan();
327void QBluetoothDeviceDiscoveryAgentPrivate::processDiscoveredDevices(
347 if (discoveredDevices[
i].
rssi() !=
info.rssi()) {
348 qCDebug(QT_BT_ANDROID) <<
"Updating RSSI for" <<
info.address()
350 discoveredDevices[
i].setRssi(
info.rssi());
353 if (discoveredDevices[
i].manufacturerData() !=
info.manufacturerData()) {
354 qCDebug(QT_BT_ANDROID) <<
"Updating manufacturer data for" <<
info.address();
357 discoveredDevices[
i].setManufacturerData(
key,
info.manufacturerData(
key));
360 if (discoveredDevices[
i].serviceData() !=
info.serviceData()) {
361 qCDebug(QT_BT_ANDROID) <<
"Updating service data for" <<
info.address();
364 discoveredDevices[
i].setServiceData(
key,
info.serviceData(
key));
368 if (lowEnergySearchTimeout > 0) {
369 if (discoveredDevices[
i] !=
info) {
370 if (discoveredDevices.
at(
i).
name() ==
info.name()) {
371 qCDebug(QT_BT_ANDROID) <<
"Almost Duplicate " <<
info.address()
372 <<
info.name() <<
"- replacing in place";
378 emit q->deviceUpdated(discoveredDevices[
i], updatedFields);
388 emit q->deviceUpdated(discoveredDevices[
i], updatedFields);
395 qCDebug(QT_BT_ANDROID) <<
"Device found: " <<
info.name() <<
info.address().toString()
396 <<
"isLeScanResult:" << isLeResult
397 <<
"Manufacturer data size:" <<
info.manufacturerData().
size();
401void QBluetoothDeviceDiscoveryAgentPrivate::startLowEnergyScan()
407 if (!leScanner.isValid()) {
408 leScanner = QJniObject::construct<QtJniTypes::QtBtLECentral>(
409 QNativeInterface::QAndroidApplication::context());
410 if (!leScanner.isValid()) {
411 qCWarning(QT_BT_ANDROID) <<
"Cannot load BTLE device scan class";
417 leScanner.setField<jlong>(
"qtObject",
reinterpret_cast<long>(receiver));
420 jboolean
result = leScanner.callMethod<jboolean>(
"scanForLeDevice",
true);
422 qCWarning(QT_BT_ANDROID) <<
"Cannot start BTLE device scanner";
429 if (!leScanTimeout) {
430 leScanTimeout =
new QTimer(
this);
431 leScanTimeout->setSingleShot(
true);
433 this, &QBluetoothDeviceDiscoveryAgentPrivate::stopLowEnergyScan);
436 if (lowEnergySearchTimeout > 0) {
437 leScanTimeout->setInterval(lowEnergySearchTimeout);
438 leScanTimeout->start();
442 <<
"QBluetoothDeviceDiscoveryAgentPrivate::start() - Low Energy search successfully started.";
445void QBluetoothDeviceDiscoveryAgentPrivate::stopLowEnergyScan()
447 jboolean
result = leScanner.callMethod<jboolean>(
"scanForLeDevice",
false);
449 qCWarning(QT_BT_ANDROID) <<
"Cannot stop BTLE device scanner";
454 if (leScanTimeout->isActive()) {
456 leScanTimeout->stop();
static JNINativeMethod methods[]
QJniObject getDefaultBluetoothAdapter()
QT_BEGIN_NAMESPACE bool ensureAndroidPermission(QBluetoothPermission::CommunicationModes modes)
~QBluetoothDeviceDiscoveryAgentPrivate()
void start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
QBluetoothDeviceDiscoveryAgentPrivate(const QBluetoothAddress &deviceAdapter, QBluetoothDeviceDiscoveryAgent *parent)
static DiscoveryMethods supportedDiscoveryMethods()
This function returns the discovery methods supported by the current platform.
@ MissingPermissionsError
@ InvalidBluetoothAdapterError
@ LocationServiceTurnedOffError
QString name() const
Returns the name assigned to the device.
qint64 size() const
Returns the file size in bytes.
qsizetype size() const noexcept
const_reference at(qsizetype i) const noexcept
void replace(qsizetype i, parameter_type t)
void append(parameter_type t)
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
void clear()
Clears the contents of the string and makes it null.
void stop()
Stops the timer.
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
Combined button and popup list for selecting options.
static constexpr auto deviceDiscoveryStartTimeLimit
static constexpr short deviceDiscoveryStartMaxAttempts
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint64EXT address
GLdouble GLdouble GLdouble GLdouble q
QFileInfo info(fileName)
[8]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent