1
/*
2
   Copyright (C) 2008 Alejandro Wainzinger <aikawarazuni@gmail.com>
3
   Copyright (C) 2009 Nikolaj Hald Nielsen <nhnFreespirit@gmail.com>
4
5
   This program is free software; you can redistribute it and/or
6
   modify it under the terms of the GNU General Public License
7
   as published by the Free Software Foundation; either version 2
8
   of the License, or (at your option) any later version.
9
10
   This program is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
   GNU General Public License for more details.
14
15
   You should have received a copy of the GNU General Public License
16
   along with this program; if not, write to the Free Software
17
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18
*/
19
20
#define DEBUG_PREFIX "MediaDeviceMonitor"
21
22
#include "MediaDeviceMonitor.h"
23
24
#include "Debug.h"
25
26
#include "MediaDeviceCache.h"
27
28
//solid specific includes
29
#include <solid/devicenotifier.h>
30
31
#include <solid/device.h>
32
#include <solid/opticaldisc.h>
33
#include <solid/storageaccess.h>
34
#include <solid/storagedrive.h>
35
#include <solid/portablemediaplayer.h>
36
#include <solid/opticaldrive.h>
37
38
MediaDeviceMonitor* MediaDeviceMonitor::s_instance = 0;
39
40
MediaDeviceMonitor::MediaDeviceMonitor()
41
    : QObject()
42
    , m_currentCdId( QString() )
43
{
44
    DEBUG_BLOCK
45
    s_instance = this;
46
    init();
47
}
48
49
MediaDeviceMonitor::~MediaDeviceMonitor()
50
{
51
    s_instance = 0;
52
}
53
54
void
55
MediaDeviceMonitor::init()
56
{
57
    DEBUG_BLOCK
58
59
    // connect to device cache so new devices are tested too
60
    connect(  MediaDeviceCache::instance(),  SIGNAL(  deviceAdded( const QString& ) ),
61
              SLOT(  deviceAdded( const QString& ) ) );
62
    connect(  MediaDeviceCache::instance(),  SIGNAL(  deviceRemoved( const QString& ) ),
63
              SLOT(  slotDeviceRemoved( const QString& ) ) );
64
    connect(  MediaDeviceCache::instance(), SIGNAL( accessibilityChanged( bool, const QString & ) ),
65
              SLOT(  slotAccessibilityChanged( bool, const QString & ) ) );
66
}
67
68
QStringList
69
MediaDeviceMonitor::getDevices()
70
{
71
    DEBUG_BLOCK
72
    /* get list of devices */
73
    MediaDeviceCache::instance()->refreshCache();
74
    return MediaDeviceCache::instance()->getAll();
75
76
}
77
78
void
79
MediaDeviceMonitor::checkDevices()
80
{
81
    DEBUG_BLOCK
82
    /* poll udi list for supported devices */
83
84
    checkDevicesForMtp();
85
    checkDevicesForIpod();
86
    checkDevicesForCd();
87
}
88
89
void
90
MediaDeviceMonitor::checkDevicesForIpod()
91
{
92
    QStringList udiList = getDevices();
93
94
    /* poll udi list for supported devices */
95
    foreach(const QString &udi, udiList )
96
    {
97
        /* if ipod device found, emit signal */
98
        if( isIpod( udi ) )
99
        {
100
            // HACK: Usability: Force auto-connection of device upon detection
101
            connectIpod( MediaDeviceCache::instance()->volumeMountPoint(udi), udi );
102
            emit ipodDetected( MediaDeviceCache::instance()->volumeMountPoint(udi), udi );
103
        }
104
    }
105
}
106
107
void
108
MediaDeviceMonitor::checkDevicesForMtp()
109
{
110
    QStringList udiList = getDevices();
111
112
    /* poll udi list for supported devices */
113
    foreach(const QString &udi, udiList )
114
    {
115
        if( isMtp( udi ) )
116
        {
117
            Solid::PortableMediaPlayer* pmp = Solid::Device( udi ).as<Solid::PortableMediaPlayer>();
118
            QString serial = pmp->driverHandle( "mtp" ).toString();
119
            debug() << "Serial is: " << serial;
120
            // HACK: Usability: Force auto-connection of device upon detection
121
            connectMtp( serial, udi );
122
            emit mtpDetected( serial, udi );
123
        }
124
    }
125
}
126
127
void
128
MediaDeviceMonitor::checkDevicesForCd()
129
{
130
    DEBUG_BLOCK
131
132
    QStringList udiList = getDevices();
133
134
    /* poll udi list for supported devices */
135
    foreach(const QString &udi, udiList )
136
    {
137
        debug() << "udi: " << udi;
138
        if ( isAudioCd( udi ) )
139
        {
140
            emit audioCdDetected( udi );
141
        }
142
    }
143
}
144
145
146
147
void
148
MediaDeviceMonitor::deviceAdded(  const QString &udi )
149
{
150
    DEBUG_BLOCK
151
152
    QStringList udiList;
153
154
    debug() << "New device added, testing...";
155
156
    udiList.append( udi );
157
    checkDevices();
158
}
159
160
void
161
MediaDeviceMonitor::slotDeviceRemoved( const QString &udi )
162
{
163
    DEBUG_BLOCK
164
165
    // NOTE: perhaps a simple forwarding of signals would do
166
    // via a connect
167
168
    emit deviceRemoved( udi );
169
}
170
171
void
172
MediaDeviceMonitor::slotAccessibilityChanged( bool accessible, const QString & udi)
173
{
174
    DEBUG_BLOCK
175
            debug() << "Accessibility changed to: " << ( accessible ? "true":"false" );
176
    if ( !accessible )
177
        deviceRemoved( udi );
178
    else
179
        deviceAdded( udi );
180
}
181
182
bool
183
MediaDeviceMonitor::isIpod( const QString &udi )
184
{
185
    DEBUG_BLOCK
186
187
    Solid::Device device;
188
189
    device = Solid::Device(udi);
190
    /* going until we reach a vendor, e.g. Apple */
191
    while ( device.isValid() && device.vendor().isEmpty() )
192
    {
193
        device = Solid::Device( device.parentUdi() );
194
    }
195
196
    debug() << "Device udi: " << udi;
197
    debug() << "Device name: " << MediaDeviceCache::instance()->deviceName(udi);
198
    debug() << "Mount point: " << MediaDeviceCache::instance()->volumeMountPoint(udi);
199
    if ( device.isValid() )
200
    {
201
        debug() << "vendor: " << device.vendor() << ", product: " << device.product();
202
    }
203
204
    /* if iPod or iPhone found, return true */
205
    return device.product() == "iPod" || device.product() == "iPhone";
206
}
207
208
bool
209
MediaDeviceMonitor::isMtp( const QString &udi )
210
{
211
    DEBUG_BLOCK
212
213
    Solid::Device device;
214
215
    device = Solid::Device( udi );
216
    if( !device.is<Solid::PortableMediaPlayer>() )
217
    {
218
        debug() << "Not a PMP";
219
        return false;
220
    }
221
222
    Solid::PortableMediaPlayer *pmp = device.as<Solid::PortableMediaPlayer>();
223
224
    debug() << "Supported Protocols: " << pmp->supportedProtocols();
225
226
    return pmp->supportedProtocols().contains( "mtp" );
227
}
228
229
bool
230
MediaDeviceMonitor::isAudioCd( const QString & udi )
231
{
232
    DEBUG_BLOCK
233
234
    Solid::Device device;
235
236
    device = Solid::Device( udi );
237
    if( device.is<Solid::OpticalDisc>() )
238
    {
239
        debug() << "OpticalDisc";
240
        Solid::OpticalDisc * opt = device.as<Solid::OpticalDisc>();
241
        if ( opt->availableContent() & Solid::OpticalDisc::Audio )
242
        {
243
            debug() << "AudioCd";
244
            return true;
245
        }
246
    }
247
248
    return false;
249
}
250
251
252
void
253
MediaDeviceMonitor::connectIpod( const QString &mountpoint, const QString &udi )
254
{
255
    emit ipodReadyToConnect( mountpoint, udi );
256
}
257
258
void
259
MediaDeviceMonitor::disconnectIpod( const QString &udi )
260
{
261
    emit ipodReadyToDisconnect( udi );
262
}
263
264
void
265
MediaDeviceMonitor::connectMtp( const QString &serial, const QString &udi )
266
{
267
    emit mtpReadyToConnect( serial, udi );
268
}
269
270
void
271
MediaDeviceMonitor::disconnectMtp( const QString &udi )
272
{
273
    emit mtpReadyToDisconnect( udi );
274
}
275
276
QString
277
MediaDeviceMonitor::isCdPresent()
278
{
279
    DEBUG_BLOCK
280
281
    QStringList udiList = getDevices();
282
283
    /* poll udi list for supported devices */
284
    foreach( const QString &udi, udiList )
285
    {
286
        debug() << "udi: " << udi;
287
        if ( isAudioCd( udi ) )
288
        {
289
            return udi;
290
        }
291
    }
292
293
    return QString();
294
}
295
296
void
297
MediaDeviceMonitor::ejectCd( const QString & udi )
298
{
299
    DEBUG_BLOCK
300
    debug() << "trying to eject udi: " << udi;
301
    Solid::Device device = Solid::Device( udi ).parent();
302
303
    if ( !device.isValid() ) {
304
        debug() << "invalid device, cannot eject";
305
        return;
306
    }
307
308
309
    debug() << "lets tryto get an OpticalDrive out of this thing";
310
    if( device.is<Solid::OpticalDrive>() )
311
    {
312
        debug() << "claims to be an OpticalDrive";
313
        Solid::OpticalDrive * drive = device.as<Solid::OpticalDrive>();
314
        if ( drive )
315
        {
316
            debug() << "ejecting the bugger";
317
            drive->eject();
318
        }
319
    }
320
}
321
322
QString
323
MediaDeviceMonitor::currentCdId()
324
{
325
    return m_currentCdId;
326
}
327
328
void
329
MediaDeviceMonitor::setCurrentCdId( const QString & id )
330
{
331
    m_currentCdId = id;
332
}