Commit ec4fe5f0 authored by Vikas Pachdha's avatar Vikas Pachdha

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: default avatarBogDan Vatra <bogdan@kdab.com>
parent 240d310a
......@@ -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 \
......
......@@ -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);
......
......@@ -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;
......
......@@ -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);
}
......
......@@ -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())));
......
......@@ -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)
{
return platform.apiLevel > 0 ? QString("android-%1").arg(platform.apiLevel) : "";
}
QList<SdkPlatform> AndroidConfig::sdkTargets(int minApiLevel) const
QString AndroidConfig::apiLevelNameFor(const SdkPlatform *platform)
{
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
......@@ -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
{
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
class CreateAvdInfo
{
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)
......@@ -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;
......
......@@ -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;
};
......
......@@ -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;
}
......
This diff is collapsed.
......@@ -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
......
/****************************************************************************
**
** 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;
}