/* * Cantata * * Copyright (c) 2011-2012 Craig Drummond * */ /**************************************************************************************** * Copyright (c) 2007 Jeff Mitchell * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * ****************************************************************************************/ #include "mediadevicecache.h" #ifdef ENABLE_KDE_SUPPORT #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #else #include "solid-lite/device.h" #include "solid-lite/deviceinterface.h" #include "solid-lite/devicenotifier.h" #include "solid-lite/genericinterface.h" #include "solid-lite/opticaldisc.h" #include "solid-lite/portablemediaplayer.h" #include "solid-lite/storageaccess.h" #include "solid-lite/storagedrive.h" #include "solid-lite/block.h" #include "solid-lite/storagevolume.h" #include #endif #include #include #include #define DEBUG_BLOCK #include #define debug qDebug MediaDeviceCache* MediaDeviceCache::s_instance = 0; MediaDeviceCache::MediaDeviceCache() : QObject() , m_type() , m_name() , m_volumes() { DEBUG_BLOCK s_instance = this; connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(const QString &)), this, SLOT(slotAddDevice(const QString &))); connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(const QString &)), this, SLOT(slotRemoveDevice(const QString &))); } MediaDeviceCache::~MediaDeviceCache() { s_instance = 0; } void MediaDeviceCache::refreshCache() { DEBUG_BLOCK m_type.clear(); m_name.clear(); QList deviceList = Solid::Device::listFromType(Solid::DeviceInterface::PortableMediaPlayer); foreach (const Solid::Device &device, deviceList) { if (device.as()) { debug() << "Found Solid PMP that is also a StorageDrive, skipping"; continue; } debug() << "Found Solid::DeviceInterface::PortableMediaPlayer with udi = " << device.udi(); debug() << "Device name is = " << device.product() << " and was made by " << device.vendor(); m_type[device.udi()] = MediaDeviceCache::PMPType; m_name[device.udi()] = device.vendor() + " - " + device.product(); } deviceList = Solid::Device::listFromType(Solid::DeviceInterface::StorageAccess); foreach (const Solid::Device &device, deviceList) { debug() << "Found Solid::DeviceInterface::StorageAccess with udi = " << device.udi(); debug() << "Device name is = " << device.product() << " and was made by " << device.vendor(); const Solid::StorageAccess* ssa = device.as(); if (ssa) { // Commented out - as we want a signal when any storage device is added/removed - so we can check for MPD dir accessibility. // device.cpp contains the check to ensure the device is a USB bevice before adding it to the list... // if ((!device.parent().as() || Solid::StorageDrive::Usb!=device.parent().as()->bus()) && // (!device.as() || Solid::StorageDrive::Usb!=device.as()->bus())) { // debug() << "Found Solid::DeviceInterface::StorageAccess that is not usb, skipping"; // continue; // } if (!m_volumes.contains(device.udi())) { connect(ssa, SIGNAL(accessibilityChanged(bool, const QString&)), this, SLOT(slotAccessibilityChanged(bool, const QString&))); m_volumes.append(device.udi()); } if (ssa->isAccessible()) { m_type[device.udi()] = MediaDeviceCache::VolumeType; m_name[device.udi()] = ssa->filePath(); m_accessibility[ device.udi() ] = true; } else { m_accessibility[ device.udi() ] = false; debug() << "Solid device is not accessible, will wait until it is to consider it added."; } } } // deviceList = Solid::Device::listFromType(Solid::DeviceInterface::StorageDrive); // foreach (const Solid::Device &device, deviceList) { // debug() << "Found Solid::DeviceInterface::StorageDrive with udi = " << device.udi(); // debug() << "Device name is = " << device.product() << " and was made by " << device.vendor(); // // if (device.as()) { // m_type[device.udi()] = MediaDeviceCache::GenericType; // m_name[device.udi()] = device.vendor() + " - " + device.product(); // } // } // deviceList = Solid::Device::listFromType(Solid::DeviceInterface::OpticalDisc); // foreach (const Solid::Device &device, deviceList) { // debug() << "Found Solid::DeviceInterface::OpticalDisc with udi = " << device.udi(); // debug() << "Device name is = " << device.product() << " and was made by " << device.vendor(); // // const Solid::OpticalDisc * opt = device.as(); // // if (opt && opt->availableContent() & Solid::OpticalDisc::Audio) { // debug() << "device is an Audio CD"; // m_type[device.udi()] = MediaDeviceCache::AudioCdType; // m_name[device.udi()] = device.vendor() + " - " + device.product(); // } // } // deviceList = Solid::Device::allDevices(); // foreach (const Solid::Device &device, deviceList) { // if (const Solid::GenericInterface *generic = device.as()) { // if (m_type.contains(device.udi())) // continue; // // const QMap properties = generic->allProperties(); // if (!properties.contains("info.capabilities")) // continue; // // const QStringList capabilities = properties["info.capabilities"].toStringList(); // if (!capabilities.contains("afc")) // continue; // // debug() << "Found AFC capable Solid::DeviceInterface::GenericInterface with udi = " << device.udi(); // debug() << "Device name is = " << device.product() << " and was made by " << device.vendor(); // // m_type[device.udi()] = MediaDeviceCache::GenericType; // m_name[device.udi()] = device.vendor() + " - " + device.product(); // } // } // KConfigGroup config(KGlobal::config(), "PortableDevices"); // const QStringList manualDeviceKeys = config.entryMap().keys(); // foreach (const QString &udi, manualDeviceKeys) { // if (udi.startsWith("manual")) { // debug() << "Found manual device with udi = " << udi; // m_type[udi] = MediaDeviceCache::ManualType; // m_name[udi] = udi.split('|')[1]; // } // } } void MediaDeviceCache::slotAddDevice(const QString &udi) { DEBUG_BLOCK Solid::Device device(udi); debug() << "Found new Solid device with udi = " << device.udi(); debug() << "Device name is = " << device.product() << " and was made by " << device.vendor(); Solid::StorageAccess *ssa = device.as(); Solid::OpticalDisc * opt = device.as(); if (opt && opt->availableContent() & Solid::OpticalDisc::Audio) { debug() << "device is an Audio CD"; m_type[udi] = MediaDeviceCache::AudioCdType; m_name[udi] = device.vendor() + " - " + device.product(); } else if (ssa) { debug() << "volume is generic storage"; if (!m_volumes.contains(device.udi())) { connect(ssa, SIGNAL(accessibilityChanged(bool, const QString&)), this, SLOT(slotAccessibilityChanged(bool, const QString&))); m_volumes.append(device.udi()); } if (ssa->isAccessible()) { m_type[udi] = MediaDeviceCache::VolumeType; m_name[udi] = ssa->filePath(); } else { debug() << "storage volume is not accessible right now, not adding."; return; } } else if (device.is()) { debug() << "device is a Storage drive, still need a volume"; m_type[udi] = MediaDeviceCache::GenericType; m_name[udi] = device.vendor() + " - " + device.product(); } else if (device.is()) { debug() << "device is a PMP"; m_type[udi] = MediaDeviceCache::PMPType; m_name[udi] = device.vendor() + " - " + device.product(); } else if (const Solid::GenericInterface *generic = device.as()) { const QMap properties = generic->allProperties(); /* At least iPod touch 3G and iPhone 3G do not advertise AFC (Apple File * Connection) capabilities. Therefore we have to white-list them so that they are * still recognised ad iPods * * @see IpodConnectionAssistant::identify() for a quirk that is currently also * needed for proper identification of iPhone-like devices. */ if (!device.product().contains("iPod") && !device.product().contains("iPhone")) { if (!properties.contains("info.capabilities")) { debug() << "udi " << udi << " does not describe a portable media player or storage volume"; return; } const QStringList capabilities = properties["info.capabilities"].toStringList(); if (!capabilities.contains("afc")) { debug() << "udi " << udi << " does not describe a portable media player or storage volume"; return; } } debug() << "udi" << udi << "is AFC cabable (Apple mobile device)"; m_type[udi] = MediaDeviceCache::GenericType; m_name[udi] = device.vendor() + " - " + device.product(); } else { debug() << "udi " << udi << " does not describe a portable media player or storage volume"; return; } emit deviceAdded(udi); } void MediaDeviceCache::slotRemoveDevice(const QString &udi) { DEBUG_BLOCK debug() << "udi is: " << udi; Solid::Device device(udi); if (m_volumes.contains(udi)) { disconnect(device.as(), SIGNAL(accessibilityChanged(bool, const QString&)), this, SLOT(slotAccessibilityChanged(bool, const QString&))); m_volumes.removeAll(udi); // emit deviceRemoved(udi); } if (m_type.contains(udi)) { m_type.remove(udi); m_name.remove(udi); // emit deviceRemoved(udi); } debug() << "Odd, got a deviceRemoved at udi " << udi << " but it did not seem to exist in the first place..."; emit deviceRemoved(udi); } void MediaDeviceCache::slotAccessibilityChanged(bool accessible, const QString &udi) { debug() << "accessibility of device " << udi << " has changed to accessible = " << (accessible ? "true":"false"); if (accessible) { Solid::Device device(udi); m_type[udi] = MediaDeviceCache::VolumeType; Solid::StorageAccess *ssa = device.as(); if (ssa) { m_name[udi] = ssa->filePath(); } emit deviceAdded(udi); return; } else { if (m_type.contains(udi)) { m_type.remove(udi); m_name.remove(udi); emit deviceRemoved(udi); return; } debug() << "Got accessibility changed to false but was not there in the first place..."; } emit accessibilityChanged(accessible, udi); } MediaDeviceCache::DeviceType MediaDeviceCache::deviceType(const QString &udi) const { if (m_type.contains(udi)) { return m_type[udi]; } return MediaDeviceCache::InvalidType; } const QString MediaDeviceCache::deviceName(const QString &udi) const { if (m_name.contains(udi)) { return m_name[udi]; } return "ERR_NO_NAME"; //Should never happen! }