Android: Refactor Android SDK packages

Introduce a hierarchy for Android SDK packages and refactor the
code accordingly. This is ground work for sdk management and
automatic android setup

Task-number: QTCREATORBUG-18978
Change-Id: Idef545e3b3a8e33e920be52b26094fb8046afcd3
Reviewed-by: BogDan Vatra <bogdan@kdab.com>
This commit is contained in:
Vikas Pachdha
2017-08-18 08:22:34 +02:00
parent 240d310a81
commit ec4fe5f04f
20 changed files with 854 additions and 317 deletions

View File

@@ -50,7 +50,8 @@ HEADERS += \
androidsdkmanager.h \ androidsdkmanager.h \
androidavdmanager.h \ androidavdmanager.h \
androidrunconfigurationwidget.h \ androidrunconfigurationwidget.h \
adbcommandswidget.h adbcommandswidget.h \
androidsdkpackage.h
SOURCES += \ SOURCES += \
androidconfigurations.cpp \ androidconfigurations.cpp \
@@ -94,7 +95,8 @@ SOURCES += \
androidsdkmanager.cpp \ androidsdkmanager.cpp \
androidavdmanager.cpp \ androidavdmanager.cpp \
androidrunconfigurationwidget.cpp \ androidrunconfigurationwidget.cpp \
adbcommandswidget.cpp adbcommandswidget.cpp \
androidsdkpackage.cpp
FORMS += \ FORMS += \
androidsettingswidget.ui \ androidsettingswidget.ui \

View File

@@ -101,37 +101,37 @@ static bool checkForTimeout(const chrono::steady_clock::time_point &start,
return timedOut; return timedOut;
} }
static AndroidConfig::CreateAvdInfo createAvdCommand(const AndroidConfig config, static CreateAvdInfo createAvdCommand(const AndroidConfig config, const CreateAvdInfo &info)
const AndroidConfig::CreateAvdInfo &info)
{ {
AndroidConfig::CreateAvdInfo result = info; CreateAvdInfo result = info;
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.target.name << result.target.apiLevel; << result.sdkPlatform->displayText() << result.sdkPlatform->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;
} }
QStringList arguments({"create", "avd", "-k", result.target.package, "-n", result.name}); QStringList arguments({"create", "avd", "-k", result.sdkPlatform->sdkStylePath(), "-n", result.name});
if (!result.abi.isEmpty()) { if (!result.abi.isEmpty()) {
SystemImage image = Utils::findOrDefault(result.target.systemImages, SystemImage *image = Utils::findOrDefault(result.sdkPlatform->systemImages(),
Utils::equal(&SystemImage::abiName, result.abi)); Utils::equal(&SystemImage::abiName, result.abi));
if (image.isValid()) { if (image && image->isValid()) {
arguments << "-k" << image.package; arguments << "-k" << image->sdkStylePath();
} else { } else {
QString name = result.sdkPlatform->displayText();
qCDebug(avdManagerLog) << "AVD Create failed. Cannot find system image for the platform" qCDebug(avdManagerLog) << "AVD Create failed. Cannot find system image for the platform"
<< result.abi << result.target.name; << result.abi << name;
result.error = QApplication::translate("AndroidAvdManager", result.error = QApplication::translate("AndroidAvdManager",
"Cannot create AVD. Cannot find system image for " "Cannot create AVD. Cannot find system image for "
"the ABI %1(%2).").arg(result.abi).arg(result.target.name); "the ABI %1(%2).").arg(result.abi).arg(name);
return result; return result;
} }
} else { } else {
arguments << "-k" << result.target.package; arguments << "-k" << result.sdkPlatform->sdkStylePath();
} }
if (result.sdcardSize > 0) if (result.sdcardSize > 0)
@@ -234,8 +234,7 @@ void AndroidAvdManager::launchAvdManagerUiTool() const
} }
} }
QFuture<AndroidConfig::CreateAvdInfo> QFuture<CreateAvdInfo> AndroidAvdManager::createAvd(CreateAvdInfo info) const
AndroidAvdManager::createAvd(AndroidConfig::CreateAvdInfo info) const
{ {
if (m_config.sdkToolsVersion() < avdManagerIntroVersion) if (m_config.sdkToolsVersion() < avdManagerIntroVersion)
return m_androidTool->createAvd(info); return m_androidTool->createAvd(info);

View File

@@ -42,7 +42,7 @@ public:
bool avdManagerUiToolAvailable() const; bool avdManagerUiToolAvailable() const;
void launchAvdManagerUiTool() const; void launchAvdManagerUiTool() const;
QFuture<AndroidConfig::CreateAvdInfo> createAvd(AndroidConfig::CreateAvdInfo info) const; QFuture<CreateAvdInfo> createAvd(CreateAvdInfo info) const;
bool removeAvd(const QString &name) const; bool removeAvd(const QString &name) const;
QFuture<AndroidDeviceInfoList> avdList() const; QFuture<AndroidDeviceInfoList> avdList() const;

View File

@@ -29,6 +29,7 @@
#include "androidconfigurations.h" #include "androidconfigurations.h"
#include "androidconstants.h" #include "androidconstants.h"
#include "androidmanager.h" #include "androidmanager.h"
#include "androidsdkmanager.h"
#include "androidqtsupport.h" #include "androidqtsupport.h"
#include "certificatesmodel.h" #include "certificatesmodel.h"
@@ -92,7 +93,8 @@ private:
AndroidBuildApkStep::AndroidBuildApkStep(ProjectExplorer::BuildStepList *parent, const Core::Id id) AndroidBuildApkStep::AndroidBuildApkStep(ProjectExplorer::BuildStepList *parent, const Core::Id id)
: ProjectExplorer::AbstractProcessStep(parent, id), : ProjectExplorer::AbstractProcessStep(parent, id),
m_buildTargetSdk(AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk())) m_buildTargetSdk(AndroidConfig::apiLevelNameFor(AndroidConfigurations::
sdkManager()->latestAndroidSdkPlatform()))
{ {
//: AndroidBuildApkStep default display name //: AndroidBuildApkStep default display name
setDefaultDisplayName(tr("Build Android APK")); setDefaultDisplayName(tr("Build Android APK"));
@@ -236,8 +238,10 @@ bool AndroidBuildApkStep::fromMap(const QVariantMap &map)
m_keystorePath = Utils::FileName::fromString(map.value(KeystoreLocationKey).toString()); m_keystorePath = Utils::FileName::fromString(map.value(KeystoreLocationKey).toString());
m_signPackage = false; // don't restore this m_signPackage = false; // don't restore this
m_buildTargetSdk = map.value(BuildTargetSdkKey).toString(); m_buildTargetSdk = map.value(BuildTargetSdkKey).toString();
if (m_buildTargetSdk.isEmpty()) if (m_buildTargetSdk.isEmpty()) {
m_buildTargetSdk = AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk()); m_buildTargetSdk = AndroidConfig::apiLevelNameFor(AndroidConfigurations::
sdkManager()->latestAndroidSdkPlatform());
}
m_verbose = map.value(VerboseOutputKey).toBool(); m_verbose = map.value(VerboseOutputKey).toBool();
return ProjectExplorer::BuildStep::fromMap(map); return ProjectExplorer::BuildStep::fromMap(map);
} }

View File

@@ -29,6 +29,7 @@
#include "androidconfigurations.h" #include "androidconfigurations.h"
#include "androidcreatekeystorecertificate.h" #include "androidcreatekeystorecertificate.h"
#include "androidmanager.h" #include "androidmanager.h"
#include "androidsdkmanager.h"
#include "ui_androidbuildapkwidget.h" #include "ui_androidbuildapkwidget.h"
#include <projectexplorer/buildconfiguration.h> #include <projectexplorer/buildconfiguration.h>
@@ -47,6 +48,8 @@
using namespace Android; using namespace Android;
using namespace Internal; using namespace Internal;
const int minApiSupported = 9;
AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step) AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step)
: ProjectExplorer::BuildStepConfigWidget(), : ProjectExplorer::BuildStepConfigWidget(),
m_ui(new Ui::AndroidBuildApkWidget), m_ui(new Ui::AndroidBuildApkWidget),
@@ -55,9 +58,8 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step)
m_ui->setupUi(this); m_ui->setupUi(this);
// Target sdk combobox // Target sdk combobox
int minApiLevel = 9; QStringList targets = AndroidConfig::apiLevelNamesFor(AndroidConfigurations::sdkManager()->
const AndroidConfig &config = AndroidConfigurations::currentConfig(); filteredSdkPlatforms(minApiSupported));
QStringList targets = AndroidConfig::apiLevelNamesFor(config.sdkTargets(minApiLevel));
targets.removeDuplicates(); targets.removeDuplicates();
m_ui->targetSDKComboBox->addItems(targets); m_ui->targetSDKComboBox->addItems(targets);
m_ui->targetSDKComboBox->setCurrentIndex(targets.indexOf(AndroidManager::buildTargetSDK(step->target()))); m_ui->targetSDKComboBox->setCurrentIndex(targets.indexOf(AndroidManager::buildTargetSDK(step->target())));

View File

@@ -272,7 +272,6 @@ void AndroidConfig::load(const QSettings &settings)
m_makeExtraSearchDirectories << extraDirectory; m_makeExtraSearchDirectories << extraDirectory;
// persistent settings // persistent settings
} }
m_availableSdkPlatformsUpToDate = false;
m_NdkInformationUpToDate = false; m_NdkInformationUpToDate = false;
} }
@@ -333,40 +332,15 @@ void AndroidConfig::updateNdkInformation() const
m_NdkInformationUpToDate = true; m_NdkInformationUpToDate = true;
} }
void AndroidConfig::updateAvailableSdkPlatforms() const QStringList AndroidConfig::apiLevelNamesFor(const SdkPlatformList &platforms)
{
if (m_availableSdkPlatformsUpToDate)
return;
m_availableSdkPlatforms.clear();
AndroidSdkManager sdkManager(*this);
bool success = false;
m_availableSdkPlatforms = sdkManager.availableSdkPlatforms(&success);
if (success)
m_availableSdkPlatformsUpToDate = true;
}
QStringList AndroidConfig::apiLevelNamesFor(const QList<SdkPlatform> &platforms)
{ {
return Utils::transform(platforms, AndroidConfig::apiLevelNameFor); return Utils::transform(platforms, AndroidConfig::apiLevelNameFor);
} }
QString AndroidConfig::apiLevelNameFor(const SdkPlatform &platform) QString AndroidConfig::apiLevelNameFor(const SdkPlatform *platform)
{ {
return platform.apiLevel > 0 ? QString("android-%1").arg(platform.apiLevel) : ""; return platform && platform->apiLevel() > 0 ?
} QString("android-%1").arg(platform->apiLevel()) : "";
QList<SdkPlatform> AndroidConfig::sdkTargets(int minApiLevel) const
{
updateAvailableSdkPlatforms();
QList<SdkPlatform> result;
for (int i = 0; i < m_availableSdkPlatforms.size(); ++i) {
if (m_availableSdkPlatforms.at(i).apiLevel >= minApiLevel)
result << m_availableSdkPlatforms.at(i);
else
break;
}
return result;
} }
FileName AndroidConfig::adbToolPath() const FileName AndroidConfig::adbToolPath() const
@@ -523,20 +497,6 @@ QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(const QString &adbToo
return devices; return devices;
} }
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 result;
result.target = d.target();
result.name = d.name();
result.abi = d.abi();
result.sdcardSize = d.sdcardSize();
return result;
}
bool AndroidConfig::isConnected(const QString &serialNumber) const bool AndroidConfig::isConnected(const QString &serialNumber) const
{ {
QVector<AndroidDeviceInfo> devices = connectedDevices(); QVector<AndroidDeviceInfo> devices = connectedDevices();
@@ -716,14 +676,6 @@ QStringList AndroidConfig::getAbis(const QString &adbToolPath, const QString &de
return result; return result;
} }
SdkPlatform AndroidConfig::highestAndroidSdk() const
{
updateAvailableSdkPlatforms();
if (m_availableSdkPlatforms.isEmpty())
return SdkPlatform();
return m_availableSdkPlatforms.first();
}
QString AndroidConfig::bestNdkPlatformMatch(int target) const QString AndroidConfig::bestNdkPlatformMatch(int target) const
{ {
target = std::max(9, target); target = std::max(9, target);
@@ -743,7 +695,6 @@ FileName AndroidConfig::sdkLocation() const
void AndroidConfig::setSdkLocation(const FileName &sdkLocation) void AndroidConfig::setSdkLocation(const FileName &sdkLocation)
{ {
m_sdkLocation = sdkLocation; m_sdkLocation = sdkLocation;
m_availableSdkPlatformsUpToDate = false;
} }
QVersionNumber AndroidConfig::sdkToolsVersion() const QVersionNumber AndroidConfig::sdkToolsVersion() const
@@ -836,7 +787,6 @@ FileName AndroidConfig::openJDKLocation() const
void AndroidConfig::setOpenJDKLocation(const FileName &openJDKLocation) void AndroidConfig::setOpenJDKLocation(const FileName &openJDKLocation)
{ {
m_openJDKLocation = openJDKLocation; m_openJDKLocation = openJDKLocation;
m_availableSdkPlatformsUpToDate = false;
} }
FileName AndroidConfig::keystoreLocation() const FileName AndroidConfig::keystoreLocation() const
@@ -1129,6 +1079,11 @@ const AndroidConfig &AndroidConfigurations::currentConfig()
return m_instance->m_config; // ensure that m_instance is initialized return m_instance->m_config; // ensure that m_instance is initialized
} }
AndroidSdkManager *AndroidConfigurations::sdkManager()
{
return m_instance->m_sdkManager.get();
}
AndroidConfigurations *AndroidConfigurations::instance() AndroidConfigurations *AndroidConfigurations::instance()
{ {
return m_instance; return m_instance;
@@ -1143,7 +1098,8 @@ void AndroidConfigurations::save()
} }
AndroidConfigurations::AndroidConfigurations(QObject *parent) AndroidConfigurations::AndroidConfigurations(QObject *parent)
: QObject(parent) : QObject(parent),
m_sdkManager(new AndroidSdkManager(m_config))
{ {
load(); load();
@@ -1155,6 +1111,11 @@ AndroidConfigurations::AndroidConfigurations(QObject *parent)
m_instance = this; m_instance = this;
} }
AndroidConfigurations::~AndroidConfigurations()
{
}
static FileName javaHomeForJavac(const FileName &location) static FileName javaHomeForJavac(const FileName &location)
{ {
QFileInfo fileInfo = location.toFileInfo(); QFileInfo fileInfo = location.toFileInfo();
@@ -1265,13 +1226,4 @@ void AndroidConfigurations::updateAndroidDevice()
AndroidConfigurations *AndroidConfigurations::m_instance = 0; AndroidConfigurations *AndroidConfigurations::m_instance = 0;
bool SdkPlatform::operator <(const SdkPlatform &other) const
{
if (apiLevel != other.apiLevel)
return apiLevel > other.apiLevel;
if (name != other.name)
return name < other.name;
return false;
}
} // namespace Android } // namespace Android

View File

@@ -26,7 +26,7 @@
#pragma once #pragma once
#include "android_global.h" #include "android_global.h"
#include "androidsdkpackage.h"
#include <projectexplorer/toolchain.h> #include <projectexplorer/toolchain.h>
#include <QObject> #include <QObject>
@@ -52,7 +52,9 @@ class Project;
namespace Utils { class Environment; } namespace Utils { class Environment; }
namespace Android { namespace Android {
class AndroidPlugin; class AndroidPlugin;
namespace Internal { class AndroidSdkManager; }
class AndroidDeviceInfo class AndroidDeviceInfo
{ {
@@ -74,31 +76,16 @@ public:
}; };
using AndroidDeviceInfoList = QList<AndroidDeviceInfo>; using AndroidDeviceInfoList = QList<AndroidDeviceInfo>;
//! Defines an Android system image. class CreateAvdInfo
class SystemImage
{ {
public: public:
bool isValid() const { return (apiLevel != -1) && !abiName.isEmpty(); } bool isValid() const { return sdkPlatform && sdkPlatform->isValid() && !name.isEmpty(); }
int apiLevel = -1; const SdkPlatform *sdkPlatform = nullptr;
QString abiName;
QString package;
Utils::FileName installedLocation;
};
using SystemImageList = QList<SystemImage>;
class SdkPlatform
{
public:
bool isValid() const { return !name.isEmpty() && apiLevel != -1; }
bool operator <(const SdkPlatform &other) const;
int apiLevel = -1;
QString name; QString name;
QString package; QString abi;
Utils::FileName installedLocation; int sdcardSize = 0;
SystemImageList systemImages; QString error; // only used in the return value of createAVD
}; };
using SdkPlatformList = QList<SdkPlatform>;
class ANDROID_EXPORT AndroidConfig class ANDROID_EXPORT AndroidConfig
{ {
@@ -106,9 +93,8 @@ public:
void load(const QSettings &settings); void load(const QSettings &settings);
void save(QSettings &settings) const; void save(QSettings &settings) const;
static QStringList apiLevelNamesFor(const QList<SdkPlatform> &platforms); static QStringList apiLevelNamesFor(const SdkPlatformList &platforms);
static QString apiLevelNameFor(const SdkPlatform &platform); static QString apiLevelNameFor(const SdkPlatform *platform);
QList<SdkPlatform> sdkTargets(int minApiLevel = 0) const;
Utils::FileName sdkLocation() const; Utils::FileName sdkLocation() const;
void setSdkLocation(const Utils::FileName &sdkLocation); void setSdkLocation(const Utils::FileName &sdkLocation);
@@ -147,19 +133,6 @@ public:
Utils::FileName keytoolPath() const; Utils::FileName keytoolPath() const;
class CreateAvdInfo
{
public:
bool isValid() const { return target.isValid() && !name.isEmpty(); }
SdkPlatform target;
QString name;
QString abi;
int sdcardSize = 0;
QString error; // only used in the return value of createAVD
};
CreateAvdInfo gatherCreateAVDInfo(QWidget *parent, int minApiLevel = 0, QString targetArch = QString()) const;
QVector<AndroidDeviceInfo> connectedDevices(QString *error = 0) const; QVector<AndroidDeviceInfo> connectedDevices(QString *error = 0) const;
static QVector<AndroidDeviceInfo> connectedDevices(const QString &adbToolPath, QString *error = 0); static QVector<AndroidDeviceInfo> connectedDevices(const QString &adbToolPath, QString *error = 0);
@@ -175,7 +148,6 @@ public:
OpenGl getOpenGLEnabled(const QString &emulator) const; OpenGl getOpenGLEnabled(const QString &emulator) const;
bool isConnected(const QString &serialNumber) const; bool isConnected(const QString &serialNumber) const;
SdkPlatform highestAndroidSdk() const;
private: private:
static QString getDeviceProperty(const QString &adbToolPath, const QString &device, const QString &property); static QString getDeviceProperty(const QString &adbToolPath, const QString &device, const QString &property);
@@ -189,7 +161,6 @@ private:
bool isBootToQt(const QString &device) const; bool isBootToQt(const QString &device) const;
static QString getAvdName(const QString &serialnumber); static QString getAvdName(const QString &serialnumber);
void updateAvailableSdkPlatforms() const;
void updateNdkInformation() const; void updateNdkInformation() const;
Utils::FileName m_sdkLocation; Utils::FileName m_sdkLocation;
@@ -201,9 +172,6 @@ private:
bool m_automaticKitCreation = true; bool m_automaticKitCreation = true;
//caches //caches
mutable bool m_availableSdkPlatformsUpToDate = false;
mutable SdkPlatformList m_availableSdkPlatforms;
mutable bool m_NdkInformationUpToDate = false; mutable bool m_NdkInformationUpToDate = false;
mutable QString m_toolchainHost; mutable QString m_toolchainHost;
mutable QVector<int> m_availableNdkPlatforms; mutable QVector<int> m_availableNdkPlatforms;
@@ -218,6 +186,7 @@ class ANDROID_EXPORT AndroidConfigurations : public QObject
public: public:
static const AndroidConfig &currentConfig(); static const AndroidConfig &currentConfig();
static Internal::AndroidSdkManager *sdkManager();
static void setConfig(const AndroidConfig &config); static void setConfig(const AndroidConfig &config);
static AndroidConfigurations *instance(); static AndroidConfigurations *instance();
@@ -236,16 +205,17 @@ signals:
private: private:
AndroidConfigurations(QObject *parent); AndroidConfigurations(QObject *parent);
~AndroidConfigurations();
void load(); void load();
void save(); void save();
static AndroidConfigurations *m_instance; static AndroidConfigurations *m_instance;
AndroidConfig m_config; AndroidConfig m_config;
std::unique_ptr<Internal::AndroidSdkManager> m_sdkManager;
QMap<ProjectExplorer::Project *, QMap<QString, QString> > m_defaultDeviceForAbi; QMap<ProjectExplorer::Project *, QMap<QString, QString> > m_defaultDeviceForAbi;
bool m_force32bit; bool m_force32bit;
}; };
} // namespace Android } // namespace Android
Q_DECLARE_METATYPE(Android::SdkPlatform)

View File

@@ -26,6 +26,7 @@
#include "androiddevicedialog.h" #include "androiddevicedialog.h"
#include "androidmanager.h" #include "androidmanager.h"
#include "androidavdmanager.h" #include "androidavdmanager.h"
#include "avddialog.h"
#include "ui_androiddevicedialog.h" #include "ui_androiddevicedialog.h"
#include <utils/environment.h> #include <utils/environment.h>
@@ -580,9 +581,10 @@ void AndroidDeviceDialog::devicesRefreshed()
void AndroidDeviceDialog::createAvd() void AndroidDeviceDialog::createAvd()
{ {
m_ui->createAVDButton->setEnabled(false); m_ui->createAVDButton->setEnabled(false);
AndroidConfig::CreateAvdInfo info = AndroidConfigurations::currentConfig().gatherCreateAVDInfo(this, m_apiLevel, m_abi); CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, AndroidConfigurations::sdkManager(),
m_apiLevel, m_abi);
if (!info.target.isValid()) { if (!info.isValid()) {
m_ui->createAVDButton->setEnabled(true); m_ui->createAVDButton->setEnabled(true);
return; return;
} }
@@ -593,7 +595,7 @@ void AndroidDeviceDialog::createAvd()
void AndroidDeviceDialog::avdAdded() void AndroidDeviceDialog::avdAdded()
{ {
m_ui->createAVDButton->setEnabled(true); m_ui->createAVDButton->setEnabled(true);
AndroidConfig::CreateAvdInfo info = m_futureWatcherAddDevice.result(); CreateAvdInfo info = m_futureWatcherAddDevice.result();
if (!info.error.isEmpty()) { if (!info.error.isEmpty()) {
QMessageBox::critical(this, QApplication::translate("AndroidConfig", "Error Creating AVD"), info.error); QMessageBox::critical(this, QApplication::translate("AndroidConfig", "Error Creating AVD"), info.error);
return; return;

View File

@@ -79,7 +79,7 @@ private:
QString m_defaultDevice; QString m_defaultDevice;
std::unique_ptr<AndroidAvdManager> m_avdManager; std::unique_ptr<AndroidAvdManager> m_avdManager;
QVector<AndroidDeviceInfo> m_connectedDevices; QVector<AndroidDeviceInfo> m_connectedDevices;
QFutureWatcher<AndroidConfig::CreateAvdInfo> m_futureWatcherAddDevice; QFutureWatcher<CreateAvdInfo> m_futureWatcherAddDevice;
QFutureWatcher<AndroidDeviceInfoList> m_futureWatcherRefreshDevices; QFutureWatcher<AndroidDeviceInfoList> m_futureWatcherRefreshDevices;
}; };

View File

@@ -35,6 +35,7 @@
#include "androidqtversion.h" #include "androidqtversion.h"
#include "androidbuildapkstep.h" #include "androidbuildapkstep.h"
#include "androidavdmanager.h" #include "androidavdmanager.h"
#include "androidsdkmanager.h"
#include <coreplugin/documentmanager.h> #include <coreplugin/documentmanager.h>
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
@@ -174,7 +175,8 @@ QString AndroidManager::buildTargetSDK(ProjectExplorer::Target *target)
if (androidBuildApkStep) if (androidBuildApkStep)
return androidBuildApkStep->buildTargetSdk(); return androidBuildApkStep->buildTargetSdk();
QString fallback = AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk()); QString fallback = AndroidConfig::apiLevelNameFor(
AndroidConfigurations::sdkManager()->latestAndroidSdkPlatform());
return fallback; return fallback;
} }

View File

@@ -48,13 +48,26 @@ namespace Internal {
const QVersionNumber sdkManagerIntroVersion(25, 3 ,0); const QVersionNumber sdkManagerIntroVersion(25, 3 ,0);
const char installLocationKey[] = "Installed Location:"; const char installLocationKey[] = "Installed Location:";
const char apiLevelPropertyKey[] = "AndroidVersion.ApiLevel"; const char revisionKey[] = "Version:";
const char abiPropertyKey[] = "SystemImage.Abi"; const char descriptionKey[] = "Description:";
const int sdkManagerCmdTimeoutS = 60; const int sdkManagerCmdTimeoutS = 60;
using namespace Utils; using namespace Utils;
int platformNameToApiLevel(const QString &platformName)
{
int apiLevel = -1;
QRegularExpression re("(android-)(?<apiLevel>[0-9]{1,})",
QRegularExpression::CaseInsensitiveOption);
QRegularExpressionMatch match = re.match(platformName);
if (match.hasMatch()) {
QString apiLevelStr = match.captured("apiLevel");
apiLevel = apiLevelStr.toInt();
}
return apiLevel;
}
/*! /*!
Parses the \a line for a [spaces]key[spaces]value[spaces] pattern and returns Parses the \a line for a [spaces]key[spaces]value[spaces] pattern and returns
\c true if \a key is found, false otherwise. Result is copied into \a value. \c true if \a key is found, false otherwise. Result is copied into \a value.
@@ -75,7 +88,7 @@ static bool valueForKey(QString key, const QString &line, QString *value = nullp
\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 sdkManagerCommand(const AndroidConfig config, const QStringList &args, QString *output, static bool sdkManagerCommand(const AndroidConfig &config, const QStringList &args, QString *output,
int timeout = sdkManagerCmdTimeoutS) int timeout = sdkManagerCmdTimeoutS)
{ {
QString sdkManagerToolPath = config.sdkManagerToolPath().toString(); QString sdkManagerToolPath = config.sdkManagerToolPath().toString();
@@ -88,6 +101,29 @@ static bool sdkManagerCommand(const AndroidConfig config, const QStringList &arg
return response.result == SynchronousProcessResponse::Finished; return response.result == SynchronousProcessResponse::Finished;
} }
class AndroidSdkManagerPrivate
{
public:
AndroidSdkManagerPrivate(AndroidSdkManager &sdkManager, const AndroidConfig &config);
~AndroidSdkManagerPrivate();
AndroidSdkPackageList filteredPackages(AndroidSdkPackage::PackageState state,
AndroidSdkPackage::PackageType type,
bool forceUpdate = false);
const AndroidSdkPackageList &allPackages(bool forceUpdate = false);
void refreshSdkPackages(bool forceReload = false);
private:
void reloadSdkPackages();
void clearPackages();
AndroidSdkManager &m_sdkManager;
const AndroidConfig &m_config;
AndroidSdkPackageList m_allPackages;
FileName lastSdkManagerPath;
};
/*! /*!
\class SdkManagerOutputParser \class SdkManagerOutputParser
\brief The SdkManagerOutputParser class is a helper class to parse the output of the \c sdkmanager \brief The SdkManagerOutputParser class is a helper class to parse the output of the \c sdkmanager
@@ -108,19 +144,20 @@ public:
SectionMarkers = InstalledPackagesMarker | AvailablePackagesMarkers | AvailableUpdatesMarker SectionMarkers = InstalledPackagesMarker | AvailablePackagesMarkers | AvailableUpdatesMarker
}; };
SdkManagerOutputParser(AndroidSdkPackageList &container) : m_packages(container) {}
void parsePackageListing(const QString &output); void parsePackageListing(const QString &output);
SdkPlatformList m_installedPlatforms; AndroidSdkPackageList &m_packages;
private: private:
void compileData(); void compilePackageAssociations();
void parsePackageData(MarkerTag packageMarker, const QStringList &data); void parsePackageData(MarkerTag packageMarker, const QStringList &data);
bool parsePlatform(const QStringList &data, SdkPlatform *platform) const; AndroidSdkPackage *parsePlatform(const QStringList &data) const;
bool parseSystemImage(const QStringList &data, SystemImage *image); QPair<SystemImage *, int> parseSystemImage(const QStringList &data) const;
MarkerTag parseMarkers(const QString &line); MarkerTag parseMarkers(const QString &line);
MarkerTag m_currentSection = MarkerTag::None; MarkerTag m_currentSection = MarkerTag::None;
SystemImageList m_installedSystemImages; QHash<AndroidSdkPackage *, int> m_systemImages;
}; };
const std::map<SdkManagerOutputParser::MarkerTag, const char *> markerTags { const std::map<SdkManagerOutputParser::MarkerTag, const char *> markerTags {
@@ -131,9 +168,9 @@ const std::map<SdkManagerOutputParser::MarkerTag, const char *> markerTags {
{SdkManagerOutputParser::MarkerTag::SystemImageMarker, "system-images"} {SdkManagerOutputParser::MarkerTag::SystemImageMarker, "system-images"}
}; };
AndroidSdkManager::AndroidSdkManager(const AndroidConfig &config): AndroidSdkManager::AndroidSdkManager(const AndroidConfig &config, QObject *parent):
m_config(config), QObject(parent),
m_parser(new SdkManagerOutputParser) m_d(new AndroidSdkManagerPrivate(*this, config))
{ {
} }
@@ -142,21 +179,61 @@ AndroidSdkManager::~AndroidSdkManager()
} }
SdkPlatformList AndroidSdkManager::availableSdkPlatforms(bool *ok) SdkPlatformList AndroidSdkManager::installedSdkPlatforms()
{ {
bool success = false; AndroidSdkPackageList list = m_d->filteredPackages(AndroidSdkPackage::Installed,
if (m_config.sdkToolsVersion() < sdkManagerIntroVersion) { AndroidSdkPackage::SdkPlatformPackage);
AndroidToolManager toolManager(m_config); return Utils::transform(list, [](AndroidSdkPackage *p) {
return toolManager.availableSdkPlatforms(ok); return static_cast<SdkPlatform *>(p);
});
}
const AndroidSdkPackageList &AndroidSdkManager::allSdkPackages()
{
return m_d->allPackages();
}
AndroidSdkPackageList AndroidSdkManager::availableSdkPackages()
{
return m_d->filteredPackages(AndroidSdkPackage::Available, AndroidSdkPackage::AnyValidType);
}
AndroidSdkPackageList AndroidSdkManager::installedSdkPackages()
{
return m_d->filteredPackages(AndroidSdkPackage::Installed, AndroidSdkPackage::AnyValidType);
}
SdkPlatform *AndroidSdkManager::latestAndroidSdkPlatform(AndroidSdkPackage::PackageState state)
{
SdkPlatform *result = nullptr;
const AndroidSdkPackageList list = m_d->filteredPackages(state,
AndroidSdkPackage::SdkPlatformPackage);
for (AndroidSdkPackage *p : list) {
auto platform = static_cast<SdkPlatform *>(p);
if (!result || result->apiLevel() < platform->apiLevel())
result = platform;
} }
return result;
}
QString packageListing; SdkPlatformList AndroidSdkManager::filteredSdkPlatforms(int minApiLevel,
if (sdkManagerCommand(m_config, QStringList({"--list", "--verbose"}), &packageListing)) AndroidSdkPackage::PackageState state)
m_parser->parsePackageListing(packageListing); {
const AndroidSdkPackageList list = m_d->filteredPackages(state,
AndroidSdkPackage::SdkPlatformPackage);
if (ok) SdkPlatformList result;
*ok = success; for (AndroidSdkPackage *p : list) {
return m_parser->m_installedPlatforms; auto platform = static_cast<SdkPlatform *>(p);
if (platform && platform->apiLevel() >= minApiLevel)
result << platform;
}
return result;
}
void AndroidSdkManager::reloadPackages(bool forceReload)
{
m_d->refreshSdkPackages(forceReload);
} }
void SdkManagerOutputParser::parsePackageListing(const QString &output) void SdkManagerOutputParser::parsePackageListing(const QString &output)
@@ -173,10 +250,9 @@ void SdkManagerOutputParser::parsePackageListing(const QString &output)
} }
}; };
QRegularExpression delimiters("[\n\r]"); QRegularExpression delimiters("[\\n\\r]");
foreach (QString outputLine, output.split(delimiters)) { foreach (QString outputLine, output.split(delimiters)) {
MarkerTag marker = parseMarkers(outputLine.trimmed()); MarkerTag marker = parseMarkers(outputLine.trimmed());
if (marker & SectionMarkers) { if (marker & SectionMarkers) {
// Section marker found. Update the current section being parsed. // Section marker found. Update the current section being parsed.
m_currentSection = marker; m_currentSection = marker;
@@ -211,20 +287,27 @@ void SdkManagerOutputParser::parsePackageListing(const QString &output)
packageData << outputLine; packageData << outputLine;
} }
} }
compileData(); compilePackageAssociations();
Utils::sort(m_installedPlatforms);
} }
void SdkManagerOutputParser::compileData() void SdkManagerOutputParser::compilePackageAssociations()
{ {
// Associate the system images with sdk platforms. // Associate the system images with sdk platforms.
for (auto &image : m_installedSystemImages) { auto imageItr = m_systemImages.cbegin();
auto findPlatfom = [image](const SdkPlatform &platform) { while (imageItr != m_systemImages.cend()) {
return platform.apiLevel == image.apiLevel; auto findPlatform = [imageItr](const AndroidSdkPackage *p) {
const SdkPlatform *platform = nullptr;
if (p->type() == AndroidSdkPackage::SdkPlatformPackage)
platform = static_cast<const SdkPlatform*>(p);
return platform && platform->apiLevel() == imageItr.value();
}; };
auto itr = std::find_if(m_installedPlatforms.begin(), m_installedPlatforms.end(), findPlatfom); auto itr = std::find_if(m_packages.begin(), m_packages.end(),
if (itr != m_installedPlatforms.end()) findPlatform);
itr->systemImages.append(image); if (itr != m_packages.end()) {
SdkPlatform *platform = static_cast<SdkPlatform*>(*itr);
platform->addSystemImage(static_cast<SystemImage *>(imageItr.key()));
}
++imageItr;
} }
} }
@@ -235,24 +318,23 @@ void SdkManagerOutputParser::parsePackageData(MarkerTag packageMarker, const QSt
if (m_currentSection != MarkerTag::InstalledPackagesMarker) if (m_currentSection != MarkerTag::InstalledPackagesMarker)
return; // For now, only interested in installed packages. return; // For now, only interested in installed packages.
AndroidSdkPackage *package = nullptr;
switch (packageMarker) { switch (packageMarker) {
case MarkerTag::PlatformMarker: case MarkerTag::PlatformMarker:
{ package = parsePlatform(data);
SdkPlatform platform; if (package)
if (parsePlatform(data, &platform)) m_packages.append(package);
m_installedPlatforms.append(platform);
else
qCDebug(sdkManagerLog) << "Platform: Parsing failed: " << data;
}
break; break;
case MarkerTag::SystemImageMarker: case MarkerTag::SystemImageMarker:
{ {
SystemImage image; QPair<SystemImage *, int> result = parseSystemImage(data);
if (parseSystemImage(data, &image)) if (result.first) {
m_installedSystemImages.append(image); m_systemImages[result.first] = result.second;
else package = result.first;
} else {
qCDebug(sdkManagerLog) << "System Image: Parsing failed: " << data; qCDebug(sdkManagerLog) << "System Image: Parsing failed: " << data;
}
} }
break; break;
@@ -260,71 +342,118 @@ void SdkManagerOutputParser::parsePackageData(MarkerTag packageMarker, const QSt
qCDebug(sdkManagerLog) << "Unhandled package: " << markerTags.at(packageMarker); qCDebug(sdkManagerLog) << "Unhandled package: " << markerTags.at(packageMarker);
break; break;
} }
}
bool SdkManagerOutputParser::parsePlatform(const QStringList &data, SdkPlatform *platform) const if (package) {
{ switch (m_currentSection) {
QTC_ASSERT(platform && !data.isEmpty(), return false); case MarkerTag::InstalledPackagesMarker:
package->setState(AndroidSdkPackage::Installed);
QStringList parts = data.at(0).split(';'); break;
if (parts.count() < 2) { case MarkerTag::AvailablePackagesMarkers:
qCDebug(sdkManagerLog) << "Platform: Unexpected header: "<< data; case MarkerTag::AvailableUpdatesMarker:
return false; package->setState(AndroidSdkPackage::Available);
} break;
platform->name = parts[1]; default:
platform->package = data.at(0); qCDebug(sdkManagerLog) << "Invalid section marker: " << markerTags.at(m_currentSection);
break;
foreach (QString line, data) {
QString value;
if (valueForKey(installLocationKey, line, &value))
platform->installedLocation = Utils::FileName::fromString(value);
}
int apiLevel = AndroidManager::findApiLevel(platform->installedLocation);
if (apiLevel != -1)
platform->apiLevel = apiLevel;
else
qCDebug(sdkManagerLog) << "Platform: Can not parse api level: "<< data;
return apiLevel != -1;
}
bool SdkManagerOutputParser::parseSystemImage(const QStringList &data, SystemImage *image)
{
QTC_ASSERT(image && !data.isEmpty(), return false);
QStringList parts = data.at(0).split(';');
QTC_ASSERT(!data.isEmpty() && parts.count() >= 4,
qCDebug(sdkManagerLog) << "System Image: Unexpected header: " << data);
image->package = data.at(0);
foreach (QString line, data) {
QString value;
if (valueForKey(installLocationKey, line, &value))
image->installedLocation = Utils::FileName::fromString(value);
}
Utils::FileName propertiesPath = image->installedLocation;
propertiesPath.appendPath("/source.properties");
if (propertiesPath.exists()) {
// Installed System Image.
QSettings imageProperties(propertiesPath.toString(), QSettings::IniFormat);
bool validApiLevel = false;
image->apiLevel = imageProperties.value(apiLevelPropertyKey).toInt(&validApiLevel);
if (!validApiLevel) {
qCDebug(sdkManagerLog) << "System Image: Can not parse api level: "<< data;
return false;
} }
image->abiName = imageProperties.value(abiPropertyKey).toString(); }
} else if (parts.count() >= 4){ }
image->apiLevel = parts[1].section('-', 1, 1).toInt();
image->abiName = parts[3]; AndroidSdkPackage *SdkManagerOutputParser::parsePlatform(const QStringList &data) const
{
QTC_ASSERT(!data.isEmpty(), qCDebug(sdkManagerLog) << "Platform: Empty input"; return nullptr);
QStringList parts = data.at(0).split(';');
QTC_ASSERT(parts.count() >= 2,
qCDebug(sdkManagerLog) << "Platform: Unexpected header:"<< data; return nullptr);
int apiLevel = platformNameToApiLevel(parts.at(1));
if (apiLevel == -1) {
qCDebug(sdkManagerLog) << "Platform: Can not parse api level:"<< data;
return nullptr;
}
QVersionNumber revision;
QString description;
Utils::FileName installedLocation;
foreach (QString line, data) {
QString value;
if (valueForKey(installLocationKey, line, &value)) {
installedLocation = Utils::FileName::fromString(value);
continue;
}
if (valueForKey(revisionKey, line, &value)) {
revision = QVersionNumber::fromString(value);
continue;
}
if (valueForKey(descriptionKey, line, &value)) {
description = value;
continue;
}
}
SdkPlatform *platform = nullptr;
if (!revision.isNull() && apiLevel != -1) {
platform = new SdkPlatform(revision, data.at(0), apiLevel);
platform->setDescriptionText(description);
platform->setInstalledLocation(installedLocation);
} else {
qCDebug(sdkManagerLog) << "Platform: Parsing failed. Minimum required data unavailable:"
<< data;
}
return platform;
}
QPair<SystemImage *, int> SdkManagerOutputParser::parseSystemImage(const QStringList &data) const
{
QPair <SystemImage *, int> result(nullptr, -1);
QTC_ASSERT(!data.isEmpty(),
qCDebug(sdkManagerLog) << "System Image: Empty input"; return result);
QStringList parts = data.at(0).split(';');
QTC_ASSERT(parts.count() >= 4,
qCDebug(sdkManagerLog) << "System Image: Unexpected header:" << data; return result);
int apiLevel = platformNameToApiLevel(parts.at(1));
if (apiLevel == -1) {
qCDebug(sdkManagerLog) << "System Image: Can not parse api level:"<< data;
return result;
}
QVersionNumber revision;
QString description;
Utils::FileName installedLocation;
foreach (QString line, data) {
QString value;
if (valueForKey(installLocationKey, line, &value)) {
installedLocation = Utils::FileName::fromString(value);
continue;
}
if (valueForKey(revisionKey, line, &value)) {
revision = QVersionNumber::fromString(value);
continue;
}
if (valueForKey(descriptionKey, line, &value)) {
description = value;
continue;
}
}
if (!revision.isNull()) {
auto image = new SystemImage(revision, data.at(0), parts.at(3));
image->setInstalledLocation(installedLocation);
image->setDisplayText(description);
image->setDescriptionText(description);
result = qMakePair(image, apiLevel);
} else { } else {
qCDebug(sdkManagerLog) << "System Image: Can not parse: "<< data; qCDebug(sdkManagerLog) << "System Image: Can not parse: "<< data;
return false;
} }
return result;
return true;
} }
SdkManagerOutputParser::MarkerTag SdkManagerOutputParser::parseMarkers(const QString &line) SdkManagerOutputParser::MarkerTag SdkManagerOutputParser::parseMarkers(const QString &line)
@@ -340,5 +469,79 @@ SdkManagerOutputParser::MarkerTag SdkManagerOutputParser::parseMarkers(const QSt
return None; return None;
} }
AndroidSdkManagerPrivate::AndroidSdkManagerPrivate(AndroidSdkManager &sdkManager,
const AndroidConfig &config):
m_sdkManager(sdkManager),
m_config(config)
{
}
AndroidSdkManagerPrivate::~AndroidSdkManagerPrivate()
{
clearPackages();
}
AndroidSdkPackageList
AndroidSdkManagerPrivate::filteredPackages(AndroidSdkPackage::PackageState state,
AndroidSdkPackage::PackageType type, bool forceUpdate)
{
refreshSdkPackages(forceUpdate);
return Utils::filtered(m_allPackages, [state, type](const AndroidSdkPackage *p) {
return p->state() & state && p->type() & type;
});
}
const AndroidSdkPackageList &AndroidSdkManagerPrivate::allPackages(bool forceUpdate)
{
refreshSdkPackages(forceUpdate);
return m_allPackages;
}
void AndroidSdkManagerPrivate::reloadSdkPackages()
{
m_sdkManager.packageReloadBegin();
clearPackages();
lastSdkManagerPath = m_config.sdkManagerToolPath();
if (m_config.sdkToolsVersion().isNull()) {
// Configuration has invalid sdk path or corrupt installation.
m_sdkManager.packageReloadFinished();
return;
}
if (m_config.sdkToolsVersion() < sdkManagerIntroVersion) {
// Old Sdk tools.
AndroidToolManager toolManager(m_config);
auto toAndroidSdkPackages = [](SdkPlatform *p) -> AndroidSdkPackage *{
return p;
};
m_allPackages = Utils::transform(toolManager.availableSdkPlatforms(), toAndroidSdkPackages);
} else {
QString packageListing;
if (sdkManagerCommand(m_config, QStringList({"--list", "--verbose"}), &packageListing)) {
SdkManagerOutputParser parser(m_allPackages);
parser.parsePackageListing(packageListing);
}
}
m_sdkManager.packageReloadFinished();
}
void AndroidSdkManagerPrivate::refreshSdkPackages(bool forceReload)
{
// Sdk path changed. Updated packages.
// QTC updates the package listing only
if (m_config.sdkManagerToolPath() != lastSdkManagerPath || forceReload)
reloadSdkPackages();
}
void AndroidSdkManagerPrivate::clearPackages()
{
for (AndroidSdkPackage *p : m_allPackages)
delete p;
m_allPackages.clear();
}
} // namespace Internal } // namespace Internal
} // namespace Android } // namespace Android

View File

@@ -25,26 +25,46 @@
#pragma once #pragma once
#include "utils/fileutils.h" #include "utils/fileutils.h"
#include "androidconfigurations.h" #include "androidsdkpackage.h"
#include <QObject>
#include <memory> #include <memory>
namespace Android { namespace Android {
class AndroidConfig;
namespace Internal { namespace Internal {
class SdkManagerOutputParser; class AndroidSdkManagerPrivate;
class AndroidSdkManager class AndroidSdkManager : public QObject
{ {
Q_OBJECT
public: public:
AndroidSdkManager(const AndroidConfig &config); AndroidSdkManager(const AndroidConfig &config, QObject *parent = nullptr);
~AndroidSdkManager(); ~AndroidSdkManager();
SdkPlatformList availableSdkPlatforms(bool *ok = nullptr); SdkPlatformList installedSdkPlatforms();
const AndroidSdkPackageList &allSdkPackages();
AndroidSdkPackageList availableSdkPackages();
AndroidSdkPackageList installedSdkPackages();
SdkPlatform *latestAndroidSdkPlatform(AndroidSdkPackage::PackageState state
= AndroidSdkPackage::Installed);
SdkPlatformList filteredSdkPlatforms(int minApiLevel,
AndroidSdkPackage::PackageState state
= AndroidSdkPackage::Installed);
void reloadPackages(bool forceReload = false);
signals:
void packageReloadBegin();
void packageReloadFinished();
private: private:
const AndroidConfig &m_config; std::unique_ptr<AndroidSdkManagerPrivate> m_d;
std::unique_ptr<SdkManagerOutputParser> m_parser; friend class AndroidSdkManagerPrivate;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -0,0 +1,193 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "androidsdkpackage.h"
namespace Android {
AndroidSdkPackage::AndroidSdkPackage(QVersionNumber version, QString sdkStylePathStr,
QObject *parent) :
QObject(parent),
m_revision(version),
m_sdkStylePath(sdkStylePathStr)
{
}
bool AndroidSdkPackage::operator <(const AndroidSdkPackage &other) const
{
if (typeid(*this) != typeid(other))
return type() < other.type();
return displayText() < other.displayText();
}
QString AndroidSdkPackage::displayText() const
{
return m_displayText;
}
QString AndroidSdkPackage::descriptionText() const
{
return m_descriptionText;
}
const QVersionNumber &AndroidSdkPackage::revision() const
{
return m_revision;
}
AndroidSdkPackage::PackageState AndroidSdkPackage::state() const
{
return m_state;
}
const QString &AndroidSdkPackage::sdkStylePath() const
{
return m_sdkStylePath;
}
const Utils::FileName &AndroidSdkPackage::installedLocation() const
{
return m_installedLocation;
}
void AndroidSdkPackage::setDisplayText(const QString &str)
{
m_displayText = str;
}
void AndroidSdkPackage::setDescriptionText(const QString &str)
{
m_descriptionText = str;
}
void AndroidSdkPackage::setState(AndroidSdkPackage::PackageState state)
{
m_state = state;
}
void AndroidSdkPackage::setInstalledLocation(const Utils::FileName &path)
{
m_installedLocation = path;
if (m_installedLocation.exists())
updatePackageDetails();
}
void AndroidSdkPackage::updatePackageDetails()
{
}
SystemImage::SystemImage(QVersionNumber version, QString sdkStylePathStr, QString abi,
SdkPlatform *platform):
AndroidSdkPackage(version, sdkStylePathStr, platform),
m_platform(platform),
m_abiName(abi)
{
}
bool SystemImage::isValid() const
{
return m_platform && m_platform->isValid();
}
AndroidSdkPackage::PackageType SystemImage::type() const
{
return SystemImagePackage;
}
const QString &SystemImage::abiName() const
{
return m_abiName;
}
const SdkPlatform *SystemImage::platform() const
{
return m_platform.data();
}
void SystemImage::setPlatform(SdkPlatform *platform)
{
m_platform = platform;
}
SdkPlatform::SdkPlatform(QVersionNumber version, QString sdkStylePathStr, int api, QObject *parent) :
AndroidSdkPackage(version, sdkStylePathStr, parent),
m_apiLevel(api)
{
setDisplayText(QString("android-%1")
.arg(m_apiLevel != -1 ? QString::number(m_apiLevel) : "Unknown"));
}
SdkPlatform::~SdkPlatform()
{
for (SystemImage *image : m_systemImages)
delete image;
m_systemImages.clear();
}
bool SdkPlatform::isValid() const
{
return m_apiLevel != -1;
}
AndroidSdkPackage::PackageType SdkPlatform::type() const
{
return SdkPlatformPackage;
}
bool SdkPlatform::operator <(const AndroidSdkPackage &other) const
{
if (typeid(*this) != typeid(other))
return AndroidSdkPackage::operator <(other);
const SdkPlatform &platform = static_cast<const SdkPlatform &>(other);
if (platform.m_apiLevel == m_apiLevel)
return AndroidSdkPackage::operator <(other);
return platform.m_apiLevel < m_apiLevel;
}
int SdkPlatform::apiLevel() const
{
return m_apiLevel;
}
QVersionNumber SdkPlatform::version() const
{
return m_version;
}
void SdkPlatform::addSystemImage(SystemImage *image)
{
m_systemImages.append(image);
image->setPlatform(this);
}
const SystemImageList &SdkPlatform::systemImages() const
{
return m_systemImages;
}
} // namespace Android

View File

@@ -0,0 +1,150 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "utils/fileutils.h"
#include <QList>
#include <QObject>
#include <QPointer>
#include <QVersionNumber>
#pragma once
namespace Android {
namespace Internal {
class SdkManagerOutputParser;
class AndroidToolOutputParser;
}
class SdkPlatform;
class SystemImage;
class AndroidSdkPackage : public QObject
{
Q_OBJECT
public:
enum PackageType {
UnknownPackage = 1 << 0,
SdkToolsPackage = 1 << 1,
BuildToolsPackage = 1 << 2,
PlatformToolsPackage = 1 << 3,
SdkPlatformPackage = 1 << 4,
SystemImagePackage = 1 << 5,
AnyValidType = SdkToolsPackage | BuildToolsPackage | PlatformToolsPackage |
SdkPlatformPackage | SystemImagePackage
};
enum PackageState {
Unknown = 1 << 0,
Installed = 1 << 1,
Available = 1 << 2,
AnyValidState = Installed | Available
};
AndroidSdkPackage(QVersionNumber revision, QString sdkStylePathStr, QObject *parent = nullptr);
virtual ~AndroidSdkPackage() { }
virtual bool isValid() const = 0;
virtual PackageType type() const = 0;
virtual bool operator <(const AndroidSdkPackage &other) const;
QString displayText() const;
QString descriptionText() const;
const QVersionNumber &revision() const;
PackageState state() const;
const QString &sdkStylePath() const;
const Utils::FileName &installedLocation() const;
protected:
void setDisplayText(const QString &str);
void setDescriptionText(const QString &str);
void setState(PackageState state);
void setInstalledLocation(const Utils::FileName &path);
virtual void updatePackageDetails();
private:
QString m_displayText;
QString m_descriptionText;
QVersionNumber m_revision;
PackageState m_state = PackageState::Unknown;
QString m_sdkStylePath;
Utils::FileName m_installedLocation;
friend class Internal::SdkManagerOutputParser;
friend class Internal::AndroidToolOutputParser;
};
using AndroidSdkPackageList = QList<AndroidSdkPackage*>;
class SystemImage : public AndroidSdkPackage
{
Q_OBJECT
public:
SystemImage(QVersionNumber revision, QString sdkStylePathStr, QString abi,
SdkPlatform *platform = nullptr);
// AndroidSdkPackage Overrides
bool isValid() const override;
PackageType type() const override;
const QString &abiName() const;
const SdkPlatform *platform() const;
void setPlatform(SdkPlatform *platform);
private:
QPointer<SdkPlatform> m_platform;
QString m_abiName;
};
using SystemImageList = QList<SystemImage*>;
class SdkPlatform : public AndroidSdkPackage
{
Q_OBJECT
public:
SdkPlatform(QVersionNumber revision, QString sdkStylePathStr, int api,
QObject *parent = nullptr);
~SdkPlatform();
// AndroidSdkPackage Overrides
bool isValid() const override;
PackageType type() const override;
bool operator <(const AndroidSdkPackage &other) const override;
int apiLevel() const;
QVersionNumber version() const;
void addSystemImage(SystemImage *image);
const SystemImageList &systemImages() const;
private:
SystemImageList m_systemImages;
int m_apiLevel = -1;
QVersionNumber m_version;
};
using SdkPlatformList = QList<SdkPlatform*>;
} // namespace Android

View File

@@ -31,6 +31,8 @@
#include "androidconstants.h" #include "androidconstants.h"
#include "androidtoolchain.h" #include "androidtoolchain.h"
#include "androidavdmanager.h" #include "androidavdmanager.h"
#include "androidsdkmanager.h"
#include "avddialog.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/environment.h> #include <utils/environment.h>
@@ -212,7 +214,8 @@ AndroidSettingsWidget::AndroidSettingsWidget(QWidget *parent)
: QWidget(parent), : QWidget(parent),
m_ui(new Ui_AndroidSettingsWidget), m_ui(new Ui_AndroidSettingsWidget),
m_androidConfig(AndroidConfigurations::currentConfig()), m_androidConfig(AndroidConfigurations::currentConfig()),
m_avdManager(new AndroidAvdManager(m_androidConfig)) m_avdManager(new AndroidAvdManager(m_androidConfig)),
m_sdkManager(new AndroidSdkManager(m_androidConfig))
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
@@ -390,7 +393,7 @@ void AndroidSettingsWidget::validateSdk()
summaryWidget->setPointValid(BuildToolsInstalledRow, summaryWidget->setPointValid(BuildToolsInstalledRow,
!m_androidConfig.buildToolsVersion().isNull()); !m_androidConfig.buildToolsVersion().isNull());
summaryWidget->setPointValid(PlatformSdkInstalledRow, summaryWidget->setPointValid(PlatformSdkInstalledRow,
!m_androidConfig.sdkTargets().isEmpty()); !m_sdkManager->installedSdkPlatforms().isEmpty());
updateUI(); updateUI();
} }
@@ -412,9 +415,9 @@ void AndroidSettingsWidget::openOpenJDKDownloadUrl()
void AndroidSettingsWidget::addAVD() void AndroidSettingsWidget::addAVD()
{ {
disableAvdControls(); disableAvdControls();
AndroidConfig::CreateAvdInfo info = m_androidConfig.gatherCreateAVDInfo(this); CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, m_sdkManager.get());
if (!info.target.isValid()) { if (!info.isValid()) {
enableAvdControls(); enableAvdControls();
return; return;
} }
@@ -424,7 +427,7 @@ void AndroidSettingsWidget::addAVD()
void AndroidSettingsWidget::avdAdded() void AndroidSettingsWidget::avdAdded()
{ {
AndroidConfig::CreateAvdInfo info = m_futureWatcher.result(); CreateAvdInfo info = m_futureWatcher.result();
if (!info.error.isEmpty()) { if (!info.error.isEmpty()) {
enableAvdControls(); enableAvdControls();
QMessageBox::critical(this, QApplication::translate("AndroidConfig", "Error Creating AVD"), info.error); QMessageBox::critical(this, QApplication::translate("AndroidConfig", "Error Creating AVD"), info.error);

View File

@@ -100,11 +100,12 @@ private:
Ui_AndroidSettingsWidget *m_ui; Ui_AndroidSettingsWidget *m_ui;
AndroidConfig m_androidConfig; AndroidConfig m_androidConfig;
AvdModel m_AVDModel; AvdModel m_AVDModel;
QFutureWatcher<AndroidConfig::CreateAvdInfo> m_futureWatcher; QFutureWatcher<CreateAvdInfo> m_futureWatcher;
QFutureWatcher<AndroidDeviceInfoList> m_virtualDevicesWatcher; QFutureWatcher<AndroidDeviceInfoList> m_virtualDevicesWatcher;
QString m_lastAddedAvd; QString m_lastAddedAvd;
std::unique_ptr<AndroidAvdManager> m_avdManager; std::unique_ptr<AndroidAvdManager> m_avdManager;
std::unique_ptr<AndroidSdkManager> m_sdkManager;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -47,7 +47,7 @@ class AndroidToolOutputParser
{ {
public: public:
void parseTargetListing(const QString &output, const FileName &sdkLocation, void parseTargetListing(const QString &output, const FileName &sdkLocation,
SdkPlatformList *platformList); SdkPlatformList &platformList);
QList<SdkPlatform> m_installedPlatforms; QList<SdkPlatform> m_installedPlatforms;
}; };
@@ -104,7 +104,7 @@ SdkPlatformList AndroidToolManager::availableSdkPlatforms(bool *ok) const
QString targetListing; QString targetListing;
if (androidToolCommand(m_config.androidToolPath(), QStringList({"list", "target"}), if (androidToolCommand(m_config.androidToolPath(), QStringList({"list", "target"}),
androidToolEnvironment(), &targetListing)) { androidToolEnvironment(), &targetListing)) {
m_parser->parseTargetListing(targetListing, m_config.sdkLocation(), &list); m_parser->parseTargetListing(targetListing, m_config.sdkLocation(), list);
success = true; success = true;
} else { } else {
qCDebug(androidToolLog) << "Android tool target listing failed"; qCDebug(androidToolLog) << "Android tool target listing failed";
@@ -121,8 +121,7 @@ void AndroidToolManager::launchAvdManager() const
QProcess::startDetached(m_config.androidToolPath().toString(), QStringList("avd")); QProcess::startDetached(m_config.androidToolPath().toString(), QStringList("avd"));
} }
QFuture<AndroidConfig::CreateAvdInfo> QFuture<CreateAvdInfo> AndroidToolManager::createAvd(CreateAvdInfo info) const
AndroidToolManager::createAvd(AndroidConfig::CreateAvdInfo info) const
{ {
return Utils::runAsync(&AndroidToolManager::createAvdImpl, info, return Utils::runAsync(&AndroidToolManager::createAvdImpl, info,
m_config.androidToolPath(), androidToolEnvironment()); m_config.androidToolPath(), androidToolEnvironment());
@@ -159,15 +158,14 @@ Environment AndroidToolManager::androidToolEnvironment() const
return env; return env;
} }
AndroidConfig::CreateAvdInfo AndroidToolManager::createAvdImpl(AndroidConfig::CreateAvdInfo info, CreateAvdInfo AndroidToolManager::createAvdImpl(CreateAvdInfo info, FileName androidToolPath,
FileName androidToolPath, Environment env)
Environment env)
{ {
QProcess proc; QProcess proc;
proc.setProcessEnvironment(env.toProcessEnvironment()); proc.setProcessEnvironment(env.toProcessEnvironment());
QStringList arguments; QStringList arguments;
arguments << QLatin1String("create") << QLatin1String("avd") arguments << QLatin1String("create") << QLatin1String("avd")
<< QLatin1String("-t") << AndroidConfig::apiLevelNameFor(info.target) << QLatin1String("-t") << AndroidConfig::apiLevelNameFor(info.sdkPlatform)
<< QLatin1String("-n") << info.name << QLatin1String("-n") << info.name
<< QLatin1String("-b") << info.abi; << QLatin1String("-b") << info.abi;
if (info.sdcardSize > 0) if (info.sdcardSize > 0)
@@ -293,24 +291,36 @@ AndroidDeviceInfoList AndroidToolManager::androidVirtualDevices(const Utils::Fil
void AndroidToolOutputParser::parseTargetListing(const QString &output, void AndroidToolOutputParser::parseTargetListing(const QString &output,
const Utils::FileName &sdkLocation, const Utils::FileName &sdkLocation,
SdkPlatformList *platformList) SdkPlatformList &platformList)
{ {
if (!platformList) auto addSystemImage = [](const QStringList& abiList, SdkPlatform *platform) {
return; QTC_ASSERT(platform, return);
auto addSystemImage = [](const QStringList& abiList, SdkPlatform &platform) {
foreach (auto imageAbi, abiList) { foreach (auto imageAbi, abiList) {
SystemImage image; auto image = new SystemImage(QVersionNumber(), "", imageAbi, platform);
image.abiName = imageAbi; platform->addSystemImage(image);
image.apiLevel = platform.apiLevel;
platform.systemImages.append(image);
} }
}; };
SdkPlatform platform; class {
QStringList abiList; public:
foreach (const QString &l, output.split('\n')) { QStringList abiList;
const QString line = l.trimmed(); QVersionNumber revision;
int apiLevel = -1;
QString description;
Utils::FileName installedLocation;
void clear() {
abiList.clear();
revision = QVersionNumber();
apiLevel = -1;
description.clear();
installedLocation.clear();
}
} platformParams;
QStringList outputLines = output.split('\n');
for (int index = 0; index < outputLines.count(); ++index) {
const QString line = outputLines.at(index).trimmed();
if (line.startsWith(QLatin1String("id:")) && line.contains(QLatin1String("android-"))) { if (line.startsWith(QLatin1String("id:")) && line.contains(QLatin1String("android-"))) {
int index = line.indexOf(QLatin1String("\"android-")); int index = line.indexOf(QLatin1String("\"android-"));
if (index == -1) if (index == -1)
@@ -319,33 +329,33 @@ void AndroidToolOutputParser::parseTargetListing(const QString &output,
const QString tmp = androidTarget.mid(androidTarget.lastIndexOf(QLatin1Char('-')) + 1); const QString tmp = androidTarget.mid(androidTarget.lastIndexOf(QLatin1Char('-')) + 1);
Utils::FileName platformPath = sdkLocation; Utils::FileName platformPath = sdkLocation;
platformPath.appendPath(QString("/platforms/android-%1").arg(tmp)); platformPath.appendPath(QString("/platforms/android-%1").arg(tmp));
platform.installedLocation = platformPath; platformParams.installedLocation = platformPath;
platform.apiLevel = AndroidManager::findApiLevel(platformPath); platformParams.apiLevel = AndroidManager::findApiLevel(platformPath);
} else if (line.startsWith(QLatin1String("Name:"))) { } else if (line.startsWith(QLatin1String("Name:"))) {
platform.name = line.mid(6); platformParams.description = line.mid(6);
} else if (line.startsWith(QLatin1String("Revision:"))) {
platformParams.revision = QVersionNumber::fromString(line.mid(10));
} else if (line.startsWith(QLatin1String("Tag/ABIs :"))) { } else if (line.startsWith(QLatin1String("Tag/ABIs :"))) {
abiList = cleanAndroidABIs(line.mid(10).trimmed().split(QLatin1String(", "))); platformParams.abiList = cleanAndroidABIs(line.mid(10).trimmed().split(QLatin1String(", ")));
} else if (line.startsWith(QLatin1String("ABIs"))) { } else if (line.startsWith(QLatin1String("ABIs"))) {
abiList = cleanAndroidABIs(line.mid(6).trimmed().split(QLatin1String(", "))); platformParams.abiList = cleanAndroidABIs(line.mid(6).trimmed().split(QLatin1String(", ")));
} else if (line.startsWith(QLatin1String("---")) || line.startsWith(QLatin1String("==="))) { } else if (line.startsWith(QLatin1String("---"))
if (platform.apiLevel == -1) || line.startsWith(QLatin1String("==="))
|| index == outputLines.count() - 1) {
if (platformParams.apiLevel == -1)
continue; continue;
auto platform = new SdkPlatform(platformParams.revision,
addSystemImage(abiList, platform); QString("platforms;android-%1").arg(platformParams.apiLevel),
*platformList << platform; platformParams.apiLevel);
platform->setState(AndroidSdkPackage::Installed);
platform = SdkPlatform(); platform->setDescriptionText(platformParams.description);
abiList.clear(); platform->setInstalledLocation(platformParams.installedLocation);
addSystemImage(platformParams.abiList, platform);
platformList << platform;
platformParams.clear();
} }
} }
Utils::sort(platformList);
// The last parsed Platform.
if (platform.apiLevel != -1) {
addSystemImage(abiList, platform);
*platformList << platform;
}
Utils::sort(*platformList);
} }
} // namespace Internal } // namespace Internal

View File

@@ -51,15 +51,15 @@ public:
SdkPlatformList availableSdkPlatforms(bool *ok = nullptr) const; SdkPlatformList availableSdkPlatforms(bool *ok = nullptr) const;
void launchAvdManager() const; void launchAvdManager() const;
QFuture<AndroidConfig::CreateAvdInfo> createAvd(AndroidConfig::CreateAvdInfo info) const; QFuture<CreateAvdInfo> createAvd(CreateAvdInfo info) const;
bool removeAvd(const QString &name) const; bool removeAvd(const QString &name) const;
QFuture<AndroidDeviceInfoList> androidVirtualDevicesFuture() const; QFuture<AndroidDeviceInfoList> androidVirtualDevicesFuture() const;
// Helper methods // Helper methods
private: private:
Utils::Environment androidToolEnvironment() const; Utils::Environment androidToolEnvironment() const;
static AndroidConfig::CreateAvdInfo createAvdImpl(AndroidConfig::CreateAvdInfo info, static CreateAvdInfo createAvdImpl(CreateAvdInfo info, Utils::FileName androidToolPath,
Utils::FileName androidToolPath, Utils::Environment env); Utils::Environment env);
static AndroidDeviceInfoList androidVirtualDevices(const Utils::FileName &androidTool, static AndroidDeviceInfoList androidVirtualDevices(const Utils::FileName &androidTool,
const Utils::FileName &sdkLlocationPath, const Utils::FileName &sdkLlocationPath,
const Utils::Environment &environment); const Utils::Environment &environment);

View File

@@ -24,11 +24,12 @@
****************************************************************************/ ****************************************************************************/
#include "avddialog.h" #include "avddialog.h"
#include "androidconfigurations.h" #include "androidsdkmanager.h"
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/tooltip/tooltip.h> #include <utils/tooltip/tooltip.h>
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <utils/qtcassert.h>
#include <QKeyEvent> #include <QKeyEvent>
#include <QMessageBox> #include <QMessageBox>
@@ -37,10 +38,14 @@
using namespace Android; using namespace Android;
using namespace Android::Internal; using namespace Android::Internal;
AvdDialog::AvdDialog(int minApiLevel, const QString &targetArch, const AndroidConfig *config, QWidget *parent) : AvdDialog::AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QString &targetArch,
QDialog(parent), m_config(config), m_minApiLevel(minApiLevel), QWidget *parent) :
QDialog(parent),
m_sdkManager(sdkManager),
m_minApiLevel(minApiLevel),
m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*")) m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*"))
{ {
QTC_CHECK(m_sdkManager);
m_avdDialog.setupUi(this); m_avdDialog.setupUi(this);
m_hideTipTimer.setInterval(2000); m_hideTipTimer.setInterval(2000);
m_hideTipTimer.setSingleShot(true); m_hideTipTimer.setSingleShot(true);
@@ -70,12 +75,27 @@ AvdDialog::AvdDialog(int minApiLevel, const QString &targetArch, const AndroidCo
bool AvdDialog::isValid() const bool AvdDialog::isValid() const
{ {
return !name().isEmpty() && target().isValid() && !abi().isEmpty(); return !name().isEmpty() && sdkPlatform() && sdkPlatform()->isValid() && !abi().isEmpty();
} }
SdkPlatform AvdDialog::target() const CreateAvdInfo AvdDialog::gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager *sdkManager,
int minApiLevel, QString targetArch)
{ {
return m_avdDialog.targetComboBox->currentData().value<SdkPlatform>(); CreateAvdInfo result;
AvdDialog d(minApiLevel, sdkManager, targetArch, parent);
if (d.exec() != QDialog::Accepted || !d.isValid())
return result;
result.sdkPlatform = d.sdkPlatform();
result.name = d.name();
result.abi = d.abi();
result.sdcardSize = d.sdcardSize();
return result;
}
const SdkPlatform* AvdDialog::sdkPlatform() const
{
return m_avdDialog.targetComboBox->currentData().value<SdkPlatform*>();
} }
QString AvdDialog::name() const QString AvdDialog::name() const
@@ -96,21 +116,23 @@ int AvdDialog::sdcardSize() const
void AvdDialog::updateApiLevelComboBox() void AvdDialog::updateApiLevelComboBox()
{ {
SdkPlatformList filteredList; SdkPlatformList filteredList;
SdkPlatformList platforms = m_config->sdkTargets(m_minApiLevel); const SdkPlatformList platforms = m_sdkManager->filteredSdkPlatforms(m_minApiLevel);
QString selectedAbi = abi(); QString selectedAbi = abi();
auto hasAbi = [selectedAbi](const SystemImage &image) { auto hasAbi = [selectedAbi](const SystemImage *image) {
return image.isValid() && (image.abiName == selectedAbi); return image && image->isValid() && (image->abiName() == selectedAbi);
}; };
filteredList = Utils::filtered(platforms, [hasAbi](const SdkPlatform &platform) { filteredList = Utils::filtered(platforms, [hasAbi](const SdkPlatform *platform) {
return Utils::anyOf(platform.systemImages,hasAbi); return platform && Utils::anyOf(platform->systemImages(), hasAbi);
}); });
m_avdDialog.targetComboBox->clear(); m_avdDialog.targetComboBox->clear();
foreach (const SdkPlatform &platform, filteredList) { for (SdkPlatform *platform: filteredList) {
m_avdDialog.targetComboBox->addItem(AndroidConfig::apiLevelNameFor(platform), m_avdDialog.targetComboBox->addItem(platform->displayText(),
QVariant::fromValue<SdkPlatform>(platform)); QVariant::fromValue<SdkPlatform *>(platform));
m_avdDialog.targetComboBox->setItemData(m_avdDialog.targetComboBox->count() - 1,
platform->descriptionText(), Qt::ToolTipRole);
} }
if (platforms.isEmpty()) { if (platforms.isEmpty()) {

View File

@@ -24,7 +24,7 @@
****************************************************************************/ ****************************************************************************/
#pragma once #pragma once
#include "androidconfigurations.h"
#include "ui_addnewavddialog.h" #include "ui_addnewavddialog.h"
#include <QDialog> #include <QDialog>
@@ -35,26 +35,28 @@ class AndroidConfig;
class SdkPlatform; class SdkPlatform;
namespace Internal { namespace Internal {
class AndroidSdkManager;
class AvdDialog : public QDialog class AvdDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit AvdDialog(int minApiLevel, const QString &targetArch, explicit AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QString &targetArch,
const AndroidConfig *config, QWidget *parent = 0); QWidget *parent = 0);
Android::SdkPlatform target() const; const SdkPlatform *sdkPlatform() const;
QString name() const; QString name() const;
QString abi() const; QString abi() const;
int sdcardSize() const; int sdcardSize() const;
bool isValid() const; bool isValid() const;
static CreateAvdInfo gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager *sdkManager,
int minApiLevel = 0, QString targetArch = QString());
private: private:
void updateApiLevelComboBox(); void updateApiLevelComboBox();
bool eventFilter(QObject *obj, QEvent *event); bool eventFilter(QObject *obj, QEvent *event);
Ui::AddNewAVDDialog m_avdDialog; Ui::AddNewAVDDialog m_avdDialog;
const AndroidConfig *m_config; AndroidSdkManager *m_sdkManager;
int m_minApiLevel; int m_minApiLevel;
QTimer m_hideTipTimer; QTimer m_hideTipTimer;
QRegExp m_allowedNameChars; QRegExp m_allowedNameChars;