diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 3b3e710426c..f5f8693dd13 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -68,6 +68,8 @@ #include #include +#include +#include #include @@ -129,6 +131,8 @@ namespace { return dev1.type == AndroidDeviceInfo::Hardware; if (dev1.sdk != dev2.sdk) return dev1.sdk < dev2.sdk; + if (dev1.avdname != dev2.avdname) + return dev1.avdname < dev2.avdname; return dev1.serialNumber < dev2.serialNumber; } @@ -564,6 +568,10 @@ QVector AndroidConfig::connectedDevices(const QString &adbToo dev.state = AndroidDeviceInfo::OfflineState; else dev.state = AndroidDeviceInfo::OkState; + + if (dev.type == AndroidDeviceInfo::Emulator) + dev.avdname = getAvdName(dev.serialNumber); + devices.push_back(dev); } @@ -700,7 +708,7 @@ QVector AndroidConfig::androidVirtualDevices(const QString &a int index = line.indexOf(QLatin1Char(':')) + 2; if (index >= line.size()) break; - dev.serialNumber = line.mid(index).trimmed(); + dev.avdname = line.mid(index).trimmed(); dev.sdk = -1; dev.cpuAbi.clear(); ++i; @@ -752,10 +760,10 @@ QVector AndroidConfig::androidVirtualDevices(const QString &a return devices; } -QString AndroidConfig::startAVD(const QString &name, int apiLevel, QString cpuAbi) const +QString AndroidConfig::startAVD(const QString &name) const { - if (!findAvd(apiLevel, cpuAbi).isEmpty() || startAVDAsync(name)) - return waitForAvd(apiLevel, cpuAbi); + if (!findAvd(name).isEmpty() || startAVDAsync(name)) + return waitForAvd(name); return QString(); } @@ -779,17 +787,14 @@ bool AndroidConfig::startAVDAsync(const QString &avdName) const return true; } -QString AndroidConfig::findAvd(int apiLevel, const QString &cpuAbi) const +QString AndroidConfig::findAvd(const QString &avdName) const { QVector devices = connectedDevices(); foreach (AndroidDeviceInfo device, devices) { - if (!device.serialNumber.startsWith(QLatin1String("emulator"))) + if (device.type != AndroidDeviceInfo::Emulator) continue; - if (!device.cpuAbi.contains(cpuAbi)) - continue; - if (device.sdk != apiLevel) - continue; - return device.serialNumber; + if (device.avdname == avdName) + return device.serialNumber; } return QString(); } @@ -821,7 +826,7 @@ bool AndroidConfig::waitForBooted(const QString &serialNumber, const QFutureInte return false; } -QString AndroidConfig::waitForAvd(int apiLevel, const QString &cpuAbi, const QFutureInterface &fi) const +QString AndroidConfig::waitForAvd(const QString &avdName, const QFutureInterface &fi) const { // we cannot use adb -e wait-for-device, since that doesn't work if a emulator is already running // 60 rounds of 2s sleeping, two minutes for the avd to start @@ -829,7 +834,7 @@ QString AndroidConfig::waitForAvd(int apiLevel, const QString &cpuAbi, const QFu for (int i = 0; i < 60; ++i) { if (fi.isCanceled()) return QString(); - serialNumber = findAvd(apiLevel, cpuAbi); + serialNumber = findAvd(avdName); if (!serialNumber.isEmpty()) return waitForBooted(serialNumber, fi) ? serialNumber : QString(); Utils::sleep(2000); @@ -889,6 +894,36 @@ int AndroidConfig::getSDKVersion(const QString &adbToolPath, const QString &devi return tmp.trimmed().toInt(); } +QString AndroidConfig::getAvdName(const QString &serialnumber) +{ + int index = serialnumber.indexOf(QLatin1String("-")); + if (index == -1) + return QString(); + bool ok; + int port = serialnumber.mid(index + 1).toInt(&ok); + if (!ok) + return QString(); + + QByteArray avdName = "avd name\n"; + + QTcpSocket tcpSocket; + tcpSocket.connectToHost(QHostAddress(QHostAddress::LocalHost), port); + tcpSocket.waitForConnected(); + tcpSocket.write(avdName + "exit\n"); + tcpSocket.waitForDisconnected(); + + QByteArray response = tcpSocket.readAll(); + int start = response.indexOf("OK\r\n"); + if (start == -1) + return QString(); + start = start + 4; + + int end = response.indexOf("\r\n", start); + if (end == -1) + return QString(); + return QString::fromLatin1(response.mid(start, end - start)); +} + AndroidConfig::OpenGl AndroidConfig::getOpenGLEnabled(const QString &emulator) const { QDir dir = QDir::home(); diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 6c0a17b8eec..77c9c5a0751 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -60,6 +60,7 @@ class AndroidPlugin; struct AndroidDeviceInfo { QString serialNumber; + QString avdname; QStringList cpuAbi; int sdk; enum State { OkState, UnAuthorizedState, OfflineState }; @@ -154,10 +155,10 @@ public: QVector androidVirtualDevices() const; static QVector androidVirtualDevices(const QString &androidTool, const Utils::Environment &environment); - QString startAVD(const QString &name, int apiLevel, QString cpuAbi) const; + QString startAVD(const QString &name) const; bool startAVDAsync(const QString &avdName) const; - QString findAvd(int apiLevel, const QString &cpuAbi) const; - QString waitForAvd(int apiLevel, const QString &cpuAbi, const QFutureInterface &fi = QFutureInterface()) const; + QString findAvd(const QString &avdName) const; + QString waitForAvd(const QString &avdName, const QFutureInterface &fi = QFutureInterface()) const; QString bestNdkPlatformMatch(int target) const; static ProjectExplorer::Abi abiForToolChainPrefix(const QString &toolchainPrefix); @@ -185,6 +186,7 @@ private: static QStringList getAbis(const QString &adbToolPath, const QString &device); static bool isBootToQt(const QString &adbToolPath, const QString &device); bool isBootToQt(const QString &device) const; + static QString getAvdName(const QString &serialnumber); void updateAvailableSdkPlatforms() const; void updateNdkInformation() const; diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 7d05e3e4737..41534e30b91 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -191,22 +191,17 @@ bool AndroidDeployQtStep::init() return false; } - m_deviceAPILevel = AndroidManager::minimumSDK(target()); + int deviceAPILevel = AndroidManager::minimumSDK(target()); AndroidConfigurations::Options options = AndroidConfigurations::None; if (androidBuildApkStep->deployAction() == AndroidBuildApkStep::DebugDeployment) options = AndroidConfigurations::FilterAndroid5; - AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(project(), m_deviceAPILevel, m_targetArch, options); - if (info.serialNumber.isEmpty()) // aborted + AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(project(), deviceAPILevel, m_targetArch, options); + if (info.serialNumber.isEmpty() && info.avdname.isEmpty()) // aborted return false; - if (info.type == AndroidDeviceInfo::Emulator) { - m_avdName = info.serialNumber; - m_serialNumber.clear(); - m_deviceAPILevel = info.sdk; - } else { - m_avdName.clear(); - m_serialNumber = info.serialNumber; - } + m_avdName = info.avdname; + m_serialNumber = info.serialNumber; + AndroidManager::setDeviceSerialNumber(target(), m_serialNumber); ProjectExplorer::BuildConfiguration *bc = target()->activeBuildConfiguration(); @@ -278,7 +273,7 @@ bool AndroidDeployQtStep::init() m_adbPath = AndroidConfigurations::currentConfig().adbToolPath().toString(); - if (AndroidConfigurations::currentConfig().findAvd(m_deviceAPILevel, m_targetArch).isEmpty()) + if (AndroidConfigurations::currentConfig().findAvd(m_avdName).isEmpty()) AndroidConfigurations::currentConfig().startAVDAsync(m_avdName); return true; } @@ -400,7 +395,7 @@ void AndroidDeployQtStep::slotSetSerialNumber(const QString &serialNumber) void AndroidDeployQtStep::run(QFutureInterface &fi) { if (!m_avdName.isEmpty()) { - QString serialNumber = AndroidConfigurations::currentConfig().waitForAvd(m_deviceAPILevel, m_targetArch, fi); + QString serialNumber = AndroidConfigurations::currentConfig().waitForAvd(m_avdName, fi); if (serialNumber.isEmpty()) { fi.reportResult(false); emit finished(); diff --git a/src/plugins/android/androiddeployqtstep.h b/src/plugins/android/androiddeployqtstep.h index 380f8df7ed5..3b846f07c31 100644 --- a/src/plugins/android/androiddeployqtstep.h +++ b/src/plugins/android/androiddeployqtstep.h @@ -129,7 +129,6 @@ private: QString m_apkPath; QString m_targetArch; - int m_deviceAPILevel; bool m_uninstallPreviousPackage; bool m_uninstallPreviousPackageRun; static const Core::Id Id; diff --git a/src/plugins/android/androiddevicedialog.cpp b/src/plugins/android/androiddevicedialog.cpp index 53e31040501..d9f2a2155e4 100644 --- a/src/plugins/android/androiddevicedialog.cpp +++ b/src/plugins/android/androiddevicedialog.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -167,9 +168,11 @@ public: QFontMetrics fm(opt.font); // TopLeft - QString topLeft = device.serialNumber; + QString topLeft; if (device.type == AndroidDeviceInfo::Hardware) topLeft = AndroidConfigurations::currentConfig().getProductModel(device.serialNumber); + else + topLeft = device.avdname; painter->drawText(size + 12, 2 + opt.rect.top() + fm.ascent(), topLeft); @@ -181,7 +184,7 @@ public: if (device.type == AndroidDeviceInfo::Hardware) { drawTopRight(device.serialNumber, fm); } else { - AndroidConfig::OpenGl openGl = AndroidConfigurations::currentConfig().getOpenGLEnabled(device.serialNumber); + AndroidConfig::OpenGl openGl = AndroidConfigurations::currentConfig().getOpenGLEnabled(device.avdname); if (openGl == AndroidConfig::OpenGl::Enabled) { drawTopRight(tr("OpenGL enabled"), fm); } else if (openGl == AndroidConfig::OpenGl::Disabled) { @@ -249,7 +252,7 @@ public: AndroidDeviceInfo device(QModelIndex index); void setDevices(const QVector &devices); - QModelIndex indexFor(const QString &serial); + QModelIndex indexFor(AndroidDeviceInfo::AndroidDeviceType type, const QString &serial); private: int m_apiLevel; QString m_abi; @@ -385,12 +388,16 @@ void AndroidDeviceModel::setDevices(const QVector &devices) endResetModel(); } -QModelIndex AndroidDeviceModel::indexFor(const QString &serial) +QModelIndex AndroidDeviceModel::indexFor(AndroidDeviceInfo::AndroidDeviceType type, const QString &serial) { foreach (AndroidDeviceModelNode *topLevelNode, m_root->children()) { QList deviceNodes = topLevelNode->children(); for (int i = 0; i < deviceNodes.size(); ++i) { - if (deviceNodes.at(i)->deviceInfo().serialNumber == serial) + const AndroidDeviceInfo &info = deviceNodes.at(i)->deviceInfo(); + if (info.type != type) + continue; + if ((type == AndroidDeviceInfo::Hardware && serial == info.serialNumber) + || (type == AndroidDeviceInfo::Emulator && serial == info.avdname)) return createIndex(i, 0, deviceNodes.at(i)); } } @@ -498,12 +505,16 @@ QVector AndroidDeviceDialog::refreshDevices(const QString &ad const QString &androidToolPath, const Utils::Environment &environment) { - QVector devices; - foreach (const AndroidDeviceInfo &info, AndroidConfig::connectedDevices(adbToolPath)) - if (info.type == AndroidDeviceInfo::Hardware) - devices << info; + QVector devices = AndroidConfig::connectedDevices(adbToolPath); - devices += AndroidConfig::androidVirtualDevices(androidToolPath, environment); + QSet startedAvds = Utils::transform(devices, + [] (const AndroidDeviceInfo &info) { + return info.avdname; + }); + + for (const AndroidDeviceInfo &dev : AndroidConfig::androidVirtualDevices(androidToolPath, environment)) + if (!startedAvds.contains(dev.avdname)) + devices << dev; return devices; } @@ -511,13 +522,18 @@ void AndroidDeviceDialog::devicesRefreshed() { m_progressIndicator->hide(); QString serialNumber; - if (!m_serialNumberFromAdd.isEmpty()) { - serialNumber = m_serialNumberFromAdd; - m_serialNumberFromAdd.clear(); + AndroidDeviceInfo::AndroidDeviceType deviceType; + if (!m_avdNameFromAdd.isEmpty()) { + serialNumber = m_avdNameFromAdd; + m_avdNameFromAdd.clear(); + deviceType = AndroidDeviceInfo::Emulator; } else { QModelIndex currentIndex = m_ui->deviceView->currentIndex(); - if (currentIndex.isValid()) - serialNumber = m_model->device(currentIndex).serialNumber; + if (currentIndex.isValid()) { + AndroidDeviceInfo info = m_model->device(currentIndex); + deviceType = info.type; + serialNumber = deviceType == AndroidDeviceInfo::Hardware ? info.serialNumber : info.avdname; + } } QVector devices = m_futureWatcherRefreshDevices.result(); @@ -530,10 +546,13 @@ void AndroidDeviceDialog::devicesRefreshed() // Smartly select a index QModelIndex newIndex; if (!serialNumber.isEmpty()) - newIndex = m_model->indexFor(serialNumber); + newIndex = m_model->indexFor(deviceType, serialNumber); - if (!newIndex.isValid() && !devices.isEmpty()) - newIndex = m_model->indexFor(devices.first().serialNumber); + if (!newIndex.isValid() && !devices.isEmpty()) { + AndroidDeviceInfo info = devices.first(); + const QString &name = info.type == AndroidDeviceInfo::Hardware ? info.serialNumber : info.avdname; + newIndex = m_model->indexFor(info.type, name); + } m_ui->deviceView->setCurrentIndex(newIndex); @@ -564,14 +583,14 @@ void AndroidDeviceDialog::avdAdded() return; } - m_serialNumberFromAdd = info.name; + m_avdNameFromAdd = info.name; refreshDeviceList(); } void AndroidDeviceDialog::enableOkayButton() { AndroidDeviceModelNode *node = static_cast(m_ui->deviceView->currentIndex().internalPointer()); - bool enable = node && !node->deviceInfo().serialNumber.isEmpty(); + bool enable = node && (!node->deviceInfo().serialNumber.isEmpty() || !node->deviceInfo().avdname.isEmpty()); m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enable); } diff --git a/src/plugins/android/androiddevicedialog.h b/src/plugins/android/androiddevicedialog.h index 127295d5d4d..51e18959302 100644 --- a/src/plugins/android/androiddevicedialog.h +++ b/src/plugins/android/androiddevicedialog.h @@ -80,7 +80,7 @@ private: Utils::ProgressIndicator *m_progressIndicator; int m_apiLevel; QString m_abi; - QString m_serialNumberFromAdd; + QString m_avdNameFromAdd; QFutureWatcher m_futureWatcherAddDevice; QFutureWatcher> m_futureWatcherRefreshDevices; }; diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index ab071b70894..d0a228f6963 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -493,14 +493,14 @@ void AndroidManager::cleanLibsOnDevice(ProjectExplorer::Target *target) return; int deviceAPILevel = AndroidManager::minimumSDK(target); AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(target->project(), deviceAPILevel, targetArch, AndroidConfigurations::None); - if (info.serialNumber.isEmpty()) // aborted + if (info.serialNumber.isEmpty() && info.avdname.isEmpty()) // aborted return; deviceAPILevel = info.sdk; QString deviceSerialNumber = info.serialNumber; if (info.type == AndroidDeviceInfo::Emulator) { - deviceSerialNumber = AndroidConfigurations::currentConfig().startAVD(deviceSerialNumber, deviceAPILevel, targetArch); + deviceSerialNumber = AndroidConfigurations::currentConfig().startAVD(info.avdname); if (deviceSerialNumber.isEmpty()) Core::MessageManager::write(tr("Starting Android virtual device failed.")); } @@ -523,13 +523,13 @@ void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const Q return; int deviceAPILevel = AndroidManager::minimumSDK(target); AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(target->project(), deviceAPILevel, targetArch, AndroidConfigurations::None); - if (info.serialNumber.isEmpty()) // aborted + if (info.serialNumber.isEmpty() && info.avdname.isEmpty()) // aborted return; deviceAPILevel = info.sdk; QString deviceSerialNumber = info.serialNumber; if (info.type == AndroidDeviceInfo::Emulator) { - deviceSerialNumber = AndroidConfigurations::currentConfig().startAVD(deviceSerialNumber, deviceAPILevel, targetArch); + deviceSerialNumber = AndroidConfigurations::currentConfig().startAVD(info.avdname); if (deviceSerialNumber.isEmpty()) Core::MessageManager::write(tr("Starting Android virtual device failed.")); } diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index f8748be2294..2cae8dc2c15 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -79,7 +79,7 @@ QModelIndex AvdModel::indexForAvdName(const QString &avdName) const QString AvdModel::avdName(const QModelIndex &index) const { - return m_list.at(index.row()).serialNumber; + return m_list.at(index.row()).avdname; } QVariant AvdModel::data(const QModelIndex &index, int role) const @@ -88,7 +88,7 @@ QVariant AvdModel::data(const QModelIndex &index, int role) const return QVariant(); switch (index.column()) { case 0: - return m_list[index.row()].serialNumber; + return m_list[index.row()].avdname; case 1: return QString::fromLatin1("API %1").arg(m_list[index.row()].sdk); case 2: {