diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 94dbbbb9e3f..e1945c594a0 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -378,12 +378,28 @@ FileName AndroidConfigurations::zipalignPath() const return path.appendPath(QLatin1String("tools/zipalign" QTC_HOST_EXE_SUFFIX)); } -QString AndroidConfigurations::getDeployDeviceSerialNumber(int *apiLevel, const QString &abi) const +QString AndroidConfigurations::getDeployDeviceSerialNumber(int *apiLevel, const QString &abi, QString *error) const { - QVector devices = connectedDevices(); + QVector devices = connectedDevices(error); foreach (AndroidDeviceInfo device, devices) { - if (device.sdk >= *apiLevel && device.cpuAbi.contains(abi)) { + if (!device.cpuAbi.contains(abi)) { + if (error) { + *error += tr("Skipping %1: ABI is incompatible, device supports ABIs: %2.") + .arg(getProductModel(device.serialNumber)) + .arg(device.cpuAbi.join(QLatin1String(" "))); + *error += QLatin1Char('\n'); + } + } else if (device.sdk < *apiLevel) { + if (error) { + *error += tr("Skipping %1: API Level of device is: %2.") + .arg(getProductModel(device.serialNumber)) + .arg(device.sdk); + *error += QLatin1Char('\n'); + } + } else { + if (error) + error->clear(); // no errors if we found a device *apiLevel = device.sdk; return device.serialNumber; } @@ -391,13 +407,15 @@ QString AndroidConfigurations::getDeployDeviceSerialNumber(int *apiLevel, const return QString(); } -QVector AndroidConfigurations::connectedDevices() const +QVector AndroidConfigurations::connectedDevices(QString *error) const { QVector devices; QProcess adbProc; adbProc.start(adbToolPath().toString(), QStringList() << QLatin1String("devices")); if (!adbProc.waitForFinished(-1)) { adbProc.kill(); + if (error) + *error = tr("Could not run: %1").arg(adbToolPath().toString() + QLatin1String(" devices")); return devices; } QList adbDevs = adbProc.readAll().trimmed().split('\n'); @@ -425,6 +443,8 @@ QVector AndroidConfigurations::connectedDevices() const devices.push_back(dev); } qSort(devices.begin(), devices.end(), androidDevicesLessThan); + if (devices.isEmpty() && error) + *error = tr("No devices found in output of: %1").arg(adbToolPath().toString() + QLatin1String(" devices")); return devices; } @@ -603,6 +623,30 @@ int AndroidConfigurations::getSDKVersion(const QString &device) const return adbProc.readAll().trimmed().toInt(); } +//! +//! \brief AndroidConfigurations::getProductModel +//! \param device serial number +//! \return the produce model of the device or if that cannot be read the serial number +//! +QString AndroidConfigurations::getProductModel(const QString &device) const +{ + // workaround for '????????????' serial numbers + QStringList arguments = AndroidDeviceInfo::adbSelector(device); + arguments << QLatin1String("shell") << QLatin1String("getprop") + << QLatin1String("ro.product.model"); + + QProcess adbProc; + adbProc.start(adbToolPath().toString(), arguments); + if (!adbProc.waitForFinished(-1)) { + adbProc.kill(); + return device; + } + QString model = QString::fromLocal8Bit(adbProc.readAll().trimmed()); + if (model.isEmpty()) + return device; + return model; +} + QStringList AndroidConfigurations::getAbis(const QString &device) const { QStringList result; diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 0fae8c711a4..0531e323ab1 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -92,10 +92,10 @@ public: Utils::FileName zipalignPath() const; Utils::FileName stripPath(ProjectExplorer::Abi::Architecture architecture, const QString &ndkToolChainVersion) const; Utils::FileName readelfPath(ProjectExplorer::Abi::Architecture architecture, const QString &ndkToolChainVersion) const; - QString getDeployDeviceSerialNumber(int *apiLevel, const QString &abi) const; + QString getDeployDeviceSerialNumber(int *apiLevel, const QString &abi, QString *error = 0) const; bool createAVD(const QString &target, const QString &name, int sdcardSize) const; bool removeAVD(const QString &name) const; - QVector connectedDevices() const; + QVector connectedDevices(QString *error = 0) const; QVector androidVirtualDevices() const; QString startAVD(int *apiLevel, const QString &name = QString()) const; QString bestMatch(const QString &targetAPI) const; @@ -109,6 +109,8 @@ public: // called from AndroidPlugin void updateAndroidDevice(); + QString getProductModel(const QString &device) const; + signals: void updated(); diff --git a/src/plugins/android/androiddeploystep.cpp b/src/plugins/android/androiddeploystep.cpp index 76f1975c92e..e3d50641e1e 100644 --- a/src/plugins/android/androiddeploystep.cpp +++ b/src/plugins/android/androiddeploystep.cpp @@ -99,11 +99,18 @@ bool AndroidDeployStep::init() const QString targetSDK = AndroidManager::targetSDK(target()); const QString targetArch = AndroidManager::targetArch(target()); - writeOutput(tr("Please wait, searching for a suitable device for target:%1.").arg(targetSDK)); + writeOutput(tr("Please wait, searching for a suitable device for target:%1, ABI:%2").arg(targetSDK).arg(targetArch)); m_deviceAPILevel = targetSDK.mid(targetSDK.indexOf(QLatin1Char('-')) + 1).toInt(); - m_deviceSerialNumber = AndroidConfigurations::instance().getDeployDeviceSerialNumber(&m_deviceAPILevel, targetArch); - if (m_deviceSerialNumber.isEmpty()) + QString error; + m_deviceSerialNumber = AndroidConfigurations::instance().getDeployDeviceSerialNumber(&m_deviceAPILevel, targetArch, &error); + if (!error.isEmpty()) + writeOutput(error); + + if (m_deviceSerialNumber.isEmpty()) { + writeOutput(tr("Falling back to android virtual machine device.")); m_deviceSerialNumber = AndroidConfigurations::instance().startAVD(&m_deviceAPILevel); + } + if (!m_deviceSerialNumber.length()) { m_deviceSerialNumber.clear(); raiseError(tr("Cannot deploy: no devices or emulators found for your package."));