Commit 7a91287c authored by Daniel Teske's avatar Daniel Teske

Android: Fix blocking the ui on adding an avd

Task-number: QTCREATORBUG-10601
Change-Id: I3d1fef8a44f434f7eb484f538863c436b4e3a21c
Reviewed-by: default avatarEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
parent acfe2a27
......@@ -61,6 +61,7 @@
#include <QDirIterator>
#include <QMetaObject>
#include <QApplication>
#include <QtConcurrentRun>
#include <QStringListModel>
#include <QMessageBox>
......@@ -501,34 +502,41 @@ QVector<AndroidDeviceInfo> 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);
}
result.target = d.target();
result.name = d.name();
result.abi = d.abi();
result.sdcardSize = d.sdcardSize();
return result;
}
return avd;
QFuture<AndroidConfig::CreateAvdInfo> AndroidConfig::createAVD(CreateAvdInfo info) const
{
return QtConcurrent::run(&AndroidConfig::createAVDImpl, info, androidToolPath(), androidToolEnvironment());
}
QString AndroidConfig::createAVD(const QString &target, const QString &name, const QString &abi, int sdcardSize, QString *error) const
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
......
......@@ -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;
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;
class CreateAvdInfo
{
public:
QString target;
QString name;
QString abi;
int sdcardSize;
QString error; // only used in the return value of createAVD
};
CreateAvdInfo gatherCreateAVDInfo(QWidget *parent, int minApiLevel = 0, QString targetArch = QString()) const;
QFuture<CreateAvdInfo> createAVD(CreateAvdInfo info) const;
bool removeAVD(const QString &name) const;
QVector<AndroidDeviceInfo> 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;
......
......@@ -31,9 +31,11 @@
#include "androidmanager.h"
#include "ui_androiddevicedialog.h"
#include <QMessageBox>
#include <QPainter>
#include <QStyledItemDelegate>
#include <QToolTip>
#include <QtConcurrentRun>
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);
}
......
......@@ -34,6 +34,7 @@
#include <QVector>
#include <QDialog>
#include <QFutureWatcher>
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<AndroidConfig::CreateAvdInfo> m_futureWatcher;
};
}
......
......@@ -53,6 +53,7 @@
#include <QMessageBox>
#include <QModelIndex>
#include <QtCore/QUrl>
#include <QtConcurrentRun>
namespace Android {
namespace Internal {
......@@ -64,6 +65,15 @@ void AvdModel::setAvdList(const QVector<AndroidDeviceInfo> &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()
......
......@@ -36,6 +36,7 @@
#include <QString>
#include <QWidget>
#include <QAbstractTableModel>
#include <QFutureWatcher>
QT_BEGIN_NAMESPACE
class Ui_AndroidSettingsWidget;
......@@ -50,6 +51,7 @@ class AvdModel: public QAbstractTableModel
public:
void setAvdList(const QVector<AndroidDeviceInfo> &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<AndroidConfig::CreateAvdInfo> m_futureWatcher;
};
} // namespace Internal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment