diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index ffcd74b2be1..fb614130d7f 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -975,52 +975,65 @@ void updateAvdList() s_instance->m_avdListRunner.start(s_instance->m_avdListRecipe); } -Result createAvd(const CreateAvdInfo &info, bool force) +Group createAvdRecipe(const Storage> &errorStorage, + const CreateAvdInfo &info, bool force) { - CommandLine cmd(AndroidConfig::avdManagerToolPath(), {"create", "avd", "-n", info.name}); - cmd.addArgs({"-k", info.sdkStylePath}); - if (info.sdcardSize > 0) - cmd.addArgs({"-c", QString("%1M").arg(info.sdcardSize)}); + struct GuardWrapper { + GuardLocker locker = GuardLocker(s_instance->m_avdPathGuard); + QByteArray buffer; + }; - const QString deviceDef = info.deviceDefinition; - if (!deviceDef.isEmpty() && deviceDef != "Custom") - cmd.addArgs({"-d", deviceDef}); + const Storage storage; - if (force) - cmd.addArg("-f"); + const auto onSetup = [storage, info, force](Process &process) { + CommandLine cmd(AndroidConfig::avdManagerToolPath(), {"create", "avd", "-n", info.name}); + cmd.addArgs({"-k", info.sdkStylePath}); + if (info.sdcardSize > 0) + cmd.addArgs({"-c", QString("%1M").arg(info.sdcardSize)}); - Process process; - process.setProcessMode(ProcessMode::Writer); - process.setEnvironment(AndroidConfig::toolsEnvironment()); - process.setCommand(cmd); - process.setWriteData("yes\n"); // yes to "Do you wish to create a custom hardware profile" + const QString deviceDef = info.deviceDefinition; + if (!deviceDef.isEmpty() && deviceDef != "Custom") + cmd.addArgs({"-d", deviceDef}); - QByteArray buffer; - QObject::connect(&process, &Process::readyReadStandardOutput, &process, [&process, &buffer] { - // This interaction is needed only if there is no "-d" arg for the avdmanager command. - buffer += process.readAllRawStandardOutput(); - if (buffer.endsWith(QByteArray("]:"))) { - // truncate to last line - const int index = buffer.lastIndexOf('\n'); - if (index != -1) - buffer = buffer.mid(index); - if (buffer.contains("hw.gpu.enabled")) - process.write("yes\n"); - else - process.write("\n"); - buffer.clear(); - } - }); + if (force) + cmd.addArg("-f"); - GuardLocker locker(s_instance->m_avdPathGuard); - process.runBlocking(); - if (process.result() != ProcessResult::FinishedWithSuccess) { + process.setProcessMode(ProcessMode::Writer); + process.setEnvironment(AndroidConfig::toolsEnvironment()); + process.setCommand(cmd); + process.setWriteData("yes\n"); // yes to "Do you wish to create a custom hardware profile" + + QByteArray *buffer = &storage->buffer; + Process *processPtr = &process; + + QObject::connect(processPtr, &Process::readyReadStandardOutput, processPtr, [processPtr, buffer] { + // This interaction is needed only if there is no "-d" arg for the avdmanager command. + *buffer += processPtr->readAllRawStandardOutput(); + if (buffer->endsWith(QByteArray("]:"))) { + // truncate to last line + const int index = buffer->lastIndexOf('\n'); + if (index != -1) + *buffer = buffer->mid(index); + if (buffer->contains("hw.gpu.enabled")) + processPtr->write("yes\n"); + else + processPtr->write("\n"); + buffer->clear(); + } + }); + }; + + const auto onDone = [errorStorage](const Process &process) { const QString stdErr = process.stdErr(); const QString errorMessage = stdErr.isEmpty() ? process.exitMessage() : process.exitMessage() + "\n\n" + stdErr; - return Result::Error(errorMessage); - } - return Result::Ok; + *errorStorage = errorMessage; + }; + + return { + storage, + ProcessTask(onSetup, onDone, CallDoneIf::Error) + }; } // Factory diff --git a/src/plugins/android/androiddevice.h b/src/plugins/android/androiddevice.h index 7896fbc9705..c262bf1aa67 100644 --- a/src/plugins/android/androiddevice.h +++ b/src/plugins/android/androiddevice.h @@ -70,7 +70,8 @@ private: void setupDevicesWatcher(); void updateAvdList(); -Utils::Result createAvd(const CreateAvdInfo &info, bool force); +Tasking::Group createAvdRecipe(const Tasking::Storage> &errorStorage, + const CreateAvdInfo &info, bool force); void setupAndroidDevice(); void setupAndroidDeviceManager(QObject *guard); diff --git a/src/plugins/android/avddialog.cpp b/src/plugins/android/avddialog.cpp index 3743715f568..052cef35368 100644 --- a/src/plugins/android/avddialog.cpp +++ b/src/plugins/android/avddialog.cpp @@ -26,12 +26,14 @@ #include #include #include +#include #include #include #include #include using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; namespace Android::Internal { @@ -114,7 +116,7 @@ AvdDialog::AvdDialog(QWidget *parent) this, &AvdDialog::updateDeviceDefinitionComboBox); connect(m_abiComboBox, &QComboBox::currentIndexChanged, this, &AvdDialog::updateApiLevelComboBox); - connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(m_buttonBox, &QDialogButtonBox::accepted, this, &AvdDialog::createAvd); connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); m_deviceTypeToStringMap.insert(AvdDialog::Phone, "Phone"); @@ -131,31 +133,6 @@ AvdDialog::AvdDialog(QWidget *parent) updateApiLevelComboBox(); } -int AvdDialog::exec() -{ - const int execResult = QDialog::exec(); - if (execResult == QDialog::Accepted) { - const SystemImage *si = systemImage(); - if (!si || !si->isValid() || name().isEmpty()) { - QMessageBox::warning(Core::ICore::dialogParent(), - Tr::tr("Create new AVD"), Tr::tr("Cannot create AVD. Invalid input.")); - return QDialog::Rejected; - } - - const CreateAvdInfo avdInfo{si->sdkStylePath(), si->apiLevel(), name(), abi(), - deviceDefinition(), sdcardSize()}; - const Result result = createAvd(avdInfo, m_overwriteCheckBox->isChecked()); - if (!result) { - QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Create new AVD"), - result.error()); - return QDialog::Rejected; - } - m_createdAvdInfo = avdInfo; - updateAvdList(); - } - return execResult; -} - bool AvdDialog::isValid() const { return !name().isEmpty() && systemImage() && systemImage()->isValid() && !abi().isEmpty(); @@ -179,6 +156,63 @@ AvdDialog::DeviceType AvdDialog::tagToDeviceType(const QString &type_tag) return AvdDialog::PhoneOrTablet; } +void AvdDialog::createAvd() +{ + const SystemImage *si = systemImage(); + if (!si || !si->isValid() || name().isEmpty()) { + QMessageBox::warning(Core::ICore::dialogParent(), + Tr::tr("Create new AVD"), Tr::tr("Cannot create AVD. Invalid input.")); + return; + } + const CreateAvdInfo avdInfo{si->sdkStylePath(), si->apiLevel(), name(), abi(), + deviceDefinition(), sdcardSize()}; + + struct Progress { + Progress() { + progressDialog.reset(new QProgressDialog(Core::ICore::dialogParent())); + progressDialog->setRange(0, 0); + progressDialog->setWindowModality(Qt::ApplicationModal); + progressDialog->setWindowTitle("Create new AVD"); + progressDialog->setLabelText(Tr::tr("Creating new AVD device...")); + progressDialog->setFixedSize(progressDialog->sizeHint()); + progressDialog->setAutoClose(false); + progressDialog->show(); // TODO: Should not be needed. Investigate possible QT_BUG + } + std::unique_ptr progressDialog; + }; + + const Storage progressStorage; + + const auto onCancelSetup = [progressStorage] { + return std::make_pair(progressStorage->progressDialog.get(), &QProgressDialog::canceled); + }; + + const Storage> errorStorage; + + const auto onDone = [errorStorage] { + if (errorStorage->has_value()) { + QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Create new AVD"), + errorStorage->value()); + } + }; + + const Group recipe { + progressStorage, + errorStorage, + createAvdRecipe(errorStorage, avdInfo, m_overwriteCheckBox->isChecked()) + .withCancel(onCancelSetup), + onGroupDone(onDone, CallDoneIf::Error) + }; + + m_taskTreeRunner.start(recipe, {}, [this, avdInfo](DoneWith result) { + if (result == DoneWith::Error) + return; + m_createdAvdInfo = avdInfo; + updateAvdList(); + accept(); + }); +} + static bool avdManagerCommand(const QStringList &args, QString *output) { CommandLine cmd(AndroidConfig::avdManagerToolPath(), args); diff --git a/src/plugins/android/avddialog.h b/src/plugins/android/avddialog.h index 550a04a158e..efbabf81c53 100644 --- a/src/plugins/android/avddialog.h +++ b/src/plugins/android/avddialog.h @@ -5,6 +5,8 @@ #include "androidconfigurations.h" +#include + #include #include #include @@ -30,7 +32,6 @@ class AvdDialog : public QDialog { public: explicit AvdDialog(QWidget *parent = nullptr); - int exec() override; CreateAvdInfo avdInfo() const; private: @@ -50,6 +51,8 @@ private: static AvdDialog::DeviceType tagToDeviceType(const QString &type_tag); + void createAvd(); + struct DeviceDefinitionStruct { QString name_id; @@ -72,6 +75,7 @@ private: QComboBox *m_deviceDefinitionTypeComboBox; QCheckBox *m_overwriteCheckBox; QDialogButtonBox *m_buttonBox; + Tasking::TaskTreeRunner m_taskTreeRunner; }; } // Internal