2013-04-25 16:02:17 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2014-01-07 13:27:11 +01:00
|
|
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
2013-04-25 16:02:17 +02:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Digia. For licensing terms and
|
2014-10-01 13:21:18 +02:00
|
|
|
** conditions see http://www.qt.io/licensing. For further information
|
|
|
|
|
** use the contact form at http://www.qt.io/contact-us.
|
2013-04-25 16:02:17 +02:00
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
2014-10-01 13:21:18 +02:00
|
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
|
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
|
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
|
|
|
** following information to ensure the GNU Lesser General Public License
|
|
|
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2013-04-25 16:02:17 +02:00
|
|
|
**
|
|
|
|
|
** In addition, as a special exception, Digia gives you certain additional
|
|
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "iosdevice.h"
|
|
|
|
|
#include "iosconstants.h"
|
|
|
|
|
#include "iosconfigurations.h"
|
|
|
|
|
#include "iostoolhandler.h"
|
|
|
|
|
#include <projectexplorer/devicesupport/devicemanager.h>
|
|
|
|
|
#include <projectexplorer/kitinformation.h>
|
2013-10-28 08:14:18 +01:00
|
|
|
#include <coreplugin/helpmanager.h>
|
2014-02-25 16:02:02 +01:00
|
|
|
#include <utils/portlist.h>
|
2013-04-25 16:02:17 +02:00
|
|
|
|
|
|
|
|
#include <QCoreApplication>
|
|
|
|
|
#include <QVariant>
|
|
|
|
|
#include <QVariantMap>
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
|
2013-10-11 13:55:45 +02:00
|
|
|
#ifdef Q_OS_MAC
|
2013-04-25 16:02:17 +02:00
|
|
|
#include <IOKit/IOKitLib.h>
|
|
|
|
|
#include <IOKit/usb/IOUSBLib.h>
|
|
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
2013-10-11 13:55:45 +02:00
|
|
|
#endif
|
|
|
|
|
|
2013-11-28 14:45:56 +01:00
|
|
|
#include <exception>
|
|
|
|
|
|
2013-04-25 16:02:17 +02:00
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
|
2014-07-07 09:24:17 +02:00
|
|
|
namespace {
|
|
|
|
|
Q_LOGGING_CATEGORY(detectLog, "qtc.ios.deviceDetect")
|
|
|
|
|
}
|
2013-04-25 16:02:17 +02:00
|
|
|
|
2013-10-11 13:55:45 +02:00
|
|
|
#ifdef Q_OS_MAC
|
|
|
|
|
static QString CFStringRef2QString(CFStringRef s)
|
2013-04-25 16:02:17 +02:00
|
|
|
{
|
|
|
|
|
unsigned char buf[250];
|
|
|
|
|
CFIndex len = CFStringGetLength(s);
|
|
|
|
|
CFIndex usedBufLen;
|
|
|
|
|
CFIndex converted = CFStringGetBytes(s, CFRangeMake(0,len), kCFStringEncodingUTF8,
|
|
|
|
|
'?', false, &buf[0], sizeof(buf), &usedBufLen);
|
|
|
|
|
if (converted == len)
|
|
|
|
|
return QString::fromUtf8(reinterpret_cast<char *>(&buf[0]), usedBufLen);
|
|
|
|
|
size_t bufSize = sizeof(buf)
|
|
|
|
|
+ CFStringGetMaximumSizeForEncoding(len - converted, kCFStringEncodingUTF8);
|
|
|
|
|
unsigned char *bigBuf = new unsigned char[bufSize];
|
|
|
|
|
memcpy(bigBuf, buf, usedBufLen);
|
|
|
|
|
CFIndex newUseBufLen;
|
|
|
|
|
CFStringGetBytes(s, CFRangeMake(converted,len), kCFStringEncodingUTF8,
|
|
|
|
|
'?', false, &bigBuf[usedBufLen], bufSize, &newUseBufLen);
|
|
|
|
|
QString res = QString::fromUtf8(reinterpret_cast<char *>(bigBuf), usedBufLen + newUseBufLen);
|
|
|
|
|
delete[] bigBuf;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2013-10-11 13:55:45 +02:00
|
|
|
#endif
|
2013-04-25 16:02:17 +02:00
|
|
|
|
|
|
|
|
namespace Ios {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
IosDevice::IosDevice()
|
|
|
|
|
: IDevice(Core::Id(Constants::IOS_DEVICE_TYPE),
|
|
|
|
|
IDevice::AutoDetected,
|
|
|
|
|
IDevice::Hardware,
|
2014-02-25 16:02:02 +01:00
|
|
|
Constants::IOS_DEVICE_ID),
|
|
|
|
|
m_lastPort(Constants::IOS_DEVICE_PORT_START)
|
2013-04-25 16:02:17 +02:00
|
|
|
{
|
2013-11-04 15:08:41 +01:00
|
|
|
setDisplayName(IosDevice::name());
|
2013-11-28 16:02:22 +01:00
|
|
|
setDeviceState(DeviceDisconnected);
|
2014-02-25 16:02:02 +01:00
|
|
|
Utils::PortList ports;
|
|
|
|
|
ports.addRange(Constants::IOS_DEVICE_PORT_START,
|
|
|
|
|
Constants::IOS_DEVICE_PORT_END);
|
|
|
|
|
setFreePorts(ports);
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IosDevice::IosDevice(const IosDevice &other)
|
2014-02-25 16:02:02 +01:00
|
|
|
: IDevice(other), m_extraInfo(other.m_extraInfo), m_ignoreDevice(other.m_ignoreDevice),
|
|
|
|
|
m_lastPort(other.m_lastPort)
|
2013-04-25 16:02:17 +02:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
IosDevice::IosDevice(const QString &uid)
|
|
|
|
|
: IDevice(Core::Id(Constants::IOS_DEVICE_TYPE),
|
|
|
|
|
IDevice::AutoDetected,
|
|
|
|
|
IDevice::Hardware,
|
2014-02-25 16:02:02 +01:00
|
|
|
Core::Id(Constants::IOS_DEVICE_ID).withSuffix(uid)),
|
|
|
|
|
m_lastPort(Constants::IOS_DEVICE_PORT_START)
|
2013-04-25 16:02:17 +02:00
|
|
|
{
|
2013-11-04 15:08:41 +01:00
|
|
|
setDisplayName(IosDevice::name());
|
2013-11-28 16:02:22 +01:00
|
|
|
setDeviceState(DeviceDisconnected);
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IDevice::DeviceInfo IosDevice::deviceInformation() const
|
|
|
|
|
{
|
|
|
|
|
IDevice::DeviceInfo res;
|
|
|
|
|
QMapIterator<QString, QString> i(m_extraInfo);
|
|
|
|
|
while (i.hasNext()) {
|
|
|
|
|
i.next();
|
|
|
|
|
IosDeviceManager::TranslationMap tMap = IosDeviceManager::translationMap();
|
|
|
|
|
if (tMap.contains(i.key()))
|
|
|
|
|
res.append(DeviceInfoItem(tMap.value(i.key()), tMap.value(i.value(), i.value())));
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString IosDevice::displayType() const
|
|
|
|
|
{
|
|
|
|
|
return QCoreApplication::translate("Ios::Internal::IosDevice", "iOS");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IDeviceWidget *IosDevice::createWidget()
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<Core::Id> IosDevice::actionIds() const
|
|
|
|
|
{
|
|
|
|
|
return QList<Core::Id>(); // add activation action?
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString IosDevice::displayNameForActionId(Core::Id actionId) const
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(actionId)
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosDevice::executeAction(Core::Id actionId, QWidget *parent)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(actionId)
|
|
|
|
|
Q_UNUSED(parent)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DeviceProcessSignalOperation::Ptr IosDevice::signalOperation() const
|
|
|
|
|
{
|
|
|
|
|
return DeviceProcessSignalOperation::Ptr();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IDevice::Ptr IosDevice::clone() const
|
|
|
|
|
{
|
|
|
|
|
return IDevice::Ptr(new IosDevice(*this));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosDevice::fromMap(const QVariantMap &map)
|
|
|
|
|
{
|
|
|
|
|
IDevice::fromMap(map);
|
2014-02-25 22:20:16 +01:00
|
|
|
QVariantMap vMap = map.value(QLatin1String(Constants::EXTRA_INFO_KEY)).toMap();
|
2013-04-25 16:02:17 +02:00
|
|
|
QMapIterator<QString, QVariant> i(vMap);
|
|
|
|
|
m_extraInfo.clear();
|
|
|
|
|
while (i.hasNext()) {
|
|
|
|
|
i.next();
|
|
|
|
|
m_extraInfo.insert(i.key(), i.value().toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariantMap IosDevice::toMap() const
|
|
|
|
|
{
|
|
|
|
|
QVariantMap res = IDevice::toMap();
|
|
|
|
|
QVariantMap vMap;
|
|
|
|
|
QMapIterator<QString, QString> i(m_extraInfo);
|
|
|
|
|
while (i.hasNext()) {
|
|
|
|
|
i.next();
|
|
|
|
|
vMap.insert(i.key(), i.value());
|
|
|
|
|
}
|
2014-02-25 22:20:16 +01:00
|
|
|
res.insert(QLatin1String(Constants::EXTRA_INFO_KEY), vMap);
|
2013-04-25 16:02:17 +02:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString IosDevice::uniqueDeviceID() const
|
|
|
|
|
{
|
|
|
|
|
return id().suffixAfter(Core::Id(Constants::IOS_DEVICE_ID));
|
|
|
|
|
}
|
2013-11-04 15:08:41 +01:00
|
|
|
|
|
|
|
|
QString IosDevice::name()
|
|
|
|
|
{
|
|
|
|
|
return QCoreApplication::translate("Ios::Internal::IosDevice", "iOS Device");
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-10 12:53:20 +01:00
|
|
|
QString IosDevice::osVersion() const
|
2013-04-25 16:02:17 +02:00
|
|
|
{
|
2013-12-10 12:53:20 +01:00
|
|
|
return m_extraInfo.value(QLatin1String("osVersion"));
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
2014-02-25 16:02:02 +01:00
|
|
|
quint16 IosDevice::nextPort() const
|
|
|
|
|
{
|
|
|
|
|
// use qrand instead?
|
|
|
|
|
if (++m_lastPort >= Constants::IOS_DEVICE_PORT_END)
|
|
|
|
|
m_lastPort = Constants::IOS_DEVICE_PORT_START;
|
|
|
|
|
return m_lastPort;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IosDevice::canAutoDetectPorts() const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-25 16:02:17 +02:00
|
|
|
|
|
|
|
|
// IosDeviceManager
|
|
|
|
|
|
|
|
|
|
IosDeviceManager::TranslationMap IosDeviceManager::translationMap()
|
|
|
|
|
{
|
|
|
|
|
static TranslationMap *translationMap = 0;
|
|
|
|
|
if (translationMap)
|
|
|
|
|
return *translationMap;
|
|
|
|
|
TranslationMap &tMap = *new TranslationMap;
|
|
|
|
|
tMap[QLatin1String("deviceName")] = tr("Device name");
|
2013-11-04 15:10:15 +01:00
|
|
|
//: Whether the device is in developer mode.
|
2013-04-25 16:02:17 +02:00
|
|
|
tMap[QLatin1String("developerStatus")] = tr("Developer status");
|
|
|
|
|
tMap[QLatin1String("deviceConnected")] = tr("Connected");
|
|
|
|
|
tMap[QLatin1String("YES")] = tr("yes");
|
|
|
|
|
tMap[QLatin1String("NO")] = tr("no");
|
|
|
|
|
tMap[QLatin1String("YES")] = tr("yes");
|
|
|
|
|
tMap[QLatin1String("*unknown*")] = tr("unknown");
|
2013-12-10 12:53:20 +01:00
|
|
|
tMap[QLatin1String("osVersion")] = tr("OS version");
|
2013-04-25 16:02:17 +02:00
|
|
|
translationMap = &tMap;
|
|
|
|
|
return tMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosDeviceManager::deviceConnected(const QString &uid, const QString &name)
|
|
|
|
|
{
|
|
|
|
|
DeviceManager *devManager = DeviceManager::instance();
|
|
|
|
|
Core::Id baseDevId(Constants::IOS_DEVICE_ID);
|
|
|
|
|
Core::Id devType(Constants::IOS_DEVICE_TYPE);
|
|
|
|
|
Core::Id devId = baseDevId.withSuffix(uid);
|
|
|
|
|
IDevice::ConstPtr dev = devManager->find(devId);
|
|
|
|
|
if (dev.isNull()) {
|
|
|
|
|
IosDevice *newDev = new IosDevice(uid);
|
|
|
|
|
if (!name.isNull())
|
|
|
|
|
newDev->setDisplayName(name);
|
2014-07-07 09:24:17 +02:00
|
|
|
qCDebug(detectLog) << "adding ios device " << uid;
|
2013-04-25 16:02:17 +02:00
|
|
|
devManager->addDevice(IDevice::ConstPtr(newDev));
|
|
|
|
|
} else if (dev->deviceState() != IDevice::DeviceConnected &&
|
|
|
|
|
dev->deviceState() != IDevice::DeviceReadyToUse) {
|
2014-07-07 09:24:17 +02:00
|
|
|
qCDebug(detectLog) << "updating ios device " << uid;
|
2013-04-25 16:02:17 +02:00
|
|
|
IosDevice *newDev = 0;
|
|
|
|
|
if (dev->type() == devType) {
|
|
|
|
|
const IosDevice *iosDev = static_cast<const IosDevice *>(dev.data());
|
|
|
|
|
newDev = new IosDevice(*iosDev);
|
|
|
|
|
} else {
|
|
|
|
|
newDev = new IosDevice(uid);
|
|
|
|
|
}
|
|
|
|
|
devManager->addDevice(IDevice::ConstPtr(newDev));
|
|
|
|
|
}
|
|
|
|
|
updateInfo(uid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosDeviceManager::deviceDisconnected(const QString &uid)
|
|
|
|
|
{
|
2014-07-07 09:24:17 +02:00
|
|
|
qCDebug(detectLog) << "detected disconnection of ios device " << uid;
|
2013-04-25 16:02:17 +02:00
|
|
|
DeviceManager *devManager = DeviceManager::instance();
|
|
|
|
|
Core::Id baseDevId(Constants::IOS_DEVICE_ID);
|
|
|
|
|
Core::Id devType(Constants::IOS_DEVICE_TYPE);
|
|
|
|
|
Core::Id devId = baseDevId.withSuffix(uid);
|
|
|
|
|
IDevice::ConstPtr dev = devManager->find(devId);
|
|
|
|
|
if (dev.isNull() || dev->type() != devType) {
|
2014-07-07 09:24:17 +02:00
|
|
|
qCWarning(detectLog) << "ignoring disconnection of ios device " << uid; // should neve happen
|
2013-04-25 16:02:17 +02:00
|
|
|
} else {
|
|
|
|
|
const IosDevice *iosDev = static_cast<const IosDevice *>(dev.data());
|
2014-02-25 22:20:16 +01:00
|
|
|
if (iosDev->m_extraInfo.isEmpty()
|
|
|
|
|
|| iosDev->m_extraInfo.value(QLatin1String("deviceName")) == QLatin1String("*unknown*")) {
|
|
|
|
|
devManager->removeDevice(iosDev->id());
|
|
|
|
|
} else if (iosDev->deviceState() != IDevice::DeviceDisconnected) {
|
2014-07-07 09:24:17 +02:00
|
|
|
qCDebug(detectLog) << "disconnecting device " << iosDev->uniqueDeviceID();
|
2013-04-25 16:02:17 +02:00
|
|
|
devManager->setDeviceState(iosDev->id(), IDevice::DeviceDisconnected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosDeviceManager::updateInfo(const QString &devId)
|
|
|
|
|
{
|
2014-03-28 19:05:35 +01:00
|
|
|
IosToolHandler *requester = new IosToolHandler(IosDeviceType::IosDevice, this);
|
2013-04-25 16:02:17 +02:00
|
|
|
connect(requester, SIGNAL(deviceInfo(Ios::IosToolHandler*,QString,Ios::IosToolHandler::Dict)),
|
2013-10-10 17:41:34 +02:00
|
|
|
SLOT(deviceInfo(Ios::IosToolHandler*,QString,Ios::IosToolHandler::Dict)), Qt::QueuedConnection);
|
2013-04-25 16:02:17 +02:00
|
|
|
connect(requester, SIGNAL(finished(Ios::IosToolHandler*)),
|
|
|
|
|
SLOT(infoGathererFinished(Ios::IosToolHandler*)));
|
|
|
|
|
requester->requestDeviceInfo(devId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosDeviceManager::deviceInfo(IosToolHandler *, const QString &uid,
|
|
|
|
|
const Ios::IosToolHandler::Dict &info)
|
|
|
|
|
{
|
|
|
|
|
DeviceManager *devManager = DeviceManager::instance();
|
|
|
|
|
Core::Id baseDevId(Constants::IOS_DEVICE_ID);
|
|
|
|
|
Core::Id devType(Constants::IOS_DEVICE_TYPE);
|
|
|
|
|
Core::Id devId = baseDevId.withSuffix(uid);
|
|
|
|
|
IDevice::ConstPtr dev = devManager->find(devId);
|
|
|
|
|
bool skipUpdate = false;
|
|
|
|
|
IosDevice *newDev = 0;
|
|
|
|
|
if (!dev.isNull() && dev->type() == devType) {
|
|
|
|
|
const IosDevice *iosDev = static_cast<const IosDevice *>(dev.data());
|
|
|
|
|
if (iosDev->m_extraInfo == info) {
|
|
|
|
|
skipUpdate = true;
|
|
|
|
|
newDev = const_cast<IosDevice *>(iosDev);
|
|
|
|
|
} else {
|
|
|
|
|
newDev = new IosDevice(*iosDev);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
newDev = new IosDevice(uid);
|
|
|
|
|
}
|
|
|
|
|
if (!skipUpdate) {
|
|
|
|
|
QString devNameKey = QLatin1String("deviceName");
|
|
|
|
|
if (info.contains(devNameKey))
|
|
|
|
|
newDev->setDisplayName(info.value(devNameKey));
|
|
|
|
|
newDev->m_extraInfo = info;
|
2014-07-07 09:24:17 +02:00
|
|
|
qCDebug(detectLog) << "updated info of ios device " << uid;
|
2013-04-25 16:02:17 +02:00
|
|
|
dev = IDevice::ConstPtr(newDev);
|
|
|
|
|
devManager->addDevice(dev);
|
|
|
|
|
}
|
|
|
|
|
QLatin1String devStatusKey = QLatin1String("developerStatus");
|
|
|
|
|
if (info.contains(devStatusKey)) {
|
|
|
|
|
QString devStatus = info.value(devStatusKey);
|
2014-02-14 01:08:09 +01:00
|
|
|
if (devStatus == QLatin1String("Development")) {
|
2013-04-25 16:02:17 +02:00
|
|
|
devManager->setDeviceState(newDev->id(), IDevice::DeviceReadyToUse);
|
2014-02-14 01:08:09 +01:00
|
|
|
m_userModeDeviceIds.removeOne(uid);
|
2013-04-25 16:02:17 +02:00
|
|
|
} else {
|
|
|
|
|
devManager->setDeviceState(newDev->id(), IDevice::DeviceConnected);
|
2014-02-14 01:08:09 +01:00
|
|
|
bool shouldIgnore = newDev->m_ignoreDevice;
|
|
|
|
|
newDev->m_ignoreDevice = true;
|
|
|
|
|
if (devStatus == QLatin1String("*off*")) {
|
|
|
|
|
if (!shouldIgnore && !IosConfigurations::ignoreAllDevices()) {
|
|
|
|
|
QMessageBox mBox;
|
|
|
|
|
mBox.setText(tr("An iOS device in user mode has been detected."));
|
|
|
|
|
mBox.setInformativeText(tr("Do you want to see how to set it up for development?"));
|
|
|
|
|
mBox.setStandardButtons(QMessageBox::NoAll | QMessageBox::No | QMessageBox::Yes);
|
|
|
|
|
mBox.setDefaultButton(QMessageBox::Yes);
|
|
|
|
|
int ret = mBox.exec();
|
|
|
|
|
switch (ret) {
|
|
|
|
|
case QMessageBox::Yes:
|
|
|
|
|
Core::HelpManager::handleHelpRequest(
|
|
|
|
|
QLatin1String("qthelp://org.qt-project.qtcreator/doc/creator-developing-ios.html"));
|
|
|
|
|
break;
|
|
|
|
|
case QMessageBox::No:
|
|
|
|
|
break;
|
|
|
|
|
case QMessageBox::NoAll:
|
|
|
|
|
IosConfigurations::setIgnoreAllDevices(true);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!m_userModeDeviceIds.contains(uid))
|
|
|
|
|
m_userModeDeviceIds.append(uid);
|
|
|
|
|
m_userModeDevicesTimer.start();
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosDeviceManager::infoGathererFinished(IosToolHandler *gatherer)
|
|
|
|
|
{
|
|
|
|
|
gatherer->deleteLater();
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-11 13:55:45 +02:00
|
|
|
#ifdef Q_OS_MAC
|
2013-04-25 16:02:17 +02:00
|
|
|
namespace {
|
|
|
|
|
io_iterator_t gAddedIter;
|
|
|
|
|
io_iterator_t gRemovedIter;
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
void deviceConnectedCallback(void *refCon, io_iterator_t iterator)
|
|
|
|
|
{
|
2013-11-28 14:45:56 +01:00
|
|
|
try {
|
|
|
|
|
kern_return_t kr;
|
|
|
|
|
io_service_t usbDevice;
|
|
|
|
|
(void) refCon;
|
|
|
|
|
|
|
|
|
|
while ((usbDevice = IOIteratorNext(iterator))) {
|
|
|
|
|
io_name_t deviceName;
|
|
|
|
|
|
|
|
|
|
// Get the USB device's name.
|
|
|
|
|
kr = IORegistryEntryGetName(usbDevice, deviceName);
|
|
|
|
|
QString name;
|
|
|
|
|
if (KERN_SUCCESS == kr)
|
|
|
|
|
name = QString::fromLocal8Bit(deviceName);
|
2014-07-07 09:24:17 +02:00
|
|
|
qCDebug(detectLog) << "ios device " << name << " in deviceAddedCallback";
|
2013-04-25 16:02:17 +02:00
|
|
|
|
|
|
|
|
CFStringRef cfUid = static_cast<CFStringRef>(IORegistryEntryCreateCFProperty(
|
|
|
|
|
usbDevice,
|
|
|
|
|
CFSTR(kUSBSerialNumberString),
|
|
|
|
|
kCFAllocatorDefault, 0));
|
|
|
|
|
QString uid = CFStringRef2QString(cfUid);
|
|
|
|
|
CFRelease(cfUid);
|
2013-11-28 14:45:56 +01:00
|
|
|
IosDeviceManager::instance()->deviceConnected(uid, name);
|
|
|
|
|
|
|
|
|
|
// Done with this USB device; release the reference added by IOIteratorNext
|
|
|
|
|
kr = IOObjectRelease(usbDevice);
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
2013-11-28 14:45:56 +01:00
|
|
|
}
|
|
|
|
|
catch (std::exception &e) {
|
2014-07-07 09:24:17 +02:00
|
|
|
qCWarning(detectLog) << "Exception " << e.what() << " in iosdevice.cpp deviceConnectedCallback";
|
2013-11-28 14:45:56 +01:00
|
|
|
}
|
|
|
|
|
catch (...) {
|
2014-07-07 09:24:17 +02:00
|
|
|
qCWarning(detectLog) << "Exception in iosdevice.cpp deviceConnectedCallback";
|
2013-11-28 14:45:56 +01:00
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void deviceDisconnectedCallback(void *refCon, io_iterator_t iterator)
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
kern_return_t kr;
|
|
|
|
|
io_service_t usbDevice;
|
|
|
|
|
(void) refCon;
|
|
|
|
|
|
|
|
|
|
while ((usbDevice = IOIteratorNext(iterator))) {
|
|
|
|
|
io_name_t deviceName;
|
|
|
|
|
|
|
|
|
|
// Get the USB device's name.
|
|
|
|
|
kr = IORegistryEntryGetName(usbDevice, deviceName);
|
|
|
|
|
if (KERN_SUCCESS != kr)
|
|
|
|
|
deviceName[0] = '\0';
|
2014-07-07 09:24:17 +02:00
|
|
|
qCDebug(detectLog) << "ios device " << deviceName << " in deviceDisconnectedCallback";
|
2013-11-28 14:45:56 +01:00
|
|
|
|
|
|
|
|
{
|
|
|
|
|
CFStringRef cfUid = static_cast<CFStringRef>(IORegistryEntryCreateCFProperty(
|
|
|
|
|
usbDevice,
|
|
|
|
|
CFSTR(kUSBSerialNumberString),
|
|
|
|
|
kCFAllocatorDefault, 0));
|
|
|
|
|
QString uid = CFStringRef2QString(cfUid);
|
|
|
|
|
CFRelease(cfUid);
|
|
|
|
|
IosDeviceManager::instance()->deviceDisconnected(uid);
|
|
|
|
|
}
|
2013-04-25 16:02:17 +02:00
|
|
|
|
2013-11-28 14:45:56 +01:00
|
|
|
// Done with this USB device; release the reference added by IOIteratorNext
|
|
|
|
|
kr = IOObjectRelease(usbDevice);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (std::exception &e) {
|
2014-07-07 09:24:17 +02:00
|
|
|
qCWarning(detectLog) << "Exception " << e.what() << " in iosdevice.cpp deviceDisconnectedCallback";
|
2013-11-28 14:45:56 +01:00
|
|
|
}
|
|
|
|
|
catch (...) {
|
2014-07-07 09:24:17 +02:00
|
|
|
qCWarning(detectLog) << "Exception in iosdevice.cpp deviceDisconnectedCallback";
|
2013-11-28 14:45:56 +01:00
|
|
|
throw;
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // extern C
|
|
|
|
|
|
|
|
|
|
} // anonymous namespace
|
2013-10-11 13:55:45 +02:00
|
|
|
#endif
|
2013-04-25 16:02:17 +02:00
|
|
|
|
|
|
|
|
void IosDeviceManager::monitorAvailableDevices()
|
|
|
|
|
{
|
2013-10-11 13:55:45 +02:00
|
|
|
#ifdef Q_OS_MAC
|
2013-04-25 16:02:17 +02:00
|
|
|
CFMutableDictionaryRef matchingDictionary =
|
|
|
|
|
IOServiceMatching("IOUSBDevice" );
|
|
|
|
|
{
|
|
|
|
|
UInt32 vendorId = 0x05ac;
|
|
|
|
|
CFNumberRef cfVendorValue = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type,
|
|
|
|
|
&vendorId );
|
|
|
|
|
CFDictionaryAddValue( matchingDictionary, CFSTR( kUSBVendorID ), cfVendorValue);
|
|
|
|
|
CFRelease( cfVendorValue );
|
|
|
|
|
UInt32 productId = 0x1280;
|
|
|
|
|
CFNumberRef cfProductIdValue = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type,
|
|
|
|
|
&productId );
|
|
|
|
|
CFDictionaryAddValue( matchingDictionary, CFSTR( kUSBProductID ), cfProductIdValue);
|
|
|
|
|
CFRelease( cfProductIdValue );
|
|
|
|
|
UInt32 productIdMask = 0xFFC0;
|
|
|
|
|
CFNumberRef cfProductIdMaskValue = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type,
|
|
|
|
|
&productIdMask );
|
|
|
|
|
CFDictionaryAddValue( matchingDictionary, CFSTR( kUSBProductIDMask ), cfProductIdMaskValue);
|
|
|
|
|
CFRelease( cfProductIdMaskValue );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IONotificationPortRef notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
|
|
|
|
|
CFRunLoopSourceRef runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
|
|
|
|
|
|
|
|
|
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
|
|
|
|
|
|
|
|
|
|
// IOServiceAddMatchingNotification releases this, so we retain for the next call
|
|
|
|
|
CFRetain(matchingDictionary);
|
|
|
|
|
|
|
|
|
|
// Now set up a notification to be called when a device is first matched by I/O Kit.
|
|
|
|
|
kern_return_t kr;
|
|
|
|
|
kr = IOServiceAddMatchingNotification(notificationPort,
|
|
|
|
|
kIOMatchedNotification,
|
|
|
|
|
matchingDictionary,
|
|
|
|
|
deviceConnectedCallback,
|
|
|
|
|
NULL,
|
|
|
|
|
&gAddedIter);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
kr = IOServiceAddMatchingNotification(notificationPort,
|
|
|
|
|
kIOTerminatedNotification,
|
|
|
|
|
matchingDictionary,
|
|
|
|
|
deviceDisconnectedCallback,
|
|
|
|
|
NULL,
|
|
|
|
|
&gRemovedIter);
|
|
|
|
|
|
|
|
|
|
// Iterate once to get already-present devices and arm the notification
|
|
|
|
|
deviceConnectedCallback(NULL, gAddedIter);
|
|
|
|
|
deviceDisconnectedCallback(NULL, gRemovedIter);
|
2013-10-11 13:55:45 +02:00
|
|
|
#endif
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IosDeviceManager::IosDeviceManager(QObject *parent) :
|
|
|
|
|
QObject(parent)
|
|
|
|
|
{
|
2014-02-14 01:08:09 +01:00
|
|
|
m_userModeDevicesTimer.setSingleShot(true);
|
|
|
|
|
m_userModeDevicesTimer.setInterval(8000);
|
|
|
|
|
connect(&m_userModeDevicesTimer, SIGNAL(timeout()),
|
|
|
|
|
SLOT(updateUserModeDevices()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosDeviceManager::updateUserModeDevices()
|
|
|
|
|
{
|
|
|
|
|
foreach (const QString &uid, m_userModeDeviceIds)
|
|
|
|
|
updateInfo(uid);
|
2013-04-25 16:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IosDeviceManager *IosDeviceManager::instance()
|
|
|
|
|
{
|
|
|
|
|
static IosDeviceManager obj;
|
|
|
|
|
return &obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IosDeviceManager::updateAvailableDevices(const QStringList &devices)
|
|
|
|
|
{
|
|
|
|
|
foreach (const QString &uid, devices)
|
|
|
|
|
deviceConnected(uid);
|
|
|
|
|
|
|
|
|
|
DeviceManager *devManager = DeviceManager::instance();
|
|
|
|
|
for (int iDevice = 0; iDevice < devManager->deviceCount(); ++iDevice) {
|
|
|
|
|
IDevice::ConstPtr dev = devManager->deviceAt(iDevice);
|
|
|
|
|
Core::Id devType(Constants::IOS_DEVICE_TYPE);
|
|
|
|
|
if (dev.isNull() || dev->type() != devType)
|
|
|
|
|
continue;
|
|
|
|
|
const IosDevice *iosDev = static_cast<const IosDevice *>(dev.data());
|
|
|
|
|
if (devices.contains(iosDev->uniqueDeviceID()))
|
|
|
|
|
continue;
|
|
|
|
|
if (iosDev->deviceState() != IDevice::DeviceDisconnected) {
|
2014-07-07 09:24:17 +02:00
|
|
|
qCDebug(detectLog) << "disconnecting device " << iosDev->uniqueDeviceID();
|
2013-04-25 16:02:17 +02:00
|
|
|
devManager->setDeviceState(iosDev->id(), IDevice::DeviceDisconnected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IosDevice::ConstPtr IosKitInformation::device(Kit *kit)
|
|
|
|
|
{
|
|
|
|
|
if (!kit)
|
|
|
|
|
return IosDevice::ConstPtr();
|
|
|
|
|
ProjectExplorer::IDevice::ConstPtr dev = ProjectExplorer::DeviceKitInformation::device(kit);
|
|
|
|
|
IosDevice::ConstPtr res = dev.dynamicCast<const IosDevice>();
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Ios
|