1 /****************************************************************************************
2  * Copyright (c) 2008 Alejandro Wainzinger <aikawarazuni@gmail.com>                     *
3  * Copyright (c) 2009 Nikolaj Hald Nielsen <nhn@kde.org>                                *
4  *                                                                                      *
5  * This program is free software; you can redistribute it and/or modify it under        *
6  * the terms of the GNU General Public License as published by the Free Software        *
7  * Foundation; either version 2 of the License, or (at your option) any later           *
8  * version.                                                                             *
9  *                                                                                      *
10  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
11  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
12  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
13  *                                                                                      *
14  * You should have received a copy of the GNU General Public License along with         *
15  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
16  ****************************************************************************************/
17 
18 #define DEBUG_PREFIX "MediaDeviceMonitor"
19 
20 #include "MediaDeviceMonitor.h"
21 
22 #include "MediaDeviceCache.h"
23 #include "core-impl/collections/mediadevicecollection/support/ConnectionAssistant.h"
24 #include "core/support/Debug.h"
25 
26 #include <Solid/DeviceNotifier>
27 #include <Solid/Device>
28 #include <Solid/OpticalDisc>
29 #include <Solid/StorageAccess>
30 #include <Solid/StorageDrive>
31 #include <Solid/PortableMediaPlayer>
32 #include <Solid/OpticalDrive>
33 
34 #include <QTimer>
35 
36 MediaDeviceMonitor* MediaDeviceMonitor::s_instance = nullptr;
37 
MediaDeviceMonitor()38 MediaDeviceMonitor::MediaDeviceMonitor() : QObject()
39  , m_udiAssistants()
40  , m_assistants()
41  , m_waitingassistants()
42  , m_nextassistant( 0 )
43  // NOTE: commented out, needs porting to new device framework
44  //, m_currentCdId( QString() )
45 {
46     DEBUG_BLOCK
47     s_instance = this;
48     init();
49 }
50 
~MediaDeviceMonitor()51 MediaDeviceMonitor::~MediaDeviceMonitor()
52 {
53     s_instance = nullptr;
54 }
55 
56 void
init()57 MediaDeviceMonitor::init()
58 {
59     DEBUG_BLOCK
60 
61     // connect to device cache so new devices are tested too
62     connect(  MediaDeviceCache::instance(),  &MediaDeviceCache::deviceAdded,
63               this, &MediaDeviceMonitor::deviceAdded );
64     connect(  MediaDeviceCache::instance(),  &MediaDeviceCache::deviceRemoved,
65               this, &MediaDeviceMonitor::slotDeviceRemoved );
66     connect(  MediaDeviceCache::instance(), &MediaDeviceCache::accessibilityChanged,
67               this, &MediaDeviceMonitor::slotAccessibilityChanged );
68 }
69 
70 QStringList
getDevices()71 MediaDeviceMonitor::getDevices()
72 {
73     DEBUG_BLOCK
74     /* get list of devices */
75     MediaDeviceCache::instance()->refreshCache();
76     return MediaDeviceCache::instance()->getAll();
77 
78 }
79 
checkDevice(const QString & udi)80 void MediaDeviceMonitor::checkDevice(const QString& udi)
81 {
82     DEBUG_BLOCK
83 
84     // First let the higher priority devices check
85 
86     foreach( ConnectionAssistant* assistant, m_assistants )
87     {
88         checkOneDevice( assistant, udi );
89     }
90 
91     // Then let the assistants that can wait check
92 
93     foreach( ConnectionAssistant* assistant, m_waitingassistants )
94     {
95         checkOneDevice( assistant, udi );
96     }
97 
98 }
99 
checkOneDevice(ConnectionAssistant * assistant,const QString & udi)100 void MediaDeviceMonitor::checkOneDevice( ConnectionAssistant* assistant, const QString& udi )
101 {
102     // Ignore already identified devices
103     if( m_udiAssistants.keys().contains( udi ) )
104     {
105         debug() << "Device already identified with udi: " << udi;
106         return;
107     }
108 
109     if( assistant->identify( udi ) )
110     {
111         debug() << "Device identified with udi: " << udi;
112         // keep track of which assistant deals with which device
113         m_udiAssistants.insert( udi, assistant );
114         // inform factory of new device identified
115         assistant->tellIdentified( udi );
116         return;
117     }
118 }
119 
checkDevicesFor(ConnectionAssistant * assistant)120 void MediaDeviceMonitor::checkDevicesFor( ConnectionAssistant* assistant )
121 {
122     DEBUG_BLOCK
123 
124     QStringList udiList = getDevices();
125 
126     foreach( const QString &udi, udiList )
127     {
128         checkOneDevice( assistant, udi );
129     }
130 
131 }
132 
133 void
registerDeviceType(ConnectionAssistant * assistant)134 MediaDeviceMonitor::registerDeviceType( ConnectionAssistant* assistant )
135 {
136     DEBUG_BLOCK
137 
138     // If the device wants to wait and give other device types
139     // a chance to recognize devices, put it in a queue for
140     // later device checking
141 
142     if ( assistant->wait() )
143     {
144         // keep track of this type of device from now on
145         m_waitingassistants << assistant;
146 
147         QTimer::singleShot( 1000, this, &MediaDeviceMonitor::slotDequeueWaitingAssistant );
148     }
149     else
150     {
151         // keep track of this type of device from now on
152         m_assistants << assistant;
153 
154         // start initial check for devices of this type
155         checkDevicesFor( assistant );
156     }
157 
158 }
159 
160 void
deviceAdded(const QString & udi)161 MediaDeviceMonitor::deviceAdded( const QString &udi )
162 {
163     DEBUG_BLOCK
164 
165     // check if device is a known device
166     checkDevice( udi );
167 }
168 
169 void
slotDeviceRemoved(const QString & udi)170 MediaDeviceMonitor::slotDeviceRemoved( const QString &udi )
171 {
172     DEBUG_BLOCK
173 
174     if ( m_udiAssistants.contains( udi ) )
175     {
176 
177         m_udiAssistants.value( udi )->tellDisconnected( udi );
178 
179         m_udiAssistants.remove( udi );
180     }
181 
182 
183 //    Q_EMIT deviceRemoved( udi );
184 }
185 
186 void
slotAccessibilityChanged(bool accessible,const QString & udi)187 MediaDeviceMonitor::slotAccessibilityChanged( bool accessible, const QString & udi)
188 {
189     // TODO: build a hack to force a device to become accessible or not
190     // This means auto-mounting of Ipod, and ejecting of it too
191 
192     DEBUG_BLOCK
193             debug() << "Accessibility changed to: " << ( accessible ? "true":"false" );
194     if ( !accessible )
195         deviceRemoved( udi );
196     else
197         deviceAdded( udi );
198 }
199 
200 void
slotDequeueWaitingAssistant()201 MediaDeviceMonitor::slotDequeueWaitingAssistant()
202 {
203     checkDevicesFor( m_waitingassistants.at( m_nextassistant++ ) );
204 }
205