File indexing completed on 2024-12-08 12:15:33
0001 /* 0002 * BluezQt - Asynchronous Bluez wrapper library 0003 * 0004 * SPDX-FileCopyrightText: 2014 David Rosca <nowrep@gmail.com> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #include "device_p.h" 0010 #include "device.h" 0011 #include "gattserviceremote_p.h" 0012 #include "gattserviceremote.h" 0013 #include "adapter.h" 0014 #include "battery.h" 0015 #include "battery_p.h" 0016 #include "device.h" 0017 #include "input.h" 0018 #include "input_p.h" 0019 #include "macros.h" 0020 #include "mediaplayer.h" 0021 #include "mediaplayer_p.h" 0022 #include "mediatransport.h" 0023 #include "mediatransport_p.h" 0024 #include "utils.h" 0025 0026 namespace BluezQt 0027 { 0028 static const qint16 INVALID_RSSI = -32768; // qint16 minimum 0029 0030 DevicePrivate::DevicePrivate(const QString &path, const QVariantMap &properties, const AdapterPtr &adapter) 0031 : QObject() 0032 , m_dbusProperties(nullptr) 0033 , m_deviceClass(0) 0034 , m_appearance(0) 0035 , m_paired(false) 0036 , m_trusted(false) 0037 , m_blocked(false) 0038 , m_legacyPairing(false) 0039 , m_rssi(INVALID_RSSI) 0040 , m_manufacturerData(ManData()) 0041 , m_servicesResolved(false) 0042 , m_connected(false) 0043 , m_adapter(adapter) 0044 { 0045 m_bluezDevice = new BluezDevice(Strings::orgBluez(), path, DBusConnection::orgBluez(), this); 0046 0047 init(properties); 0048 } 0049 0050 static QHash<QString, QByteArray> toByteArrayHash(const QDBusArgument &arg) 0051 { 0052 if (arg.currentType() != QDBusArgument::MapType) { 0053 return {}; 0054 } 0055 0056 QHash<QString, QByteArray> result; 0057 arg.beginMap(); 0058 while (!arg.atEnd()) { 0059 arg.beginMapEntry(); 0060 QString key; 0061 QDBusVariant value; 0062 arg >> key >> value; 0063 result.insert(key.toUpper(), value.variant().toByteArray()); 0064 arg.endMapEntry(); 0065 } 0066 arg.endMap(); 0067 return result; 0068 } 0069 0070 void DevicePrivate::init(const QVariantMap &properties) 0071 { 0072 m_dbusProperties = new DBusProperties(Strings::orgBluez(), m_bluezDevice->path(), DBusConnection::orgBluez(), this); 0073 0074 // Init properties 0075 m_address = properties.value(QStringLiteral("Address")).toString(); 0076 m_name = properties.value(QStringLiteral("Name")).toString(); 0077 m_alias = properties.value(QStringLiteral("Alias")).toString(); 0078 m_deviceClass = properties.value(QStringLiteral("Class")).toUInt(); 0079 m_appearance = properties.value(QStringLiteral("Appearance")).toUInt(); 0080 m_icon = properties.value(QStringLiteral("Icon")).toString(); 0081 m_paired = properties.value(QStringLiteral("Paired")).toBool(); 0082 m_trusted = properties.value(QStringLiteral("Trusted")).toBool(); 0083 m_blocked = properties.value(QStringLiteral("Blocked")).toBool(); 0084 m_legacyPairing = properties.value(QStringLiteral("LegacyPairing")).toBool(); 0085 m_rssi = properties.value(QStringLiteral("RSSI")).toInt(); 0086 m_manufacturerData = variantToManData(properties.value(QStringLiteral("ManufacturerData"))); 0087 m_servicesResolved = properties.value(QStringLiteral("ServicesResolved")).toBool(); 0088 m_connected = properties.value(QStringLiteral("Connected")).toBool(); 0089 m_uuids = stringListToUpper(properties.value(QStringLiteral("UUIDs")).toStringList()); 0090 m_modalias = properties.value(QStringLiteral("Modalias")).toString(); 0091 m_serviceData = toByteArrayHash(properties.value(QStringLiteral("ServiceData")).value<QDBusArgument>()); 0092 0093 if (!m_rssi) { 0094 m_rssi = INVALID_RSSI; 0095 } 0096 } 0097 0098 void DevicePrivate::interfacesAdded(const QString &path, const QVariantMapMap &interfaces) 0099 { 0100 bool changed = false; 0101 QVariantMapMap::const_iterator it; 0102 0103 for (it = interfaces.constBegin(); it != interfaces.constEnd(); ++it) { 0104 if (it.key() == Strings::orgBluezBattery1()) { 0105 m_battery = BatteryPtr(new Battery(path, it.value())); 0106 m_battery->d->q = m_battery.toWeakRef(); 0107 Q_EMIT q.lock()->batteryChanged(m_battery); 0108 changed = true; 0109 } else if (it.key() == Strings::orgBluezInput1()) { 0110 m_input = InputPtr(new Input(path, it.value())); 0111 m_input->d->q = m_input.toWeakRef(); 0112 Q_EMIT q.lock()->inputChanged(m_input); 0113 changed = true; 0114 } else if (it.key() == Strings::orgBluezMediaPlayer1()) { 0115 m_mediaPlayer = MediaPlayerPtr(new MediaPlayer(path, it.value())); 0116 m_mediaPlayer->d->q = m_mediaPlayer.toWeakRef(); 0117 Q_EMIT q.lock()->mediaPlayerChanged(m_mediaPlayer); 0118 changed = true; 0119 } else if (it.key() == Strings::orgBluezMediaTransport1()) { 0120 m_mediaTransport = MediaTransportPtr(new MediaTransport(path, it.value())); 0121 m_mediaTransport->d->q = m_mediaTransport.toWeakRef(); 0122 Q_EMIT q.lock()->mediaTransportChanged(m_mediaTransport); 0123 changed = true; 0124 } else if (it.key() == Strings::orgBluezGattService1()) { 0125 addGattService(path,it.value()); 0126 changed = true; 0127 } 0128 } 0129 0130 for (auto& service : m_services) { 0131 if (path.startsWith(service->ubi())) { 0132 service->d->interfacesAdded(path, interfaces); 0133 changed = true; 0134 } 0135 } 0136 0137 if (changed) { 0138 Q_EMIT q.lock()->deviceChanged(q.toStrongRef()); 0139 } 0140 } 0141 0142 void DevicePrivate::interfacesRemoved(const QString &path, const QStringList &interfaces) 0143 { 0144 bool changed = false; 0145 0146 for (const QString &interface : interfaces) { 0147 if (interface == Strings::orgBluezBattery1() && m_battery && m_battery->d->m_path == path) { 0148 m_battery.clear(); 0149 Q_EMIT q.lock()->batteryChanged(m_battery); 0150 changed = true; 0151 } else if (interface == Strings::orgBluezInput1() && m_input && m_input->d->m_path == path) { 0152 m_input.clear(); 0153 Q_EMIT q.lock()->inputChanged(m_input); 0154 changed = true; 0155 } else if (interface == Strings::orgBluezMediaPlayer1() && m_mediaPlayer && m_mediaPlayer->d->m_path == path) { 0156 m_mediaPlayer.clear(); 0157 Q_EMIT q.lock()->mediaPlayerChanged(m_mediaPlayer); 0158 changed = true; 0159 } else if (interface == Strings::orgBluezMediaTransport1() && m_mediaTransport && m_mediaTransport->d->m_path == path) { 0160 m_mediaTransport.clear(); 0161 Q_EMIT q.lock()->mediaTransportChanged(m_mediaTransport); 0162 changed = true; 0163 } else if (interface == Strings::orgBluezGattService1()) { 0164 removeGattService(path); 0165 changed = true; 0166 } 0167 } 0168 0169 for (auto& service : m_services) { 0170 if (path.startsWith(service->ubi())) { 0171 service->d->interfacesRemoved(path,interfaces); 0172 changed = true; 0173 } 0174 } 0175 0176 if (changed) { 0177 Q_EMIT q.lock()->deviceChanged(q.toStrongRef()); 0178 } 0179 } 0180 0181 void DevicePrivate::addGattService(const QString &gattServicePath, const QVariantMap &properties) 0182 { 0183 // Check if we have the right path 0184 if (m_bluezDevice->path() != properties.value(QStringLiteral("Device")).value<QDBusObjectPath>().path()) { 0185 return; 0186 } 0187 0188 DevicePtr device = DevicePtr(this->q); 0189 0190 if (!device) { 0191 return; 0192 } 0193 0194 GattServiceRemotePtr gattService = GattServiceRemotePtr(new GattServiceRemote(gattServicePath, properties, device)); 0195 gattService->d->q = gattService.toWeakRef(); 0196 m_services.append(gattService); 0197 0198 Q_EMIT device->gattServiceAdded(gattService); 0199 Q_EMIT device->gattServicesChanged(m_services); 0200 0201 // Connections 0202 connect(gattService.data(),&GattServiceRemote::serviceChanged,q.lock().data(),&Device::gattServiceChanged); 0203 } 0204 0205 void DevicePrivate::removeGattService(const QString &gattServicePath) 0206 { 0207 DevicePtr device = DevicePtr(this->q); 0208 0209 if (!device) { 0210 return; 0211 } 0212 0213 GattServiceRemotePtr gattService = nullptr; 0214 for (int i=0; i < device->gattServices().size(); ++i) { 0215 if (device->gattServices().at(i)->ubi() == gattServicePath) { 0216 gattService = device->gattServices().at(i); 0217 } 0218 } 0219 0220 if (gattService == nullptr) { 0221 return; 0222 } 0223 0224 m_services.removeOne(gattService); 0225 0226 Q_EMIT device->gattServiceRemoved(gattService); 0227 Q_EMIT device->gattServicesChanged(m_services); 0228 0229 // Connections 0230 disconnect(gattService.data(),&GattServiceRemote::serviceChanged,q.lock().data(),&Device::gattServiceChanged); 0231 } 0232 0233 QDBusPendingReply<> DevicePrivate::setDBusProperty(const QString &name, const QVariant &value) 0234 { 0235 return m_dbusProperties->Set(Strings::orgBluezDevice1(), name, QDBusVariant(value)); 0236 } 0237 0238 void DevicePrivate::propertiesChanged(const QString &path, const QString &interface, const QVariantMap &changed, const QStringList &invalidated) 0239 { 0240 if (interface == Strings::orgBluezBattery1() && m_battery) { 0241 m_battery->d->propertiesChanged(interface, changed, invalidated); 0242 } else if (interface == Strings::orgBluezInput1() && m_input) { 0243 m_input->d->propertiesChanged(interface, changed, invalidated); 0244 } else if (interface == Strings::orgBluezMediaPlayer1() && m_mediaPlayer) { 0245 m_mediaPlayer->d->propertiesChanged(interface, changed, invalidated); 0246 } else if ((interface == Strings::orgBluezGattService1()) || (interface == Strings::orgBluezGattCharacteristic1()) || (interface == Strings::orgBluezGattDescriptor1())) { 0247 for (GattServiceRemotePtr service : m_services) { 0248 if (path.startsWith(service->ubi())) { 0249 service->d->propertiesChanged(path, interface, changed, invalidated); 0250 return; 0251 } 0252 } 0253 } else if (interface != Strings::orgBluezDevice1()) { 0254 return; 0255 } 0256 0257 QVariantMap::const_iterator i; 0258 for (i = changed.constBegin(); i != changed.constEnd(); ++i) { 0259 const QVariant &value = i.value(); 0260 const QString &property = i.key(); 0261 0262 if (property == QLatin1String("Name")) { 0263 namePropertyChanged(value.toString()); 0264 } else if (property == QLatin1String("Address")) { 0265 addressPropertyChanged(value.toString()); 0266 } else if (property == QLatin1String("Alias")) { 0267 aliasPropertyChanged(value.toString()); 0268 } else if (property == QLatin1String("Class")) { 0269 classPropertyChanged(value.toUInt()); 0270 } else if (property == QLatin1String("Appearance")) { 0271 PROPERTY_CHANGED(m_appearance, toUInt, appearanceChanged); 0272 } else if (property == QLatin1String("Icon")) { 0273 PROPERTY_CHANGED(m_icon, toString, iconChanged); 0274 } else if (property == QLatin1String("Paired")) { 0275 PROPERTY_CHANGED(m_paired, toBool, pairedChanged); 0276 } else if (property == QLatin1String("Trusted")) { 0277 PROPERTY_CHANGED(m_trusted, toBool, trustedChanged); 0278 } else if (property == QLatin1String("Blocked")) { 0279 PROPERTY_CHANGED(m_blocked, toBool, blockedChanged); 0280 } else if (property == QLatin1String("LegacyPairing")) { 0281 PROPERTY_CHANGED(m_legacyPairing, toBool, legacyPairingChanged); 0282 } else if (property == QLatin1String("RSSI")) { 0283 PROPERTY_CHANGED(m_rssi, toInt, rssiChanged); 0284 } else if (property == QLatin1String("ManufacturerData")) { 0285 PROPERTY_CHANGED2(m_manufacturerData, variantToManData(value), manufacturerDataChanged); 0286 } else if (property == QLatin1String("ServicesResolved")) { 0287 PROPERTY_CHANGED(m_servicesResolved, toBool, servicesResolvedChanged); 0288 } else if (property == QLatin1String("Connected")) { 0289 PROPERTY_CHANGED(m_connected, toBool, connectedChanged); 0290 } else if (property == QLatin1String("Modalias")) { 0291 PROPERTY_CHANGED(m_modalias, toString, modaliasChanged); 0292 } else if (property == QLatin1String("UUIDs")) { 0293 PROPERTY_CHANGED2(m_uuids, stringListToUpper(value.toStringList()), uuidsChanged); 0294 } else if (property == QLatin1String("ServiceData")) { 0295 PROPERTY_CHANGED2(m_serviceData, toByteArrayHash(value.value<QDBusArgument>()), serviceDataChanged); 0296 } 0297 } 0298 0299 for (const QString &property : invalidated) { 0300 if (property == QLatin1String("Name")) { 0301 namePropertyChanged(QString()); 0302 } else if (property == QLatin1String("Class")) { 0303 classPropertyChanged(0); 0304 } else if (property == QLatin1String("Appearance")) { 0305 PROPERTY_INVALIDATED(m_appearance, 0, appearanceChanged); 0306 } else if (property == QLatin1String("Icon")) { 0307 PROPERTY_INVALIDATED(m_icon, QString(), iconChanged); 0308 } else if (property == QLatin1String("RSSI")) { 0309 PROPERTY_INVALIDATED(m_rssi, INVALID_RSSI, rssiChanged); 0310 } else if (property == QLatin1String("ManufacturerData")) { 0311 QMap<uint16_t,QByteArray> map; 0312 PROPERTY_INVALIDATED(m_manufacturerData, map, manufacturerDataChanged); 0313 } else if (property == QLatin1String("ServicesResolved")) { 0314 PROPERTY_INVALIDATED(m_servicesResolved, false, servicesResolvedChanged); 0315 } else if (property == QLatin1String("Modalias")) { 0316 PROPERTY_INVALIDATED(m_modalias, QString(), modaliasChanged); 0317 } else if (property == QLatin1String("UUIDs")) { 0318 PROPERTY_INVALIDATED(m_uuids, QStringList(), uuidsChanged); 0319 } else if (property == QLatin1String("ServiceData")) { 0320 PROPERTY_INVALIDATED(m_serviceData, (QHash<QString, QByteArray>()), serviceDataChanged); 0321 } 0322 } 0323 0324 Q_EMIT q.lock()->deviceChanged(q.toStrongRef()); 0325 } 0326 0327 void DevicePrivate::namePropertyChanged(const QString &value) 0328 { 0329 if (m_name != value) { 0330 m_name = value; 0331 Q_EMIT q.lock()->remoteNameChanged(m_name); 0332 Q_EMIT q.lock()->friendlyNameChanged(q.lock()->friendlyName()); 0333 } 0334 } 0335 0336 void DevicePrivate::addressPropertyChanged(const QString &value) 0337 { 0338 if (m_address != value) { 0339 m_address = value; 0340 Q_EMIT q.lock()->addressChanged(m_address); 0341 } 0342 } 0343 0344 void DevicePrivate::aliasPropertyChanged(const QString &value) 0345 { 0346 if (m_alias != value) { 0347 m_alias = value; 0348 Q_EMIT q.lock()->nameChanged(m_alias); 0349 Q_EMIT q.lock()->friendlyNameChanged(q.lock()->friendlyName()); 0350 } 0351 } 0352 0353 void DevicePrivate::classPropertyChanged(quint32 value) 0354 { 0355 if (m_deviceClass != value) { 0356 m_deviceClass = value; 0357 Q_EMIT q.lock()->deviceClassChanged(m_deviceClass); 0358 Q_EMIT q.lock()->typeChanged(q.lock()->type()); 0359 } 0360 } 0361 0362 void DevicePrivate::serviceDataChanged(const QHash<QString, QByteArray> &value) 0363 { 0364 if (m_serviceData != value) { 0365 m_serviceData = value; 0366 Q_EMIT q.lock()->serviceDataChanged(m_serviceData); 0367 } 0368 } 0369 0370 } // namespace BluezQt 0371 0372 #include "moc_device_p.cpp"