diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 4709c55e8e4..5268fe66946 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -61,6 +61,7 @@ #include #include #include +#include #include #include @@ -501,34 +502,41 @@ QVector AndroidConfig::connectedDevices(QString *error) const return devices; } -QString AndroidConfig::createAVD(QWidget *parent, int minApiLevel, QString targetArch) const +AndroidConfig::CreateAvdInfo AndroidConfig::gatherCreateAVDInfo(QWidget *parent, int minApiLevel, QString targetArch) const { + CreateAvdInfo result; AvdDialog d(minApiLevel, targetArch, this, parent); if (d.exec() != QDialog::Accepted || !d.isValid()) - return QString(); - QString error; - QString avd = createAVD(d.target(), d.name(), d.abi(), d.sdcardSize(), &error); + return result; - if (!error.isEmpty()) { - QMessageBox::critical(parent, QApplication::translate("AndroidConfig", "Error Creating AVD"), - error); - } - - return avd; + result.target = d.target(); + result.name = d.name(); + result.abi = d.abi(); + result.sdcardSize = d.sdcardSize(); + return result; } -QString AndroidConfig::createAVD(const QString &target, const QString &name, const QString &abi, int sdcardSize, QString *error) const +QFuture AndroidConfig::createAVD(CreateAvdInfo info) const +{ + return QtConcurrent::run(&AndroidConfig::createAVDImpl, info, androidToolPath(), androidToolEnvironment()); +} + +AndroidConfig::CreateAvdInfo AndroidConfig::createAVDImpl(CreateAvdInfo info, Utils::FileName androidToolPath, Utils::Environment env) { QProcess proc; - proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment()); - proc.start(androidToolPath().toString(), - QStringList() << QLatin1String("create") << QLatin1String("avd") - << QLatin1String("-t") << target - << QLatin1String("-n") << name - << QLatin1String("-b") << abi - << QLatin1String("-c") << QString::fromLatin1("%1M").arg(sdcardSize)); - if (!proc.waitForStarted()) - return QString(); + proc.setProcessEnvironment(env.toProcessEnvironment()); + QStringList arguments; + arguments << QLatin1String("create") << QLatin1String("avd") + << QLatin1String("-t") << info.target + << QLatin1String("-n") << info.name + << QLatin1String("-b") << info.abi + << QLatin1String("-c") << QString::fromLatin1("%1M").arg(info.sdcardSize); + proc.start(androidToolPath.toString(), arguments); + if (!proc.waitForStarted()) { + info.error = QApplication::translate("AndroidConfig", "Could not start process \"%1 %2\"") + .arg(androidToolPath.toString(), arguments.join(QLatin1String(" "))); + return info; + } proc.write(QByteArray("yes\n")); // yes to "Do you wish to create a custom hardware profile" @@ -558,11 +566,10 @@ QString AndroidConfig::createAVD(const QString &target, const QString &name, con // The exit code is always 0, so we need to check stderr // For now assume that any output at all indicates a error if (!errorOutput.isEmpty()) { - *error = errorOutput; - return QString(); + info.error = errorOutput; } - return name; + return info; } bool AndroidConfig::removeAVD(const QString &name) const diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index fd35944737e..1bd49a095c6 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -127,9 +127,18 @@ public: Utils::FileName stripPath(ProjectExplorer::Abi::Architecture architecture, const QString &ndkToolChainVersion) const; Utils::FileName readelfPath(ProjectExplorer::Abi::Architecture architecture, const QString &ndkToolChainVersion) const; + class CreateAvdInfo + { + public: + QString target; + QString name; + QString abi; + int sdcardSize; + QString error; // only used in the return value of createAVD + }; - QString createAVD(QWidget *parent, int minApiLevel = 0, QString targetArch = QString()) const; - QString createAVD(const QString &target, const QString &name, const QString &abi, int sdcardSize, QString *error) const; + CreateAvdInfo gatherCreateAVDInfo(QWidget *parent, int minApiLevel = 0, QString targetArch = QString()) const; + QFuture createAVD(CreateAvdInfo info) const; bool removeAVD(const QString &name) const; QVector connectedDevices(QString *error = 0) const; @@ -151,6 +160,8 @@ public: SdkPlatform highestAndroidSdk() const; private: + static CreateAvdInfo createAVDImpl(CreateAvdInfo info, Utils::FileName androidToolPath, Utils::Environment env); + Utils::FileName toolPath(ProjectExplorer::Abi::Architecture architecture, const QString &ndkToolChainVersion) const; Utils::FileName openJDKBinPath() const; int getSDKVersion(const QString &device) const; diff --git a/src/plugins/android/androiddevicedialog.cpp b/src/plugins/android/androiddevicedialog.cpp index fef86bf4093..cf42688915e 100644 --- a/src/plugins/android/androiddevicedialog.cpp +++ b/src/plugins/android/androiddevicedialog.cpp @@ -31,9 +31,11 @@ #include "androidmanager.h" #include "ui_androiddevicedialog.h" +#include #include #include #include +#include using namespace Android; using namespace Android::Internal; @@ -413,12 +415,16 @@ AndroidDeviceDialog::AndroidDeviceDialog(int apiLevel, const QString &abi, QWidg connect(m_ui->createAVDButton, SIGNAL(clicked()), this, SLOT(createAvd())); + connect(&m_futureWatcher, SIGNAL(finished()), + this, SLOT(avdAdded())); + refreshDeviceList(); } AndroidDeviceDialog::~AndroidDeviceDialog() { delete m_ui; + m_futureWatcher.waitForFinished(); } AndroidDeviceInfo AndroidDeviceDialog::device() @@ -472,11 +478,28 @@ void AndroidDeviceDialog::refreshDeviceList() void AndroidDeviceDialog::createAvd() { - QString avd = AndroidConfigurations::currentConfig().createAVD(this, m_apiLevel, m_abi); - if (avd.isEmpty()) + m_ui->createAVDButton->setEnabled(false); + AndroidConfig::CreateAvdInfo info = AndroidConfigurations::currentConfig().gatherCreateAVDInfo(this, m_apiLevel, m_abi); + + if (info.target.isEmpty()) { + m_ui->createAVDButton->setEnabled(true); return; + } + + m_futureWatcher.setFuture(AndroidConfigurations::currentConfig().createAVD(info)); +} + +void AndroidDeviceDialog::avdAdded() +{ + m_ui->createAVDButton->setEnabled(true); + AndroidConfig::CreateAvdInfo info = m_futureWatcher.result(); + if (!info.error.isEmpty()) { + QMessageBox::critical(this, QApplication::translate("AndroidConfig", "Error Creating AVD"), info.error); + return; + } + refreshDeviceList(); - QModelIndex index = m_model->indexFor(avd); + QModelIndex index = m_model->indexFor(info.name); m_ui->deviceView->setCurrentIndex(index); } diff --git a/src/plugins/android/androiddevicedialog.h b/src/plugins/android/androiddevicedialog.h index 6cb4202ab7e..4f07b804afa 100644 --- a/src/plugins/android/androiddevicedialog.h +++ b/src/plugins/android/androiddevicedialog.h @@ -34,6 +34,7 @@ #include #include +#include QT_BEGIN_NAMESPACE class QModelIndex; @@ -63,11 +64,13 @@ private slots: void createAvd(); void clickedOnView(const QModelIndex &idx); void showHelp(); + void avdAdded(); private: AndroidDeviceModel *m_model; Ui::AndroidDeviceDialog *m_ui; int m_apiLevel; QString m_abi; + QFutureWatcher m_futureWatcher; }; } diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index e60357a37f9..5c6b6fe7512 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -53,6 +53,7 @@ #include #include #include +#include namespace Android { namespace Internal { @@ -64,6 +65,15 @@ void AvdModel::setAvdList(const QVector &list) endResetModel(); } +QModelIndex AvdModel::indexForAvdName(const QString &avdName) const +{ + for (int i = 0; i < m_list.size(); ++i) { + if (m_list.at(i).serialNumber == avdName) + return index(i, 0); + } + return QModelIndex(); +} + QString AvdModel::avdName(const QModelIndex &index) const { return m_list.at(index.row()).serialNumber; @@ -144,11 +154,15 @@ AndroidSettingsWidget::AndroidSettingsWidget(QWidget *parent) check(All); applyToUi(All); + + connect(&m_futureWatcher, SIGNAL(finished()), + this, SLOT(avdAdded())); } AndroidSettingsWidget::~AndroidSettingsWidget() { delete m_ui; + m_futureWatcher.waitForFinished(); } void AndroidSettingsWidget::check(AndroidSettingsWidget::Mode mode) @@ -468,9 +482,28 @@ void AndroidSettingsWidget::openOpenJDKDownloadUrl() void AndroidSettingsWidget::addAVD() { - m_androidConfig.createAVD(this); + m_ui->AVDAddPushButton->setEnabled(false); + AndroidConfig::CreateAvdInfo info = m_androidConfig.gatherCreateAVDInfo(this); + + if (info.target.isEmpty()) { + m_ui->AVDAddPushButton->setEnabled(true); + return; + } + + m_futureWatcher.setFuture(m_androidConfig.createAVD(info)); +} + +void AndroidSettingsWidget::avdAdded() +{ + m_ui->AVDAddPushButton->setEnabled(true); + AndroidConfig::CreateAvdInfo info = m_futureWatcher.result(); + if (!info.error.isEmpty()) { + QMessageBox::critical(this, QApplication::translate("AndroidConfig", "Error Creating AVD"), info.error); + return; + } + m_AVDModel.setAvdList(m_androidConfig.androidVirtualDevices()); - avdActivated(m_ui->AVDTableView->currentIndex()); + m_ui->AVDTableView->setCurrentIndex(m_AVDModel.indexForAvdName(info.name)); } void AndroidSettingsWidget::removeAVD() diff --git a/src/plugins/android/androidsettingswidget.h b/src/plugins/android/androidsettingswidget.h index b80fde68722..7f7dbe93fb3 100644 --- a/src/plugins/android/androidsettingswidget.h +++ b/src/plugins/android/androidsettingswidget.h @@ -36,6 +36,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE class Ui_AndroidSettingsWidget; @@ -50,6 +51,7 @@ class AvdModel: public QAbstractTableModel public: void setAvdList(const QVector &list); QString avdName(const QModelIndex &index) const; + QModelIndex indexForAvdName(const QString &avdName) const; protected: QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; @@ -86,6 +88,7 @@ private slots: void openAntDownloadUrl(); void openOpenJDKDownloadUrl(); void addAVD(); + void avdAdded(); void removeAVD(); void startAVD(); void avdActivated(QModelIndex); @@ -111,6 +114,7 @@ private: Ui_AndroidSettingsWidget *m_ui; AndroidConfig m_androidConfig; AvdModel m_AVDModel; + QFutureWatcher m_futureWatcher; }; } // namespace Internal