forked from qt-creator/qt-creator
Android: Collect initial data inside AvdDialog asynchronously
Disable all GUI controls but cancel button and execute the list command asynchronously. Show a spinner during process execution. Re-enable GUI controls on successful execution. Show message box on failure and reject the AvdDialog. Change-Id: Idf3c5fc2f6d16f752999368bdecab24edfc51915 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include <projectexplorer/projectexplorerconstants.h>
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
|
|
||||||
|
#include <solutions/spinner/spinner.h>
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/infolabel.h>
|
#include <utils/infolabel.h>
|
||||||
#include <utils/layoutbuilder.h>
|
#include <utils/layoutbuilder.h>
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
#include <QSysInfo>
|
#include <QSysInfo>
|
||||||
|
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
|
using namespace SpinnerSolution;
|
||||||
using namespace Tasking;
|
using namespace Tasking;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
@@ -96,8 +99,10 @@ AvdDialog::AvdDialog(QWidget *parent)
|
|||||||
|
|
||||||
using namespace Layouting;
|
using namespace Layouting;
|
||||||
|
|
||||||
|
m_gui = new QWidget;
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Form {
|
m_gui = Form {
|
||||||
Tr::tr("Name:"), m_nameLineEdit, br,
|
Tr::tr("Name:"), m_nameLineEdit, br,
|
||||||
Tr::tr("Target ABI / API:"),
|
Tr::tr("Target ABI / API:"),
|
||||||
Row { m_abiComboBox, m_targetApiComboBox }, br,
|
Row { m_abiComboBox, m_targetApiComboBox }, br,
|
||||||
@@ -106,7 +111,8 @@ AvdDialog::AvdDialog(QWidget *parent)
|
|||||||
Row { m_deviceDefinitionTypeComboBox, m_deviceDefinitionComboBox }, br,
|
Row { m_deviceDefinitionTypeComboBox, m_deviceDefinitionComboBox }, br,
|
||||||
Tr::tr("SD card size:"), m_sdcardSizeSpinBox, br,
|
Tr::tr("SD card size:"), m_sdcardSizeSpinBox, br,
|
||||||
QString(), m_overwriteCheckBox,
|
QString(), m_overwriteCheckBox,
|
||||||
},
|
noMargin
|
||||||
|
}.emerge(),
|
||||||
st,
|
st,
|
||||||
m_buttonBox
|
m_buttonBox
|
||||||
}.attachTo(this);
|
}.attachTo(this);
|
||||||
@@ -126,11 +132,7 @@ AvdDialog::AvdDialog(QWidget *parent)
|
|||||||
m_deviceTypeToStringMap.insert(AvdDialog::Wear, "Wear");
|
m_deviceTypeToStringMap.insert(AvdDialog::Wear, "Wear");
|
||||||
m_deviceTypeToStringMap.insert(AvdDialog::Desktop, "Desktop");
|
m_deviceTypeToStringMap.insert(AvdDialog::Desktop, "Desktop");
|
||||||
|
|
||||||
parseDeviceDefinitionsList();
|
collectInitialData();
|
||||||
for (const QString &type : m_deviceTypeToStringMap)
|
|
||||||
m_deviceDefinitionTypeComboBox->addItem(type);
|
|
||||||
|
|
||||||
updateApiLevelComboBox();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AvdDialog::isValid() const
|
bool AvdDialog::isValid() const
|
||||||
@@ -156,6 +158,106 @@ AvdDialog::DeviceType AvdDialog::tagToDeviceType(const QString &type_tag)
|
|||||||
return AvdDialog::PhoneOrTablet;
|
return AvdDialog::PhoneOrTablet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AvdDialog::collectInitialData()
|
||||||
|
{
|
||||||
|
const auto onProcessSetup = [this](Process &process) {
|
||||||
|
m_gui->setEnabled(false);
|
||||||
|
m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||||
|
const CommandLine cmd(AndroidConfig::avdManagerToolPath(), {"list", "device"});
|
||||||
|
qCDebug(avdDialogLog).noquote() << "Running AVD Manager command:" << cmd.toUserOutput();
|
||||||
|
process.setEnvironment(AndroidConfig::toolsEnvironment());
|
||||||
|
process.setCommand(cmd);
|
||||||
|
};
|
||||||
|
const auto onProcessDone = [this](const Process &process, DoneWith result) {
|
||||||
|
const QString output = process.allOutput();
|
||||||
|
if (result == DoneWith::Error) {
|
||||||
|
QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Create new AVD"),
|
||||||
|
Tr::tr("Avd list command failed. %1 %2")
|
||||||
|
.arg(output).arg(AndroidConfig::sdkToolsVersion().toString()));
|
||||||
|
reject();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Example output:
|
||||||
|
|
||||||
|
Available devices definitions:
|
||||||
|
id: 0 or "automotive_1024p_landscape"
|
||||||
|
Name: Automotive (1024p landscape)
|
||||||
|
OEM : Google
|
||||||
|
Tag : android-automotive-playstore
|
||||||
|
---------
|
||||||
|
id: 1 or "automotive_1080p_landscape"
|
||||||
|
Name: Automotive (1080p landscape)
|
||||||
|
OEM : Google
|
||||||
|
Tag : android-automotive
|
||||||
|
---------
|
||||||
|
id: 2 or "Galaxy Nexus"
|
||||||
|
Name: Galaxy Nexus
|
||||||
|
OEM : Google
|
||||||
|
---------
|
||||||
|
id: 3 or "desktop_large"
|
||||||
|
Name: Large Desktop
|
||||||
|
OEM : Google
|
||||||
|
Tag : android-desktop
|
||||||
|
...
|
||||||
|
*/
|
||||||
|
QStringList avdDeviceInfo;
|
||||||
|
|
||||||
|
const auto lines = output.split('\n');
|
||||||
|
for (const QString &line : lines) {
|
||||||
|
if (line.startsWith("---------") || line.isEmpty()) {
|
||||||
|
DeviceDefinitionStruct deviceDefinition;
|
||||||
|
for (const QString &line : avdDeviceInfo) {
|
||||||
|
if (line.contains("id:")) {
|
||||||
|
deviceDefinition.name_id = line.split("or").at(1);
|
||||||
|
deviceDefinition.name_id = deviceDefinition.name_id.remove(0, 1).remove('"');
|
||||||
|
} else if (line.contains("Tag :")) {
|
||||||
|
deviceDefinition.type_str = line.split(':').at(1);
|
||||||
|
deviceDefinition.type_str = deviceDefinition.type_str.remove(0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceType deviceType = tagToDeviceType(deviceDefinition.type_str);
|
||||||
|
if (deviceType == PhoneOrTablet) {
|
||||||
|
if (deviceDefinition.name_id.contains("Tablet"))
|
||||||
|
deviceType = Tablet;
|
||||||
|
else
|
||||||
|
deviceType = Phone;
|
||||||
|
}
|
||||||
|
deviceDefinition.deviceType = deviceType;
|
||||||
|
m_deviceDefinitionsList.append(deviceDefinition);
|
||||||
|
avdDeviceInfo.clear();
|
||||||
|
} else {
|
||||||
|
avdDeviceInfo << line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const QString &type : m_deviceTypeToStringMap)
|
||||||
|
m_deviceDefinitionTypeComboBox->addItem(type);
|
||||||
|
|
||||||
|
updateApiLevelComboBox();
|
||||||
|
m_gui->setEnabled(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SpinnerStruct {
|
||||||
|
std::unique_ptr<Spinner> spinner;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Storage<SpinnerStruct> storage;
|
||||||
|
|
||||||
|
const auto onSetup = [this, storage] {
|
||||||
|
storage->spinner.reset(new Spinner(SpinnerSize::Medium, m_gui));
|
||||||
|
storage->spinner->show();
|
||||||
|
};
|
||||||
|
|
||||||
|
const Group recipe {
|
||||||
|
storage,
|
||||||
|
onGroupSetup(onSetup),
|
||||||
|
ProcessTask(onProcessSetup, onProcessDone)
|
||||||
|
};
|
||||||
|
|
||||||
|
m_taskTreeRunner.start(recipe);
|
||||||
|
}
|
||||||
|
|
||||||
void AvdDialog::createAvd()
|
void AvdDialog::createAvd()
|
||||||
{
|
{
|
||||||
const SystemImage *si = systemImage();
|
const SystemImage *si = systemImage();
|
||||||
@@ -213,87 +315,6 @@ void AvdDialog::createAvd()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool avdManagerCommand(const QStringList &args, QString *output)
|
|
||||||
{
|
|
||||||
CommandLine cmd(AndroidConfig::avdManagerToolPath(), args);
|
|
||||||
Process proc;
|
|
||||||
proc.setEnvironment(AndroidConfig::toolsEnvironment());
|
|
||||||
qCDebug(avdDialogLog).noquote() << "Running AVD Manager command:" << cmd.toUserOutput();
|
|
||||||
proc.setCommand(cmd);
|
|
||||||
proc.runBlocking();
|
|
||||||
if (proc.result() == ProcessResult::FinishedWithSuccess) {
|
|
||||||
if (output)
|
|
||||||
*output = proc.allOutput();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AvdDialog::parseDeviceDefinitionsList()
|
|
||||||
{
|
|
||||||
QString output;
|
|
||||||
|
|
||||||
if (!avdManagerCommand({"list", "device"}, &output)) {
|
|
||||||
qCDebug(avdDialogLog) << "Avd list command failed" << output
|
|
||||||
<< AndroidConfig::sdkToolsVersion();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Example output:
|
|
||||||
Available devices definitions:
|
|
||||||
id: 0 or "automotive_1024p_landscape"
|
|
||||||
Name: Automotive (1024p landscape)
|
|
||||||
OEM : Google
|
|
||||||
Tag : android-automotive-playstore
|
|
||||||
---------
|
|
||||||
id: 1 or "automotive_1080p_landscape"
|
|
||||||
Name: Automotive (1080p landscape)
|
|
||||||
OEM : Google
|
|
||||||
Tag : android-automotive
|
|
||||||
---------
|
|
||||||
id: 2 or "Galaxy Nexus"
|
|
||||||
Name: Galaxy Nexus
|
|
||||||
OEM : Google
|
|
||||||
---------
|
|
||||||
id: 3 or "desktop_large"
|
|
||||||
Name: Large Desktop
|
|
||||||
OEM : Google
|
|
||||||
Tag : android-desktop
|
|
||||||
...
|
|
||||||
*/
|
|
||||||
|
|
||||||
QStringList avdDeviceInfo;
|
|
||||||
|
|
||||||
const auto lines = output.split('\n');
|
|
||||||
for (const QString &line : lines) {
|
|
||||||
if (line.startsWith("---------") || line.isEmpty()) {
|
|
||||||
DeviceDefinitionStruct deviceDefinition;
|
|
||||||
for (const QString &line : avdDeviceInfo) {
|
|
||||||
if (line.contains("id:")) {
|
|
||||||
deviceDefinition.name_id = line.split("or").at(1);
|
|
||||||
deviceDefinition.name_id = deviceDefinition.name_id.remove(0, 1).remove('"');
|
|
||||||
} else if (line.contains("Tag :")) {
|
|
||||||
deviceDefinition.type_str = line.split(':').at(1);
|
|
||||||
deviceDefinition.type_str = deviceDefinition.type_str.remove(0, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceType deviceType = tagToDeviceType(deviceDefinition.type_str);
|
|
||||||
if (deviceType == PhoneOrTablet) {
|
|
||||||
if (deviceDefinition.name_id.contains("Tablet"))
|
|
||||||
deviceType = Tablet;
|
|
||||||
else
|
|
||||||
deviceType = Phone;
|
|
||||||
}
|
|
||||||
deviceDefinition.deviceType = deviceType;
|
|
||||||
m_deviceDefinitionsList.append(deviceDefinition);
|
|
||||||
avdDeviceInfo.clear();
|
|
||||||
} else {
|
|
||||||
avdDeviceInfo << line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AvdDialog::updateDeviceDefinitionComboBox()
|
void AvdDialog::updateDeviceDefinitionComboBox()
|
||||||
{
|
{
|
||||||
DeviceType curDeviceType = m_deviceTypeToStringMap.key(
|
DeviceType curDeviceType = m_deviceTypeToStringMap.key(
|
||||||
|
@@ -44,13 +44,13 @@ private:
|
|||||||
int sdcardSize() const;
|
int sdcardSize() const;
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
|
|
||||||
void parseDeviceDefinitionsList();
|
|
||||||
void updateDeviceDefinitionComboBox();
|
void updateDeviceDefinitionComboBox();
|
||||||
void updateApiLevelComboBox();
|
void updateApiLevelComboBox();
|
||||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
|
||||||
static AvdDialog::DeviceType tagToDeviceType(const QString &type_tag);
|
static AvdDialog::DeviceType tagToDeviceType(const QString &type_tag);
|
||||||
|
|
||||||
|
void collectInitialData();
|
||||||
void createAvd();
|
void createAvd();
|
||||||
|
|
||||||
struct DeviceDefinitionStruct
|
struct DeviceDefinitionStruct
|
||||||
@@ -66,6 +66,7 @@ private:
|
|||||||
QList<DeviceDefinitionStruct> m_deviceDefinitionsList;
|
QList<DeviceDefinitionStruct> m_deviceDefinitionsList;
|
||||||
QMap<AvdDialog::DeviceType, QString> m_deviceTypeToStringMap;
|
QMap<AvdDialog::DeviceType, QString> m_deviceTypeToStringMap;
|
||||||
|
|
||||||
|
QWidget *m_gui;
|
||||||
QComboBox *m_abiComboBox;
|
QComboBox *m_abiComboBox;
|
||||||
QSpinBox *m_sdcardSizeSpinBox;
|
QSpinBox *m_sdcardSizeSpinBox;
|
||||||
QLineEdit *m_nameLineEdit;
|
QLineEdit *m_nameLineEdit;
|
||||||
|
Reference in New Issue
Block a user