77#include " trayiconmanager.h"
88#include " enums.h"
99#include " battery.hpp"
10+ #include " BluetoothMonitor.h"
1011
1112using namespace AirpodsTrayApp ::Enums;
1213
@@ -31,7 +32,8 @@ class AirPodsTrayApp : public QObject {
3132public:
3233 AirPodsTrayApp (bool debugMode)
3334 : debugMode (debugMode)
34- , m_battery (new Battery (this )) {
35+ , m_battery (new Battery (this ))
36+ , monitor (new BluetoothMonitor (this )) {
3537 if (debugMode) {
3638 QLoggingCategory::setFilterRules (" airpodsApp.debug=true" );
3739 } else {
@@ -55,6 +57,9 @@ class AirPodsTrayApp : public QObject {
5557 mediaController->initializeMprisInterface ();
5658 mediaController->followMediaChanges ();
5759
60+ connect (monitor, &BluetoothMonitor::deviceConnected, this , &AirPodsTrayApp::bluezDeviceConnected);
61+ connect (monitor, &BluetoothMonitor::deviceDisconnected, this , &AirPodsTrayApp::bluezDeviceDisconnected);
62+
5863 connect (m_battery, &Battery::primaryChanged, this , &AirPodsTrayApp::primaryChanged);
5964
6065 CrossDevice.isEnabled = loadCrossDeviceEnabled ();
@@ -78,15 +83,6 @@ class AirPodsTrayApp : public QObject {
7883 }
7984 }
8085
81- QDBusInterface iface (" org.bluez" , " /org/bluez" , " org.bluez.Adapter1" );
82- QDBusReply<QVariant> reply = iface.call (" GetServiceRecords" , QString::fromUtf8 (" 74ec2172-0bad-4d01-8f77-997b2be0722a" ));
83- if (reply.isValid ()) {
84- LOG_INFO (" Service record found, proceeding with connection" );
85- } else {
86- LOG_WARN (" Service record not found, waiting for BLE broadcast" );
87- }
88-
89- listenForDeviceConnections ();
9086 initializeDBus ();
9187 initializeBluetooth ();
9288 }
@@ -97,8 +93,6 @@ class AirPodsTrayApp : public QObject {
9793 delete trayIcon;
9894 delete trayMenu;
9995 delete discoveryAgent;
100- delete bluezInterface;
101- delete mprisInterface;
10296 delete socket;
10397 delete phoneSocket;
10498 }
@@ -137,46 +131,7 @@ class AirPodsTrayApp : public QObject {
137131 bool isEnabled = true ; // Ability to disable the feature
138132 } CrossDevice;
139133
140- void initializeDBus () {
141- QDBusConnection systemBus = QDBusConnection::systemBus ();
142- if (!systemBus.isConnected ()) {
143- }
144-
145- bluezInterface = new QDBusInterface (" org.bluez" ,
146- " /" ,
147- " org.freedesktop.DBus.ObjectManager" ,
148- systemBus,
149- this );
150-
151- if (!bluezInterface->isValid ()) {
152- LOG_ERROR (" Failed to connect to org.bluez DBus interface." );
153- return ;
154- }
155-
156- connect (systemBus.interface (), &QDBusConnectionInterface::NameOwnerChanged,
157- this , &AirPodsTrayApp::onNameOwnerChanged);
158-
159- systemBus.connect (QString (), QString (), " org.freedesktop.DBus.Properties" , " PropertiesChanged" ,
160- this , SLOT (onDevicePropertiesChanged (QString, QVariantMap, QStringList)));
161-
162- systemBus.connect (QString (), QString (), " org.freedesktop.DBus.ObjectManager" , " InterfacesAdded" ,
163- this , SLOT (onInterfacesAdded (QString, QVariantMap)));
164-
165- QDBusMessage msg = bluezInterface->call (" GetManagedObjects" );
166- if (msg.type () == QDBusMessage::ErrorMessage) {
167- LOG_ERROR (" Error getting managed objects: " << msg.errorMessage ());
168- return ;
169- }
170-
171- QVariantMap objects = qdbus_cast<QVariantMap>(msg.arguments ().at (0 ));
172- for (auto it = objects.begin (); it != objects.end (); ++it) {
173- if (it.key ().startsWith (" /org/bluez/hci0/dev_" )) {
174- LOG_INFO (" Existing device: " << it.key ());
175- }
176- }
177- QDBusConnection::systemBus ().registerObject (" /me/kavishdevar/aln" , this );
178- QDBusConnection::systemBus ().registerService (" me.kavishdevar.aln" );
179- }
134+ void initializeDBus () { }
180135
181136 bool isAirPodsDevice (const QBluetoothDeviceInfo &device)
182137 {
@@ -195,43 +150,11 @@ class AirPodsTrayApp : public QObject {
195150 LOG_WARN (" Phone socket is not open, cannot send notification packet" );
196151 }
197152 }
198- void onNameOwnerChanged (const QString &name, const QString &oldOwner, const QString &newOwner) {
199- if (name == " org.bluez" ) {
200- if (newOwner.isEmpty ()) {
201- LOG_WARN (" BlueZ has been stopped." );
202- } else {
203- LOG_INFO (" BlueZ started." );
204- }
205- }
206- }
207-
208- void onDevicePropertiesChanged (const QString &interface, const QVariantMap &changed, const QStringList &invalidated) {
209- if (interface != " org.bluez.Device1" )
210- return ;
211-
212- if (changed.contains (" Connected" )) {
213- bool connected = changed.value (" Connected" ).toBool ();
214- QString devicePath = sender ()->objectName ();
215- LOG_INFO (QString (" Device %1 connected: %2" ).arg (devicePath, connected ? " Yes" : " No" ));
216-
217- if (connected) {
218- const QBluetoothAddress address = QBluetoothAddress (devicePath.split (" /" ).last ().replace (" _" , " :" ));
219- QBluetoothDeviceInfo device (address, " " , 0 );
220- if (isAirPodsDevice (device)) {
221- connectToDevice (device);
222- }
223- } else {
224- disconnectDevice (devicePath);
225- }
226- }
227- }
228153
229154 void disconnectDevice (const QString &devicePath) {
230155 LOG_INFO (" Disconnecting device at " << devicePath);
231156 }
232157
233- QDBusInterface *bluezInterface = nullptr ;
234-
235158public slots:
236159 void connectToDevice (const QString &address) {
237160 LOG_INFO (" Connecting to device with address: " << address);
@@ -422,6 +345,11 @@ private slots:
422345 connectToDevice (device);
423346 }
424347 }
348+ void bluezDeviceConnected (const QString &address)
349+ {
350+ QBluetoothDeviceInfo device (QBluetoothAddress (address), " " , 0 );
351+ connectToDevice (device);
352+ }
425353
426354 void onDeviceDisconnected (const QBluetoothAddress &address)
427355 {
@@ -431,13 +359,23 @@ private slots:
431359 LOG_WARN (" Socket is still open, closing it" );
432360 socket->close ();
433361 socket = nullptr ;
362+ discoveryAgent->start ();
434363 }
435364 if (phoneSocket && phoneSocket->isOpen ())
436365 {
437366 phoneSocket->write (AirPodsPackets::Connection::AIRPODS_DISCONNECTED);
438367 LOG_DEBUG (" AIRPODS_DISCONNECTED packet written: " << AirPodsPackets::Connection::AIRPODS_DISCONNECTED.toHex ());
439368 }
440369 }
370+ void bluezDeviceDisconnected (const QString &address)
371+ {
372+ if (address == connectedDeviceMacAddress.replace (" _" , " :" )) {
373+ onDeviceDisconnected (QBluetoothAddress (address));
374+ }
375+ else {
376+ LOG_WARN (" Disconnected device does not match connected device: " << address << " != " << connectedDeviceMacAddress);
377+ }
378+ }
441379
442380 void parseMetadata (const QByteArray &data)
443381 {
@@ -524,9 +462,6 @@ private slots:
524462
525463 LOG_INFO (" Connecting to device: " << device.name ());
526464 QBluetoothSocket *localSocket = new QBluetoothSocket (QBluetoothServiceInfo::L2capProtocol);
527- connect (localSocket, &QBluetoothSocket::disconnected, this , [this , localSocket]() {
528- onDeviceDisconnected (localSocket->peerAddress ());
529- });
530465 connect (localSocket, &QBluetoothSocket::connected, this , [this , localSocket]() {
531466 // Start periodic magic pairing attempts
532467 QTimer *magicPairingTimer = new QTimer (this );
@@ -778,26 +713,6 @@ private slots:
778713 QMetaObject::invokeMethod (this , " handlePhonePacket" , Qt::QueuedConnection, Q_ARG (QByteArray, data));
779714 }
780715
781- void listenForDeviceConnections () {
782- QDBusConnection systemBus = QDBusConnection::systemBus ();
783- systemBus.connect (QString (), QString (), " org.freedesktop.DBus.Properties" , " PropertiesChanged" , this , SLOT (onDevicePropertiesChanged (QString, QVariantMap, QStringList)));
784- systemBus.connect (QString (), QString (), " org.freedesktop.DBus.ObjectManager" , " InterfacesAdded" , this , SLOT (onInterfacesAdded (QString, QVariantMap)));
785- }
786-
787- void onInterfacesAdded (QString path, QVariantMap interfaces) {
788- if (interfaces.contains (" org.bluez.Device1" )) {
789- QVariantMap deviceProps = interfaces[" org.bluez.Device1" ].toMap ();
790- if (deviceProps.contains (" Connected" ) && deviceProps[" Connected" ].toBool ()) {
791- QString addr = deviceProps[" Address" ].toString ();
792- QBluetoothAddress btAddress (addr);
793- QBluetoothDeviceInfo device (btAddress, " " , 0 );
794- if (isAirPodsDevice (device)) {
795- connectToDevice (device);
796- }
797- }
798- }
799- }
800-
801716 public:
802717 void handleMediaStateChange (MediaController::MediaState state) {
803718 if (state == MediaController::MediaState::Playing) {
@@ -903,12 +818,12 @@ private slots:
903818 QBluetoothDeviceDiscoveryAgent *discoveryAgent;
904819 QBluetoothSocket *socket = nullptr ;
905820 QBluetoothSocket *phoneSocket = nullptr ;
906- QDBusInterface *mprisInterface;
907821 QString connectedDeviceMacAddress;
908822 QByteArray lastBatteryStatus;
909823 QByteArray lastEarDetectionStatus;
910824 MediaController* mediaController;
911825 TrayIconManager *trayManager;
826+ BluetoothMonitor *monitor;
912827 QSettings *settings;
913828
914829 QString m_batteryStatus;
0 commit comments