6#include "android/localdevicebroadcastreceiver_p.h"
7#include "android/androidutils_p.h"
8#include "android/jni_android_p.h"
9#include <QCoreApplication>
10#include <QtCore/QLoggingCategory>
11#include <QtCore/QJniEnvironment>
12#include <QtCore/QJniObject>
13#include <QtBluetooth/QBluetoothLocalDevice>
14#include <QtBluetooth/QBluetoothAddress>
18Q_DECLARE_LOGGING_CATEGORY(QT_BT_ANDROID)
20QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(
21 QBluetoothLocalDevice *q,
const QBluetoothAddress &address) :
24 registerQBluetoothLocalDeviceMetaType();
28 receiver =
new LocalDeviceBroadcastReceiver(q_ptr);
29 connect(receiver, &LocalDeviceBroadcastReceiver::hostModeStateChanged,
30 this, &QBluetoothLocalDevicePrivate::processHostModeChange);
31 connect(receiver, &LocalDeviceBroadcastReceiver::pairingStateChanged,
32 this, &QBluetoothLocalDevicePrivate::processPairingStateChanged);
33 connect(receiver, &LocalDeviceBroadcastReceiver::connectDeviceChanges,
34 this, &QBluetoothLocalDevicePrivate::processConnectDeviceChanges);
39 receiver->unregisterReceiver();
51 QJniObject adapter = getDefaultBluetoothAdapter();
53 if (!adapter.isValid()) {
54 qCWarning(QT_BT_ANDROID) <<
"Device does not support Bluetooth";
58 if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
59 qCWarning(QT_BT_ANDROID) <<
"Local device initialize() failed due to missing permissions";
63 obj =
new QJniObject(adapter);
64 if (!address.isNull()) {
65 const QString localAddress = obj->callMethod<jstring>(
"getAddress").toString();
66 if (localAddress != address.toString()) {
76 return obj ?
true :
false;
81 qCDebug(QT_BT_ANDROID) <<
"Processing host mode change:" << newMode
82 <<
", pending transition:" << pendingConnectableHostModeTransition;
83 if (!pendingConnectableHostModeTransition) {
85 emit q_ptr->hostModeStateChanged(newMode);
91 if (isValid() && newMode == QBluetoothLocalDevice::HostPoweredOff) {
92 const bool success = (
bool)QJniObject::callStaticMethod<jboolean>(
93 QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(),
96 qCWarning(QT_BT_ANDROID) <<
"Transitioning Bluetooth from OFF to ON failed";
97 emit q_ptr->errorOccurred(QBluetoothLocalDevice::UnknownError);
100 pendingConnectableHostModeTransition =
false;
107 for (qsizetype i = 0; i < pendingPairings.size(); ++i) {
108 if (pendingPairings.at(i).first == address)
116 const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing)
118 int index = pendingPairing(address);
123 QPair<QBluetoothAddress,
bool> entry = pendingPairings.takeAt(index);
124 if ((entry.second && pairing == QBluetoothLocalDevice::Paired)
125 || (!entry.second && pairing == QBluetoothLocalDevice::Unpaired)) {
126 emit q_ptr->pairingFinished(address, pairing);
128 emit q_ptr->errorOccurred(QBluetoothLocalDevice::PairingError);
135 if (isConnectEvent) {
136 if (connectedDevices.contains(address))
138 connectedDevices.append(address);
139 emit q_ptr->deviceConnected(address);
141 connectedDevices.removeAll(address);
142 emit q_ptr->deviceDisconnected(address);
146QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
148 d_ptr(
new QBluetoothLocalDevicePrivate(
this, QBluetoothAddress()))
152QBluetoothLocalDevice::QBluetoothLocalDevice(
const QBluetoothAddress &address, QObject *parent) :
154 d_ptr(
new QBluetoothLocalDevicePrivate(
this, address))
158QString QBluetoothLocalDevice::name()
const
160 if (d_ptr->adapter())
161 return d_ptr->adapter()->callMethod<jstring>(
"getName").toString();
166QBluetoothAddress QBluetoothLocalDevice::address()
const
169 if (d_ptr->adapter())
170 result = d_ptr->adapter()->callMethod<jstring>(
"getAddress").toString();
172 QBluetoothAddress address(result);
176void QBluetoothLocalDevice::powerOn()
178 if (hostMode() != HostPoweredOff)
181 if (d_ptr->adapter()) {
183 if (QNativeInterface::QAndroidApplication::sdkVersion() >= 31) {
184 success = (
bool)QJniObject::callStaticMethod<jboolean>(
185 QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(),
188 success = (
bool)d_ptr->adapter()->callMethod<jboolean>(
"enable");
191 qCWarning(QT_BT_ANDROID) <<
"Enabling bluetooth failed";
192 emit errorOccurred(QBluetoothLocalDevice::UnknownError);
197void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode requestedMode)
199 QBluetoothLocalDevice::HostMode nextMode = requestedMode;
200 if (requestedMode == HostDiscoverableLimitedInquiry)
201 nextMode = HostDiscoverable;
203 if (nextMode == hostMode())
208 case QBluetoothLocalDevice::HostPoweredOff: {
209 bool success =
false;
210 if (d_ptr->adapter()) {
211 if (QNativeInterface::QAndroidApplication::sdkVersion() >= 31) {
212 success = (
bool)QJniObject::callStaticMethod<jboolean>(
213 QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(),
216 success = (
bool)d_ptr->adapter()->callMethod<jboolean>(
"disable");
220 qCWarning(QT_BT_ANDROID) <<
"Unable to power off the adapter";
221 emit errorOccurred(QBluetoothLocalDevice::UnknownError);
226 case QBluetoothLocalDevice::HostConnectable: {
227 if (hostMode() == QBluetoothLocalDevice::HostDiscoverable) {
231 setHostMode(QBluetoothLocalDevice::HostPoweredOff);
232 d_ptr->pendingConnectableHostModeTransition =
true;
234 const bool success = (
bool)QJniObject::callStaticMethod<jboolean>(
235 QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(),
238 qCWarning(QT_BT_ANDROID) <<
"Unable to enable the Bluetooth";
239 emit errorOccurred(QBluetoothLocalDevice::UnknownError);
245 case QBluetoothLocalDevice::HostDiscoverable: {
246 if (!ensureAndroidPermission(QBluetoothPermission::Advertise)) {
247 qCWarning(QT_BT_ANDROID) <<
"Local device setHostMode() failed due to "
248 "missing permissions";
249 emit errorOccurred(QBluetoothLocalDevice::MissingPermissionsError);
252 const bool success = (
bool)QJniObject::callStaticMethod<jboolean>(
253 QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(),
256 qCWarning(QT_BT_ANDROID) <<
"Unable to set Bluetooth as discoverable";
257 emit errorOccurred(QBluetoothLocalDevice::UnknownError);
262 qCWarning(QT_BT_ANDROID) <<
"setHostMode() unsupported host mode:" << nextMode;
267QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode()
const
269 if (d_ptr->adapter()) {
270 jint scanMode = d_ptr->adapter()->callMethod<jint>(
"getScanMode");
274 return HostPoweredOff;
276 return HostConnectable;
278 return HostDiscoverable;
284 return HostPoweredOff;
287QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
290 if (!ensureAndroidPermission(QBluetoothPermission::Access)) {
291 qCWarning(QT_BT_ANDROID) <<
"Local device allDevices() failed due to "
292 "missing permissions";
296 QList<QBluetoothHostInfo> localDevices;
298 QJniObject o = getDefaultBluetoothAdapter();
300 QBluetoothHostInfo info;
301 info.setName(o.callMethod<jstring>(
"getName").toString());
302 info.setAddress(QBluetoothAddress(o.callMethod<jstring>(
"getAddress").toString()));
303 localDevices.append(info);
308void QBluetoothLocalDevice::requestPairing(
const QBluetoothAddress &address, Pairing pairing)
310 if (address.isNull()) {
311 QMetaObject::invokeMethod(
this,
"errorOccurred", Qt::QueuedConnection,
312 Q_ARG(QBluetoothLocalDevice::Error,
313 QBluetoothLocalDevice::PairingError));
317 const Pairing previousPairing = pairingStatus(address);
318 Pairing newPairing = pairing;
319 if (pairing == AuthorizedPaired)
322 if (previousPairing == newPairing) {
323 QMetaObject::invokeMethod(
this,
"pairingFinished", Qt::QueuedConnection,
324 Q_ARG(QBluetoothAddress, address),
325 Q_ARG(QBluetoothLocalDevice::Pairing, newPairing));
329 if (!d_ptr->adapter()) {
330 qCWarning(QT_BT_ANDROID) <<
"Unable to pair, invalid adapter";
331 QMetaObject::invokeMethod(
this,
"errorOccurred", Qt::QueuedConnection,
332 Q_ARG(QBluetoothLocalDevice::Error,
333 QBluetoothLocalDevice::PairingError));
337 QJniObject inputString = QJniObject::fromString(address.toString());
338 jboolean success = QJniObject::callStaticMethod<jboolean>(
339 QtJniTypes::Traits<QtJniTypes::QtBtBroadcastReceiver>::className(),
341 inputString.object<jstring>(),
342 jboolean(newPairing == Paired ? JNI_TRUE : JNI_FALSE));
345 QMetaObject::invokeMethod(
this,
"errorOccurred", Qt::QueuedConnection,
346 Q_ARG(QBluetoothLocalDevice::Error,
347 QBluetoothLocalDevice::PairingError));
349 d_ptr->pendingPairings.append(qMakePair(address, newPairing == Paired ?
true :
false));
353QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
354 const QBluetoothAddress &address)
const
356 if (address.isNull() || !d_ptr->adapter())
359 QJniObject inputString = QJniObject::fromString(address.toString());
360 QJniObject remoteDevice
361 = d_ptr->adapter()->callMethod<QtJniTypes::BluetoothDevice>(
"getRemoteDevice",
362 inputString.object<jstring>());
364 if (!remoteDevice.isValid())
367 jint bondState = remoteDevice.callMethod<jint>(
"getBondState");
378QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices()
const
381
382
383
384
385
386
387
388
389
390
391 using namespace QtJniTypes;
393 const auto connectedDevices = QtBtBroadcastReceiver::callStaticMethod<String[]>(
"getConnectedDevices");
395 if (!connectedDevices.isValid())
396 return d_ptr->connectedDevices;
398 QList<QBluetoothAddress> knownAddresses = d_ptr->connectedDevices;
399 for (
const auto &device : connectedDevices) {
400 QBluetoothAddress address(device.toString());
401 if (!address.isNull() && !knownAddresses.contains(address))
402 knownAddresses.append(address);
405 return knownAddresses;