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 \
androidavdmanager.h \
androidrunconfigurationwidget.h \
adbcommandswidget.h
adbcommandswidget.h \
androidsdkpackage.h
SOURCES += \
androidconfigurations.cpp \
@@ -94,7 +95,8 @@ SOURCES += \
androidsdkmanager.cpp \
androidavdmanager.cpp \
androidrunconfigurationwidget.cpp \
adbcommandswidget.cpp
adbcommandswidget.cpp \
androidsdkpackage.cpp
FORMS += \
androidsettingswidget.ui \

View File

@@ -101,37 +101,37 @@ static bool checkForTimeout(const chrono::steady_clock::time_point &start,
return timedOut;
}
static AndroidConfig::CreateAvdInfo createAvdCommand(const AndroidConfig config,
const AndroidConfig::CreateAvdInfo &info)
static CreateAvdInfo createAvdCommand(const AndroidConfig config, const CreateAvdInfo &info)
{
AndroidConfig::CreateAvdInfo result = info;
CreateAvdInfo result = info;
if (!result.isValid()) {
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",
"Cannot create AVD. Invalid input.");
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()) {
SystemImage image = Utils::findOrDefault(result.target.systemImages,
SystemImage *image = Utils::findOrDefault(result.sdkPlatform->systemImages(),
Utils::equal(&SystemImage::abiName, result.abi));
if (image.isValid()) {
arguments << "-k" << image.package;
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 << result.target.name;
<< result.abi << name;
result.error = QApplication::translate("AndroidAvdManager",
"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;
}
} else {
arguments << "-k" << result.target.package;
arguments << "-k" << result.sdkPlatform->sdkStylePath();
}
if (result.sdcardSize > 0)
@@ -234,8 +234,7 @@ void AndroidAvdManager::launchAvdManagerUiTool() const
}
}
QFuture<AndroidConfig::CreateAvdInfo>
AndroidAvdManager::createAvd(AndroidConfig::CreateAvdInfo info) const
QFuture<CreateAvdInfo> AndroidAvdManager::createAvd(CreateAvdInfo info) const
{
if (m_config.sdkToolsVersion() < avdManagerIntroVersion)
return m_androidTool->createAvd(info);

View File

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

View File

@@ -29,6 +29,7 @@
#include "androidconfigurations.h"
#include "androidconstants.h"
#include "androidmanager.h"
#include "androidsdkmanager.h"
#include "androidqtsupport.h"
#include "certificatesmodel.h"
@@ -92,7 +93,8 @@ private:
AndroidBuildApkStep::AndroidBuildApkStep(ProjectExplorer::BuildStepList *parent, const Core::Id id)
: ProjectExplorer::AbstractProcessStep(parent, id),
m_buildTargetSdk(AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk()))
m_buildTargetSdk(AndroidConfig::apiLevelNameFor(AndroidConfigurations::
sdkManager()->latestAndroidSdkPlatform()))
{
//: AndroidBuildApkStep default display name
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_signPackage = false; // don't restore this
m_buildTargetSdk = map.value(BuildTargetSdkKey).toString();
if (m_buildTargetSdk.isEmpty())
m_buildTargetSdk = AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk());
if (m_buildTargetSdk.isEmpty()) {
m_buildTargetSdk = AndroidConfig::apiLevelNameFor(AndroidConfigurations::
sdkManager()->latestAndroidSdkPlatform());
}
m_verbose = map.value(VerboseOutputKey).toBool();
return ProjectExplorer::BuildStep::fromMap(map);
}

View File

@@ -29,6 +29,7 @@
#include "androidconfigurations.h"
#include "androidcreatekeystorecertificate.h"
#include "androidmanager.h"
#include "androidsdkmanager.h"
#include "ui_androidbuildapkwidget.h"
#include <projectexplorer/buildconfiguration.h>
@@ -47,6 +48,8 @@
using namespace Android;
using namespace Internal;
const int minApiSupported = 9;
AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step)
: ProjectExplorer::BuildStepConfigWidget(),
m_ui(new Ui::AndroidBuildApkWidget),
@@ -55,9 +58,8 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step)
m_ui->setupUi(this);
// Target sdk combobox
int minApiLevel = 9;
const AndroidConfig &config = AndroidConfigurations::currentConfig();
QStringList targets = AndroidConfig::apiLevelNamesFor(config.sdkTargets(minApiLevel));
QStringList targets = AndroidConfig::apiLevelNamesFor(AndroidConfigurations::sdkManager()->
filteredSdkPlatforms(minApiSupported));
targets.removeDuplicates();
m_ui->targetSDKComboBox->addItems(targets);
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;
// persistent settings
}
m_availableSdkPlatformsUpToDate = false;
m_NdkInformationUpToDate = false;
}
@@ -333,40 +332,15 @@ void AndroidConfig::updateNdkInformation() const
m_NdkInformationUpToDate = true;
}
void AndroidConfig::updateAvailableSdkPlatforms() const
{
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)
QStringList AndroidConfig::apiLevelNamesFor(const SdkPlatformList &platforms)
{
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) : "";
}
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;
return platform && platform->apiLevel() > 0 ?
QString("android-%1").arg(platform->apiLevel()) : "";
}
FileName AndroidConfig::adbToolPath() const
@@ -523,20 +497,6 @@ QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(const QString &adbToo
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
{
QVector<AndroidDeviceInfo> devices = connectedDevices();
@@ -716,14 +676,6 @@ QStringList AndroidConfig::getAbis(const QString &adbToolPath, const QString &de
return result;
}
SdkPlatform AndroidConfig::highestAndroidSdk() const
{
updateAvailableSdkPlatforms();
if (m_availableSdkPlatforms.isEmpty())
return SdkPlatform();
return m_availableSdkPlatforms.first();
}
QString AndroidConfig::bestNdkPlatformMatch(int target) const
{
target = std::max(9, target);
@@ -743,7 +695,6 @@ FileName AndroidConfig::sdkLocation() const
void AndroidConfig::setSdkLocation(const FileName &sdkLocation)
{
m_sdkLocation = sdkLocation;
m_availableSdkPlatformsUpToDate = false;
}
QVersionNumber AndroidConfig::sdkToolsVersion() const
@@ -836,7 +787,6 @@ FileName AndroidConfig::openJDKLocation() const
void AndroidConfig::setOpenJDKLocation(const FileName &openJDKLocation)
{
m_openJDKLocation = openJDKLocation;
m_availableSdkPlatformsUpToDate = false;
}
FileName AndroidConfig::keystoreLocation() const
@@ -1129,6 +1079,11 @@ const AndroidConfig &AndroidConfigurations::currentConfig()
return m_instance->m_config; // ensure that m_instance is initialized
}
AndroidSdkManager *AndroidConfigurations::sdkManager()
{
return m_instance->m_sdkManager.get();
}
AndroidConfigurations *AndroidConfigurations::instance()
{
return m_instance;
@@ -1143,7 +1098,8 @@ void AndroidConfigurations::save()
}
AndroidConfigurations::AndroidConfigurations(QObject *parent)
: QObject(parent)
: QObject(parent),
m_sdkManager(new AndroidSdkManager(m_config))
{
load();
@@ -1155,6 +1111,11 @@ AndroidConfigurations::AndroidConfigurations(QObject *parent)
m_instance = this;
}
AndroidConfigurations::~AndroidConfigurations()
{
}
static FileName javaHomeForJavac(const FileName &location)
{
QFileInfo fileInfo = location.toFileInfo();
@@ -1265,13 +1226,4 @@ void AndroidConfigurations::updateAndroidDevice()
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

View File

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

View File

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

View File

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

View File

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

View File

@@ -48,13 +48,26 @@ namespace Internal {
const QVersionNumber sdkManagerIntroVersion(25, 3 ,0);
const char installLocationKey[] = "Installed Location:";
const char apiLevelPropertyKey[] = "AndroidVersion.ApiLevel";
const char abiPropertyKey[] = "SystemImage.Abi";
const char revisionKey[] = "Version:";
const char descriptionKey[] = "Description:";
const int sdkManagerCmdTimeoutS = 60;
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
\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
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)
{
QString sdkManagerToolPath = config.sdkManagerToolPath().toString();
@@ -88,6 +101,29 @@ static bool sdkManagerCommand(const AndroidConfig config, const QStringList &arg
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
\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
};
SdkManagerOutputParser(AndroidSdkPackageList &container) : m_packages(container) {}
void parsePackageListing(const QString &output);
SdkPlatformList m_installedPlatforms;
AndroidSdkPackageList &m_packages;
private:
void compileData();
void compilePackageAssociations();
void parsePackageData(MarkerTag packageMarker, const QStringList &data);
bool parsePlatform(const QStringList &data, SdkPlatform *platform) const;
bool parseSystemImage(const QStringList &data, SystemImage *image);
AndroidSdkPackage *parsePlatform(const QStringList &data) const;
QPair<SystemImage *, int> parseSystemImage(const QStringList &data) const;
MarkerTag parseMarkers(const QString &line);
MarkerTag m_currentSection = MarkerTag::None;
SystemImageList m_installedSystemImages;
QHash<AndroidSdkPackage *, int> m_systemImages;
};
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"}
};
AndroidSdkManager::AndroidSdkManager(const AndroidConfig &config):
m_config(config),
m_parser(new SdkManagerOutputParser)
AndroidSdkManager::AndroidSdkManager(const AndroidConfig &config, QObject *parent):
QObject(parent),
m_d(new AndroidSdkManagerPrivate(*this, config))
{
}
@@ -142,21 +179,61 @@ AndroidSdkManager::~AndroidSdkManager()
}
SdkPlatformList AndroidSdkManager::availableSdkPlatforms(bool *ok)
SdkPlatformList AndroidSdkManager::installedSdkPlatforms()
{
bool success = false;
if (m_config.sdkToolsVersion() < sdkManagerIntroVersion) {
AndroidToolManager toolManager(m_config);
return toolManager.availableSdkPlatforms(ok);
AndroidSdkPackageList list = m_d->filteredPackages(AndroidSdkPackage::Installed,
AndroidSdkPackage::SdkPlatformPackage);
return Utils::transform(list, [](AndroidSdkPackage *p) {
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;
if (sdkManagerCommand(m_config, QStringList({"--list", "--verbose"}), &packageListing))
m_parser->parsePackageListing(packageListing);
SdkPlatformList AndroidSdkManager::filteredSdkPlatforms(int minApiLevel,
AndroidSdkPackage::PackageState state)
{
const AndroidSdkPackageList list = m_d->filteredPackages(state,
AndroidSdkPackage::SdkPlatformPackage);
if (ok)
*ok = success;
return m_parser->m_installedPlatforms;
SdkPlatformList result;
for (AndroidSdkPackage *p : list) {
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)
@@ -173,10 +250,9 @@ void SdkManagerOutputParser::parsePackageListing(const QString &output)
}
};
QRegularExpression delimiters("[\n\r]");
QRegularExpression delimiters("[\\n\\r]");
foreach (QString outputLine, output.split(delimiters)) {
MarkerTag marker = parseMarkers(outputLine.trimmed());
if (marker & SectionMarkers) {
// Section marker found. Update the current section being parsed.
m_currentSection = marker;
@@ -211,20 +287,27 @@ void SdkManagerOutputParser::parsePackageListing(const QString &output)
packageData << outputLine;
}
}
compileData();
Utils::sort(m_installedPlatforms);
compilePackageAssociations();
}
void SdkManagerOutputParser::compileData()
void SdkManagerOutputParser::compilePackageAssociations()
{
// Associate the system images with sdk platforms.
for (auto &image : m_installedSystemImages) {
auto findPlatfom = [image](const SdkPlatform &platform) {
return platform.apiLevel == image.apiLevel;
auto imageItr = m_systemImages.cbegin();
while (imageItr != m_systemImages.cend()) {
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);
if (itr != m_installedPlatforms.end())
itr->systemImages.append(image);
auto itr = std::find_if(m_packages.begin(), m_packages.end(),
findPlatform);
if (itr != m_packages.end()) {
SdkPlatform *platform = static_cast<SdkPlatform*>(*itr);
platform->addSystemImage(static_cast<SystemImage *>(imageItr.key()));
}
++imageItr;
}
}
@@ -235,96 +318,142 @@ void SdkManagerOutputParser::parsePackageData(MarkerTag packageMarker, const QSt
if (m_currentSection != MarkerTag::InstalledPackagesMarker)
return; // For now, only interested in installed packages.
AndroidSdkPackage *package = nullptr;
switch (packageMarker) {
case MarkerTag::PlatformMarker:
{
SdkPlatform platform;
if (parsePlatform(data, &platform))
m_installedPlatforms.append(platform);
else
qCDebug(sdkManagerLog) << "Platform: Parsing failed: " << data;
}
package = parsePlatform(data);
if (package)
m_packages.append(package);
break;
case MarkerTag::SystemImageMarker:
{
SystemImage image;
if (parseSystemImage(data, &image))
m_installedSystemImages.append(image);
else
QPair<SystemImage *, int> result = parseSystemImage(data);
if (result.first) {
m_systemImages[result.first] = result.second;
package = result.first;
} else {
qCDebug(sdkManagerLog) << "System Image: Parsing failed: " << data;
}
}
break;
default:
qCDebug(sdkManagerLog) << "Unhandled package: " << markerTags.at(packageMarker);
break;
}
if (package) {
switch (m_currentSection) {
case MarkerTag::InstalledPackagesMarker:
package->setState(AndroidSdkPackage::Installed);
break;
case MarkerTag::AvailablePackagesMarkers:
case MarkerTag::AvailableUpdatesMarker:
package->setState(AndroidSdkPackage::Available);
break;
default:
qCDebug(sdkManagerLog) << "Invalid section marker: " << markerTags.at(m_currentSection);
break;
}
}
}
bool SdkManagerOutputParser::parsePlatform(const QStringList &data, SdkPlatform *platform) const
AndroidSdkPackage *SdkManagerOutputParser::parsePlatform(const QStringList &data) const
{
QTC_ASSERT(platform && !data.isEmpty(), return false);
QTC_ASSERT(!data.isEmpty(), qCDebug(sdkManagerLog) << "Platform: Empty input"; return nullptr);
QStringList parts = data.at(0).split(';');
if (parts.count() < 2) {
qCDebug(sdkManagerLog) << "Platform: Unexpected header: "<< data;
return false;
}
platform->name = parts[1];
platform->package = data.at(0);
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))
platform->installedLocation = Utils::FileName::fromString(value);
if (valueForKey(installLocationKey, line, &value)) {
installedLocation = Utils::FileName::fromString(value);
continue;
}
int apiLevel = AndroidManager::findApiLevel(platform->installedLocation);
if (apiLevel != -1)
platform->apiLevel = apiLevel;
else
qCDebug(sdkManagerLog) << "Platform: Can not parse api level: "<< data;
if (valueForKey(revisionKey, line, &value)) {
revision = QVersionNumber::fromString(value);
continue;
}
return apiLevel != -1;
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;
}
bool SdkManagerOutputParser::parseSystemImage(const QStringList &data, SystemImage *image)
QPair<SystemImage *, int> SdkManagerOutputParser::parseSystemImage(const QStringList &data) const
{
QTC_ASSERT(image && !data.isEmpty(), return false);
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(!data.isEmpty() && parts.count() >= 4,
qCDebug(sdkManagerLog) << "System Image: Unexpected header: " << data);
QTC_ASSERT(parts.count() >= 4,
qCDebug(sdkManagerLog) << "System Image: Unexpected header:" << data; return result);
image->package = data.at(0);
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))
image->installedLocation = Utils::FileName::fromString(value);
if (valueForKey(installLocationKey, line, &value)) {
installedLocation = Utils::FileName::fromString(value);
continue;
}
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;
if (valueForKey(revisionKey, line, &value)) {
revision = QVersionNumber::fromString(value);
continue;
}
image->abiName = imageProperties.value(abiPropertyKey).toString();
} else if (parts.count() >= 4){
image->apiLevel = parts[1].section('-', 1, 1).toInt();
image->abiName = parts[3];
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 {
qCDebug(sdkManagerLog) << "System Image: Can not parse: "<< data;
return false;
}
return true;
return result;
}
SdkManagerOutputParser::MarkerTag SdkManagerOutputParser::parseMarkers(const QString &line)
@@ -340,5 +469,79 @@ SdkManagerOutputParser::MarkerTag SdkManagerOutputParser::parseMarkers(const QSt
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 Android

View File

@@ -25,26 +25,46 @@
#pragma once
#include "utils/fileutils.h"
#include "androidconfigurations.h"
#include "androidsdkpackage.h"
#include <QObject>
#include <memory>
namespace Android {
class AndroidConfig;
namespace Internal {
class SdkManagerOutputParser;
class AndroidSdkManagerPrivate;
class AndroidSdkManager
class AndroidSdkManager : public QObject
{
Q_OBJECT
public:
AndroidSdkManager(const AndroidConfig &config);
AndroidSdkManager(const AndroidConfig &config, QObject *parent = nullptr);
~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:
const AndroidConfig &m_config;
std::unique_ptr<SdkManagerOutputParser> m_parser;
std::unique_ptr<AndroidSdkManagerPrivate> m_d;
friend class AndroidSdkManagerPrivate;
};
} // 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 "androidtoolchain.h"
#include "androidavdmanager.h"
#include "androidsdkmanager.h"
#include "avddialog.h"
#include <utils/qtcassert.h>
#include <utils/environment.h>
@@ -212,7 +214,8 @@ AndroidSettingsWidget::AndroidSettingsWidget(QWidget *parent)
: QWidget(parent),
m_ui(new Ui_AndroidSettingsWidget),
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);
@@ -390,7 +393,7 @@ void AndroidSettingsWidget::validateSdk()
summaryWidget->setPointValid(BuildToolsInstalledRow,
!m_androidConfig.buildToolsVersion().isNull());
summaryWidget->setPointValid(PlatformSdkInstalledRow,
!m_androidConfig.sdkTargets().isEmpty());
!m_sdkManager->installedSdkPlatforms().isEmpty());
updateUI();
}
@@ -412,9 +415,9 @@ void AndroidSettingsWidget::openOpenJDKDownloadUrl()
void AndroidSettingsWidget::addAVD()
{
disableAvdControls();
AndroidConfig::CreateAvdInfo info = m_androidConfig.gatherCreateAVDInfo(this);
CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, m_sdkManager.get());
if (!info.target.isValid()) {
if (!info.isValid()) {
enableAvdControls();
return;
}
@@ -424,7 +427,7 @@ void AndroidSettingsWidget::addAVD()
void AndroidSettingsWidget::avdAdded()
{
AndroidConfig::CreateAvdInfo info = m_futureWatcher.result();
CreateAvdInfo info = m_futureWatcher.result();
if (!info.error.isEmpty()) {
enableAvdControls();
QMessageBox::critical(this, QApplication::translate("AndroidConfig", "Error Creating AVD"), info.error);

View File

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

View File

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

View File

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

View File

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

View File

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