Android: Improve "Add new AVD" dialog

* Re-organize the implementation to create a new AVD
* Use SystemImage instead of SdKPlatform because now
an SdkPlatform can be installed partially with a SystemImage.
The current implementation does not consider the this case,
thus we end up with an uncomplete list of installed system images.
* Add Device definitions with categories (phone, tablet, tv, etc.)
to the creation process (check -d arg in avdmanager create avd).

Task-number: QTCREATORBUG-23284
Change-Id: Id02a71ad452fb423fa2781d06ef3fcf2afa328a9
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Assam Boudjelthia
2020-01-08 14:55:16 +02:00
parent 382589f160
commit 0df5d8c2e5
13 changed files with 263 additions and 73 deletions

View File

@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>600</width> <width>600</width>
<height>187</height> <height>243</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
@@ -30,45 +30,49 @@
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="nameLabel"> <widget class="QLabel" name="nameLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>Name:</string> <string>Name:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="2" column="0">
<widget class="QLineEdit" name="nameLineEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="abiLabel"> <widget class="QLabel" name="abiLabel">
<property name="text"> <property name="text">
<string>Architecture (ABI):</string> <string>Architecture (ABI):</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="5" column="0">
<widget class="QComboBox" name="abiComboBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="targetApiLabel">
<property name="text">
<string>Target API:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="targetApiComboBox"/>
</item>
<item row="3" column="1">
<widget class="Utils::InfoLabel" name="warningText"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="sdcardSizeLabel"> <widget class="QLabel" name="sdcardSizeLabel">
<property name="text"> <property name="text">
<string>SD card size:</string> <string>SD card size:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="3" column="0">
<widget class="QLabel" name="targetApiLabel">
<property name="text">
<string>Target API:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="deviceDefinitionLabel">
<property name="text">
<string>Device definition:</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QComboBox" name="abiComboBox"/>
</item>
<item row="5" column="1" colspan="2">
<widget class="QSpinBox" name="sdcardSizeSpinBox"> <widget class="QSpinBox" name="sdcardSizeSpinBox">
<property name="alignment"> <property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@@ -87,6 +91,35 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="nameLineEdit"/>
</item>
<item row="3" column="1" colspan="2">
<widget class="QComboBox" name="targetApiComboBox"/>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="deviceDefinitionComboBox"/>
</item>
<item row="4" column="1" colspan="2">
<widget class="Utils::InfoLabel" name="warningText"/>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="deviceDefinitionTypeComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="overwriteCheckBox">
<property name="text">
<string>Overwrite existing AVD name</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>

View File

@@ -71,7 +71,7 @@ const int avdCreateTimeoutMs = 30000;
\c true if the command is successfully executed. Output is copied into \a output. The function \c true if the command is successfully executed. Output is copied into \a output. The function
blocks the calling thread. blocks the calling thread.
*/ */
static bool avdManagerCommand(const AndroidConfig config, const QStringList &args, QString *output) bool AndroidAvdManager::avdManagerCommand(const AndroidConfig config, const QStringList &args, QString *output)
{ {
CommandLine cmd(config.avdManagerToolPath(), args); CommandLine cmd(config.avdManagerToolPath(), args);
Utils::SynchronousProcess proc; Utils::SynchronousProcess proc;
@@ -118,7 +118,7 @@ static CreateAvdInfo createAvdCommand(const AndroidConfig config, const CreateAv
if (!result.isValid()) { if (!result.isValid()) {
qCDebug(avdManagerLog) << "AVD Create failed. Invalid CreateAvdInfo" << result.name qCDebug(avdManagerLog) << "AVD Create failed. Invalid CreateAvdInfo" << result.name
<< result.sdkPlatform->displayText() << result.sdkPlatform->apiLevel(); << result.systemImage->displayText() << result.systemImage->apiLevel();
result.error = QApplication::translate("AndroidAvdManager", result.error = QApplication::translate("AndroidAvdManager",
"Cannot create AVD. Invalid input."); "Cannot create AVD. Invalid input.");
return result; return result;
@@ -126,28 +126,17 @@ static CreateAvdInfo createAvdCommand(const AndroidConfig config, const CreateAv
QStringList arguments({"create", "avd", "-n", result.name}); QStringList arguments({"create", "avd", "-n", result.name});
if (!result.abi.isEmpty()) { arguments << "-k" << result.systemImage->sdkStylePath();
SystemImage *image = Utils::findOrDefault(result.sdkPlatform->systemImages(),
Utils::equal(&SystemImage::abiName, result.abi));
if (image && image->isValid()) {
arguments << "-k" << image->sdkStylePath();
} else {
QString name = result.sdkPlatform->displayText();
qCDebug(avdManagerLog) << "AVD Create failed. Cannot find system image for the platform"
<< result.abi << name;
result.error = QApplication::translate("AndroidAvdManager",
"Cannot create AVD. Cannot find system image for "
"the ABI %1(%2).").arg(result.abi).arg(name);
return result;
}
} else {
arguments << "-k" << result.sdkPlatform->sdkStylePath();
}
if (result.sdcardSize > 0) if (result.sdcardSize > 0)
arguments << "-c" << QString::fromLatin1("%1M").arg(result.sdcardSize); arguments << "-c" << QString::fromLatin1("%1M").arg(result.sdcardSize);
if (!result.deviceDefinition.isEmpty() && result.deviceDefinition != "Custom")
arguments << "-d" << QString::fromLatin1("%1").arg(result.deviceDefinition);
if (result.overwrite)
arguments << "-f";
QProcess proc; QProcess proc;
proc.start(config.avdManagerToolPath().toString(), arguments); proc.start(config.avdManagerToolPath().toString(), arguments);
if (!proc.waitForStarted()) { if (!proc.waitForStarted()) {
@@ -419,7 +408,7 @@ AndroidDeviceInfoList AvdManagerOutputParser::listVirtualDevices(const AndroidCo
AndroidDeviceInfoList avdList; AndroidDeviceInfoList avdList;
do { do {
if (!avdManagerCommand(config, {"list", "avd"}, &output)) { if (!AndroidAvdManager::avdManagerCommand(config, {"list", "avd"}, &output)) {
qCDebug(avdManagerLog) qCDebug(avdManagerLog)
<< "Avd list command failed" << output << config.sdkToolsVersion(); << "Avd list command failed" << output << config.sdkToolsVersion();
return {}; return {};

View File

@@ -54,6 +54,9 @@ public:
QString waitForAvd(const QString &avdName, QString waitForAvd(const QString &avdName,
const std::function<bool()> &cancelChecker = {}) const; const std::function<bool()> &cancelChecker = {}) const;
bool isAvdBooted(const QString &device) const; bool isAvdBooted(const QString &device) const;
static bool avdManagerCommand(const AndroidConfig config,
const QStringList &args,
QString *output);
private: private:
bool waitForBooted(const QString &serialNumber, bool waitForBooted(const QString &serialNumber,

View File

@@ -85,12 +85,14 @@ using AndroidDeviceInfoList = QList<AndroidDeviceInfo>;
class CreateAvdInfo class CreateAvdInfo
{ {
public: public:
bool isValid() const { return sdkPlatform && sdkPlatform->isValid() && !name.isEmpty(); } bool isValid() const { return systemImage && systemImage->isValid() && !name.isEmpty(); }
const SdkPlatform *sdkPlatform = nullptr; const SystemImage *systemImage = nullptr;
QString name; QString name;
QString abi; QString abi;
QString deviceDefinition;
int sdcardSize = 0; int sdcardSize = 0;
QString error; // only used in the return value of createAVD QString error; // only used in the return value of createAVD
bool overwrite = false;
}; };
class ANDROID_EXPORT AndroidConfig class ANDROID_EXPORT AndroidConfig

View File

@@ -578,7 +578,7 @@ void AndroidDeviceDialog::createAvd()
{ {
m_ui->createAVDButton->setEnabled(false); m_ui->createAVDButton->setEnabled(false);
CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, AndroidConfigurations::sdkManager(), CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, AndroidConfigurations::sdkManager(),
m_apiLevel, m_abis); AndroidConfigurations::currentConfig(), m_apiLevel, m_abis);
if (!info.isValid()) { if (!info.isValid()) {
m_ui->createAVDButton->setEnabled(true); m_ui->createAVDButton->setEnabled(true);

View File

@@ -345,6 +345,21 @@ AndroidSdkPackageList AndroidSdkManager::installedSdkPackages()
return m_d->filteredPackages(AndroidSdkPackage::Installed, AndroidSdkPackage::AnyValidType); return m_d->filteredPackages(AndroidSdkPackage::Installed, AndroidSdkPackage::AnyValidType);
} }
SystemImageList AndroidSdkManager::installedSystemImages()
{
AndroidSdkPackageList list = m_d->filteredPackages(AndroidSdkPackage::AnyValidState,
AndroidSdkPackage::SdkPlatformPackage);
QList<SdkPlatform *> platforms = Utils::static_container_cast<SdkPlatform *>(list);
SystemImageList result;
for (SdkPlatform *platform : platforms) {
if (platform->systemImages().size() > 0)
result.append(platform->systemImages());
}
return result;
}
SdkPlatform *AndroidSdkManager::latestAndroidSdkPlatform(AndroidSdkPackage::PackageState state) SdkPlatform *AndroidSdkManager::latestAndroidSdkPlatform(AndroidSdkPackage::PackageState state)
{ {
SdkPlatform *result = nullptr; SdkPlatform *result = nullptr;
@@ -679,6 +694,7 @@ QPair<SystemImage *, int> SdkManagerOutputParser::parseSystemImage(const QString
image->setInstalledLocation(packageData.installedLocation); image->setInstalledLocation(packageData.installedLocation);
image->setDisplayText(packageData.description); image->setDisplayText(packageData.description);
image->setDescriptionText(packageData.description); image->setDescriptionText(packageData.description);
image->setApiLevel(apiLevel);
result = qMakePair(image, apiLevel); result = qMakePair(image, apiLevel);
} else { } else {
qCDebug(sdkManagerLog) << "System-image: Minimum required data unavailable: "<< data; qCDebug(sdkManagerLog) << "System-image: Minimum required data unavailable: "<< data;

View File

@@ -69,6 +69,7 @@ public:
const AndroidSdkPackageList &allSdkPackages(); const AndroidSdkPackageList &allSdkPackages();
AndroidSdkPackageList availableSdkPackages(); AndroidSdkPackageList availableSdkPackages();
AndroidSdkPackageList installedSdkPackages(); AndroidSdkPackageList installedSdkPackages();
SystemImageList installedSystemImages();
SdkPlatform *latestAndroidSdkPlatform(AndroidSdkPackage::PackageState state SdkPlatform *latestAndroidSdkPlatform(AndroidSdkPackage::PackageState state
= AndroidSdkPackage::Installed); = AndroidSdkPackage::Installed);

View File

@@ -134,6 +134,16 @@ void SystemImage::setPlatform(SdkPlatform *platform)
m_platform = platform; m_platform = platform;
} }
int SystemImage::apiLevel() const
{
return m_apiLevel;
}
void SystemImage::setApiLevel(const int apiLevel)
{
m_apiLevel = apiLevel;
}
SdkPlatform::SdkPlatform(QVersionNumber version, QString sdkStylePathStr, int api, QObject *parent) : SdkPlatform::SdkPlatform(QVersionNumber version, QString sdkStylePathStr, int api, QObject *parent) :
AndroidSdkPackage(version, sdkStylePathStr, parent), AndroidSdkPackage(version, sdkStylePathStr, parent),
m_apiLevel(api) m_apiLevel(api)

View File

@@ -114,10 +114,13 @@ public:
const QString &abiName() const; const QString &abiName() const;
const SdkPlatform *platform() const; const SdkPlatform *platform() const;
void setPlatform(SdkPlatform *platform); void setPlatform(SdkPlatform *platform);
int apiLevel() const;
void setApiLevel(const int apiLevel);
private: private:
QPointer<SdkPlatform> m_platform; QPointer<SdkPlatform> m_platform;
QString m_abiName; QString m_abiName;
int m_apiLevel = -1;
}; };
using SystemImageList = QList<SystemImage*>; using SystemImageList = QList<SystemImage*>;

View File

@@ -260,7 +260,8 @@ QVariant AvdModel::data(const QModelIndex &index, int role) const
return cpuAbis.isEmpty() ? QVariant() : QVariant(cpuAbis.first()); return cpuAbis.isEmpty() ? QVariant() : QVariant(cpuAbis.first());
} }
case 3: case 3:
return currentRow.avdDevice; return currentRow.avdDevice.isEmpty() ? QVariant("Custom")
: currentRow.avdDevice;
case 4: case 4:
return currentRow.avdTarget; return currentRow.avdTarget;
case 5: case 5:
@@ -556,7 +557,7 @@ void AndroidSettingsWidget::openOpenJDKDownloadUrl()
void AndroidSettingsWidget::addAVD() void AndroidSettingsWidget::addAVD()
{ {
disableAvdControls(); disableAvdControls();
CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, m_sdkManager.get()); CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, m_sdkManager.get(), m_androidConfig);
if (!info.isValid()) { if (!info.isValid()) {
enableAvdControls(); enableAvdControls();

View File

@@ -148,7 +148,7 @@ CreateAvdInfo AndroidToolManager::createAvdImpl(CreateAvdInfo info, FilePath and
proc.setProcessEnvironment(env); proc.setProcessEnvironment(env);
QStringList arguments; QStringList arguments;
arguments << QLatin1String("create") << QLatin1String("avd") arguments << QLatin1String("create") << QLatin1String("avd")
<< QLatin1String("-t") << AndroidConfig::apiLevelNameFor(info.sdkPlatform) << QLatin1String("-t") << QString("android-%1").arg(info.systemImage->apiLevel())
<< QLatin1String("-n") << info.name << QLatin1String("-n") << info.name
<< QLatin1String("-b") << info.abi; << QLatin1String("-b") << info.abi;
if (info.sdcardSize > 0) if (info.sdcardSize > 0)

View File

@@ -25,6 +25,7 @@
#include "avddialog.h" #include "avddialog.h"
#include "androidsdkmanager.h" #include "androidsdkmanager.h"
#include "androidavdmanager.h"
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/tooltip/tooltip.h> #include <utils/tooltip/tooltip.h>
@@ -34,16 +35,22 @@
#include <QKeyEvent> #include <QKeyEvent>
#include <QMessageBox> #include <QMessageBox>
#include <QToolTip> #include <QToolTip>
#include <QLoggingCategory>
using namespace Android; using namespace Android;
using namespace Android::Internal; using namespace Android::Internal;
namespace {
Q_LOGGING_CATEGORY(avdDialogLog, "qtc.android.avdDialog", QtWarningMsg)
}
AvdDialog::AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QStringList &abis, AvdDialog::AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QStringList &abis,
QWidget *parent) : const AndroidConfig &config, QWidget *parent) :
QDialog(parent), QDialog(parent),
m_sdkManager(sdkManager), m_sdkManager(sdkManager),
m_minApiLevel(minApiLevel), m_minApiLevel(minApiLevel),
m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*")) m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*")),
m_androidConfig(config)
{ {
QTC_CHECK(m_sdkManager); QTC_CHECK(m_sdkManager);
m_avdDialog.setupUi(this); m_avdDialog.setupUi(this);
@@ -63,39 +70,119 @@ AvdDialog::AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QStri
m_avdDialog.warningText->setType(Utils::InfoLabel::Warning); m_avdDialog.warningText->setType(Utils::InfoLabel::Warning);
updateApiLevelComboBox(); connect(&m_hideTipTimer, &QTimer::timeout, this, []() { Utils::ToolTip::hide(); });
parseDeviceDefinitionsList();
for (const QString &type : DeviceTypeToStringMap.values())
m_avdDialog.deviceDefinitionTypeComboBox->addItem(type);
connect(m_avdDialog.deviceDefinitionTypeComboBox,
QOverload<int>::of(&QComboBox::currentIndexChanged),
this,
&AvdDialog::updateDeviceDefinitionComboBox);
connect(m_avdDialog.abiComboBox, connect(m_avdDialog.abiComboBox,
QOverload<int>::of(&QComboBox::currentIndexChanged), QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &AvdDialog::updateApiLevelComboBox); this, &AvdDialog::updateApiLevelComboBox);
connect(&m_hideTipTimer, &QTimer::timeout, m_avdDialog.deviceDefinitionTypeComboBox->setCurrentIndex(1); // Set Phone type as default index
this, [](){Utils::ToolTip::hide();}); updateApiLevelComboBox();
} }
bool AvdDialog::isValid() const bool AvdDialog::isValid() const
{ {
return !name().isEmpty() && sdkPlatform() && sdkPlatform()->isValid() && !abi().isEmpty(); return !name().isEmpty() && systemImage() && systemImage()->isValid() && !abi().isEmpty();
} }
CreateAvdInfo AvdDialog::gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager *sdkManager, CreateAvdInfo AvdDialog::gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager *sdkManager,
int minApiLevel, const QStringList &abis) const AndroidConfig &config, int minApiLevel, const QStringList &abis)
{ {
CreateAvdInfo result; CreateAvdInfo result;
AvdDialog d(minApiLevel, sdkManager, abis, parent); AvdDialog d(minApiLevel, sdkManager, abis, config, parent);
if (d.exec() != QDialog::Accepted || !d.isValid()) if (d.exec() != QDialog::Accepted || !d.isValid())
return result; return result;
result.sdkPlatform = d.sdkPlatform(); result.systemImage = d.systemImage();
result.name = d.name(); result.name = d.name();
result.abi = d.abi(); result.abi = d.abi();
result.deviceDefinition = d.deviceDefinition();
result.sdcardSize = d.sdcardSize(); result.sdcardSize = d.sdcardSize();
result.overwrite = d.m_avdDialog.overwriteCheckBox->isChecked();
return result; return result;
} }
const SdkPlatform* AvdDialog::sdkPlatform() const AvdDialog::DeviceType AvdDialog::tagToDeviceType(const QString &type_tag)
{ {
return m_avdDialog.targetApiComboBox->currentData().value<SdkPlatform*>(); if (type_tag.contains("android-wear"))
return AvdDialog::Wear;
else if (type_tag.contains("android-tv"))
return AvdDialog::TV;
else if (type_tag.contains("android-automotive"))
return AvdDialog::Automotive;
else
return AvdDialog::PhoneOrTablet;
}
void AvdDialog::parseDeviceDefinitionsList()
{
QString output;
if (!AndroidAvdManager::avdManagerCommand(m_androidConfig, {"list", "device"}, &output)) {
qCDebug(avdDialogLog) << "Avd list command failed" << output
<< m_androidConfig.sdkToolsVersion();
return;
}
QStringList avdDeviceInfo;
for (QString line : output.split('\n')) {
if (line.startsWith("---------") || line.isEmpty()) {
DeviceDefinitionStruct deviceDefinition;
for (const QString &line : avdDeviceInfo) {
QString value;
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()
{
DeviceType curDeviceType = DeviceTypeToStringMap.key(
m_avdDialog.deviceDefinitionTypeComboBox->currentText());
m_avdDialog.deviceDefinitionComboBox->clear();
for (auto item : m_deviceDefinitionsList) {
if (item.deviceType == curDeviceType)
m_avdDialog.deviceDefinitionComboBox->addItem(item.name_id);
}
m_avdDialog.deviceDefinitionComboBox->addItem("Custom");
updateApiLevelComboBox();
}
const SystemImage* AvdDialog::systemImage() const
{
return m_avdDialog.targetApiComboBox->currentData().value<SystemImage*>();
} }
QString AvdDialog::name() const QString AvdDialog::name() const
@@ -108,6 +195,11 @@ QString AvdDialog::abi() const
return m_avdDialog.abiComboBox->currentText(); return m_avdDialog.abiComboBox->currentText();
} }
QString AvdDialog::deviceDefinition() const
{
return m_avdDialog.deviceDefinitionComboBox->currentText();
}
int AvdDialog::sdcardSize() const int AvdDialog::sdcardSize() const
{ {
return m_avdDialog.sdcardSizeSpinBox->value(); return m_avdDialog.sdcardSizeSpinBox->value();
@@ -115,37 +207,49 @@ int AvdDialog::sdcardSize() const
void AvdDialog::updateApiLevelComboBox() void AvdDialog::updateApiLevelComboBox()
{ {
SdkPlatformList filteredList; SystemImageList installedSystemImages = m_sdkManager->installedSystemImages();
const SdkPlatformList platforms = m_sdkManager->filteredSdkPlatforms(m_minApiLevel); DeviceType curDeviceType = DeviceTypeToStringMap.key(
m_avdDialog.deviceDefinitionTypeComboBox->currentText());
QString selectedAbi = abi(); QString selectedAbi = abi();
auto hasAbi = [selectedAbi](const SystemImage *image) { auto hasAbi = [selectedAbi](const SystemImage *image) {
return image && image->isValid() && (image->abiName() == selectedAbi); return image && image->isValid() && (image->abiName() == selectedAbi);
}; };
filteredList = Utils::filtered(platforms, [hasAbi](const SdkPlatform *platform) { SystemImageList filteredList;
return platform && Utils::anyOf(platform->systemImages(), hasAbi); filteredList = Utils::filtered(installedSystemImages, [hasAbi, &curDeviceType](const SystemImage *image) {
DeviceType deviceType = tagToDeviceType(image->sdkStylePath().split(';').at(2));
if (deviceType == PhoneOrTablet && (curDeviceType == Phone || curDeviceType == Tablet))
curDeviceType = PhoneOrTablet;
return image && deviceType == curDeviceType && hasAbi(image);
}); });
m_avdDialog.targetApiComboBox->clear(); m_avdDialog.targetApiComboBox->clear();
for (SdkPlatform *platform: filteredList) { for (SystemImage *image : filteredList) {
m_avdDialog.targetApiComboBox->addItem(platform->displayText(), QString imageString = "android-" % QString::number(image->apiLevel());
QVariant::fromValue<SdkPlatform *>(platform)); if (image->sdkStylePath().contains("playstore"))
imageString += " (Google PlayStore)";
m_avdDialog.targetApiComboBox->addItem(imageString,
QVariant::fromValue<SystemImage *>(image));
m_avdDialog.targetApiComboBox->setItemData(m_avdDialog.targetApiComboBox->count() - 1, m_avdDialog.targetApiComboBox->setItemData(m_avdDialog.targetApiComboBox->count() - 1,
platform->descriptionText(), Qt::ToolTipRole); image->descriptionText(),
Qt::ToolTipRole);
} }
if (platforms.isEmpty()) { if (installedSystemImages.isEmpty()) {
m_avdDialog.targetApiComboBox->setEnabled(false);
m_avdDialog.warningText->setVisible(true); m_avdDialog.warningText->setVisible(true);
m_avdDialog.warningText->setText(tr("Cannot create a new AVD. No sufficiently recent Android SDK available.\n" m_avdDialog.warningText->setText(tr("Cannot create a new AVD. No sufficiently recent Android SDK available.\n"
"Install an SDK of at least API version %1.") "Install an SDK of at least API version %1.")
.arg(m_minApiLevel)); .arg(m_minApiLevel));
} else if (filteredList.isEmpty()) { } else if (filteredList.isEmpty()) {
m_avdDialog.targetApiComboBox->setEnabled(false);
m_avdDialog.warningText->setVisible(true); m_avdDialog.warningText->setVisible(true);
m_avdDialog.warningText->setText(tr("Cannot create a AVD for ABI %1. Install an image for it.") m_avdDialog.warningText->setText(tr("Cannot create a AVD for ABI %1. Install an image for it.")
.arg(abi())); .arg(abi()));
} else { } else {
m_avdDialog.warningText->setVisible(false); m_avdDialog.warningText->setVisible(false);
m_avdDialog.targetApiComboBox->setEnabled(true);
} }
} }

View File

@@ -26,6 +26,7 @@
#pragma once #pragma once
#include "androidconfigurations.h" #include "androidconfigurations.h"
#include "ui_addnewavddialog.h" #include "ui_addnewavddialog.h"
#include "androidconfigurations.h"
#include <QDialog> #include <QDialog>
#include <QTimer> #include <QTimer>
@@ -40,18 +41,43 @@ class AvdDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QStringList &abis, explicit AvdDialog(int minApiLevel,
AndroidSdkManager *sdkManager,
const QStringList &abis,
const AndroidConfig &config,
QWidget *parent = nullptr); QWidget *parent = nullptr);
const SdkPlatform *sdkPlatform() const; enum DeviceType { TV, Phone, Wear, Tablet, Automotive, PhoneOrTablet };
const QMap<DeviceType, QString> DeviceTypeToStringMap{
{TV, "TV"},
{Phone, "Phone"},
{Wear, "Wear"},
{Tablet, "Tablet"},
{Automotive, "Automotive"}
};
struct DeviceDefinitionStruct
{
QString name_id;
QString type_str;
DeviceType deviceType;
};
const SystemImage *systemImage() const;
QString name() const; QString name() const;
QString abi() const; QString abi() const;
QString deviceDefinition() const;
int sdcardSize() const; int sdcardSize() const;
bool isValid() const; bool isValid() const;
static AvdDialog::DeviceType tagToDeviceType(const QString &type_tag);
static CreateAvdInfo gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager *sdkManager, static CreateAvdInfo gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager *sdkManager,
const AndroidConfig &config,
int minApiLevel = 0, const QStringList &abis = {}); int minApiLevel = 0, const QStringList &abis = {});
private: private:
void parseDeviceDefinitionsList();
void updateDeviceDefinitionComboBox();
void updateApiLevelComboBox(); void updateApiLevelComboBox();
bool eventFilter(QObject *obj, QEvent *event) override; bool eventFilter(QObject *obj, QEvent *event) override;
@@ -60,6 +86,8 @@ private:
int m_minApiLevel; int m_minApiLevel;
QTimer m_hideTipTimer; QTimer m_hideTipTimer;
QRegExp m_allowedNameChars; QRegExp m_allowedNameChars;
QList<DeviceDefinitionStruct> m_deviceDefinitionsList;
AndroidConfig m_androidConfig;
}; };
} }
} }