forked from qt-creator/qt-creator
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:
@@ -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>
|
||||||
|
|||||||
@@ -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 {};
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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*>;
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user