Android: read SDK configuration from user editable path

By default, copy the sdk_definitions.json to Qt Creator user resource
path. The user can use that to make any updates if desired.

Add SdkDownloader instance as a member of AndroidSettingsWidget.

Change-Id: Ieabc9c6ddecbe63586f750b26bcf4ca990caee26
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Assam Boudjelthia
2020-03-16 20:14:56 +02:00
parent 76c2208bac
commit 41dd8dc8ef
4 changed files with 65 additions and 50 deletions

View File

@@ -286,13 +286,27 @@ void AndroidConfig::save(QSettings &settings) const
void AndroidConfig::parseDependenciesJson()
{
QString sdkConfigUserFile(Core::ICore::userResourcePath() + JsonFilePath);
QString sdkConfigFile(Core::ICore::resourcePath() + JsonFilePath);
QFile jsonFile(sdkConfigFile);
if (!jsonFile.open(QIODevice::ReadOnly))
qCDebug(avdConfigLog, "Couldn't open JSON config file %s.", qPrintable(sdkConfigFile));
QJsonDocument loadDoc(QJsonDocument::fromJson(jsonFile.readAll()));
QJsonObject jsonObject = loadDoc.object();
if (!QFile::exists(sdkConfigUserFile)) {
QDir(QFileInfo(sdkConfigUserFile).absolutePath()).mkpath(".");
QFile::copy(sdkConfigFile, sdkConfigUserFile);
}
if (QFileInfo(sdkConfigFile).lastModified() > QFileInfo(sdkConfigUserFile).lastModified()) {
QFile::remove(sdkConfigUserFile + ".old");
QFile::rename(sdkConfigUserFile, sdkConfigUserFile + ".old");
QFile::copy(sdkConfigFile, sdkConfigUserFile);
}
QFile jsonFile(sdkConfigUserFile);
if (!jsonFile.open(QIODevice::ReadOnly)) {
qCDebug(avdConfigLog, "Couldn't open JSON config file %s.", qPrintable(jsonFile.fileName()));
return;
}
QJsonObject jsonObject = QJsonDocument::fromJson(jsonFile.readAll()).object();
if (jsonObject.contains(CommonKey) && jsonObject[CommonKey].isObject()) {
QJsonObject commonObject = jsonObject[CommonKey].toObject();

View File

@@ -42,9 +42,9 @@ namespace Internal {
* @class SdkDownloader
* @brief Download Android SDK tools package from within Qt Creator.
*/
AndroidSdkDownloader::AndroidSdkDownloader(const QUrl &sdkUrl, const QByteArray &sha256) :
m_sdkUrl(sdkUrl), m_sha256(sha256)
AndroidSdkDownloader::AndroidSdkDownloader()
{
m_androidConfig = AndroidConfigurations::currentConfig();
connect(&m_manager, &QNetworkAccessManager::finished, this, &AndroidSdkDownloader::downloadFinished);
}
@@ -73,12 +73,12 @@ static void setSdkFilesExecPermission( const QString &sdkExtractPath)
void AndroidSdkDownloader::downloadAndExtractSdk(const QString &jdkPath, const QString &sdkExtractPath)
{
if (m_sdkUrl.isEmpty()) {
if (m_androidConfig.sdkToolsUrl().isEmpty()) {
logError(tr("The SDK Tools download URL is empty."));
return;
}
QNetworkRequest request(m_sdkUrl);
QNetworkRequest request(m_androidConfig.sdkToolsUrl());
m_reply = m_manager.get(request);
#if QT_CONFIG(ssl)
@@ -131,7 +131,7 @@ bool AndroidSdkDownloader::verifyFileIntegrity()
if (f.open(QFile::ReadOnly)) {
QCryptographicHash hash(QCryptographicHash::Sha256);
if (hash.addData(&f)) {
return hash.result() == m_sha256;
return hash.result() == m_androidConfig.getSdkToolsSha256();
}
}
return false;

View File

@@ -26,6 +26,8 @@
#ifndef ANDROIDSDKDOWNLOADER_H
#define ANDROIDSDKDOWNLOADER_H
#include "androidconfigurations.h"
#include <QNetworkReply>
#include <QObject>
#include <QProgressDialog>
@@ -38,7 +40,7 @@ class AndroidSdkDownloader : public QObject
Q_OBJECT
public:
AndroidSdkDownloader(const QUrl &sdkUrl, const QByteArray &sha256);
AndroidSdkDownloader();
void downloadAndExtractSdk(const QString &jdkPath, const QString &sdkExtractPath);
static QString dialogTitle();
@@ -68,8 +70,7 @@ private:
QNetworkReply *m_reply = nullptr;
QString m_sdkFilename;
QProgressDialog *m_progressDialog = nullptr;
QUrl m_sdkUrl;
QByteArray m_sha256;
AndroidConfig m_androidConfig;
};
} // Internal

View File

@@ -149,6 +149,7 @@ private:
QString m_lastAddedAvd;
std::unique_ptr<AndroidAvdManager> m_avdManager;
std::unique_ptr<AndroidSdkManager> m_sdkManager;
std::unique_ptr<AndroidSdkDownloader> m_sdkDownloader;
bool m_isInitialReloadDone = false;
};
@@ -405,7 +406,8 @@ AndroidSettingsWidget::AndroidSettingsWidget()
: m_ui(new Ui_AndroidSettingsWidget),
m_androidConfig(AndroidConfigurations::currentConfig()),
m_avdManager(new AndroidAvdManager(m_androidConfig)),
m_sdkManager(new AndroidSdkManager(m_androidConfig))
m_sdkManager(new AndroidSdkManager(m_androidConfig)),
m_sdkDownloader(new AndroidSdkDownloader())
{
m_ui->setupUi(this);
m_sdkManagerWidget = new AndroidSdkManagerWidget(m_androidConfig, m_sdkManager.get(),
@@ -498,6 +500,13 @@ AndroidSettingsWidget::AndroidSettingsWidget()
m_ui->downloadOpenJDKToolButton->setIcon(downloadIcon);
m_ui->downloadOpenSSLPrebuiltLibs->setIcon(downloadIcon);
m_ui->sdkToolsAutoDownloadButton->setIcon(Utils::Icons::RELOAD.icon());
m_ui->sdkToolsAutoDownloadButton->setToolTip(tr(
"Automatically download Android SDK Tools to selected location.\n\n"
"If the selected path contains no valid SDK Tools, the SDK Tools package "
"is downloaded from %1, and extracted to the selected path.\n"
"After the SDK Tools are properly set up, you are prompted to install "
"any essential packages required for Qt to build for Android.\n")
.arg(m_androidConfig.sdkToolsUrl().toString()));
connect(m_ui->SDKLocationPathChooser, &Utils::PathChooser::rawPathChanged,
this, &AndroidSettingsWidget::onSdkPathChanged);
@@ -545,18 +554,25 @@ AndroidSettingsWidget::AndroidSettingsWidget()
connect(m_ui->downloadOpenJDKToolButton, &QAbstractButton::clicked,
this, &AndroidSettingsWidget::openOpenJDKDownloadUrl);
// Validate SDK again after any change in SDK packages.
connect(m_sdkManager.get(),
&AndroidSdkManager::packageReloadFinished,
this,
&AndroidSettingsWidget::validateSdk);
connect(m_ui->sdkToolsAutoDownloadButton, &QAbstractButton::clicked, this, [this]() {
if (sdkToolsOk()) {
QMessageBox::warning(this, AndroidSdkDownloader::dialogTitle(),
tr("The selected path already has a valid SDK Tools package."));
validateSdk();
return;
}
downloadSdk();
connect(m_sdkManager.get(), &AndroidSdkManager::packageReloadFinished,
this, &AndroidSettingsWidget::validateSdk);
connect(m_ui->sdkToolsAutoDownloadButton, &QAbstractButton::clicked,
this, &AndroidSettingsWidget::downloadSdk);
connect(m_sdkDownloader.get(), &AndroidSdkDownloader::sdkDownloaderError, this, [this](const QString &error) {
QMessageBox::warning(this, AndroidSdkDownloader::dialogTitle(), error);
});
connect(m_sdkDownloader.get(), &AndroidSdkDownloader::sdkExtracted, this, [this]() {
m_sdkManager->reloadPackages(true);
updateUI();
apply();
QMetaObject::Connection *const openSslOneShot = new QMetaObject::Connection;
*openSslOneShot = connect(m_sdkManager.get(), &AndroidSdkManager::packageReloadFinished,
this, [this, openSslOneShot]() {
QObject::disconnect(*openSslOneShot);
downloadOpenSslRepo(true);
delete openSslOneShot;
});
});
}
@@ -933,6 +949,13 @@ void AndroidSettingsWidget::manageAVD()
void AndroidSettingsWidget::downloadSdk()
{
if (sdkToolsOk()) {
QMessageBox::warning(this, AndroidSdkDownloader::dialogTitle(),
tr("The selected path already has a valid SDK Tools package."));
validateSdk();
return;
}
QString message(tr("Download and install Android SDK Tools to: %1?")
.arg(QDir::toNativeSeparators(m_ui->SDKLocationPathChooser->rawPath())));
auto userInput = QMessageBox::information(this, AndroidSdkDownloader::dialogTitle(),
@@ -941,31 +964,8 @@ void AndroidSettingsWidget::downloadSdk()
auto javaSummaryWidget = static_cast<SummaryWidget *>(m_ui->javaDetailsWidget->widget());
if (javaSummaryWidget->allRowsOk()) {
auto javaPath = Utils::FilePath::fromUserInput(m_ui->OpenJDKLocationPathChooser->rawPath());
AndroidSdkDownloader *sdkDownloader = new AndroidSdkDownloader(
m_androidConfig.sdkToolsUrl(),
m_androidConfig.getSdkToolsSha256());
sdkDownloader->downloadAndExtractSdk(javaPath.toString(),
m_sdkDownloader->downloadAndExtractSdk(javaPath.toString(),
m_ui->SDKLocationPathChooser->path());
connect(sdkDownloader, &AndroidSdkDownloader::sdkExtracted, this, [this]() {
m_sdkManager->reloadPackages(true);
updateUI();
apply();
QMetaObject::Connection *const openSslOneShot = new QMetaObject::Connection;
*openSslOneShot = connect(m_sdkManager.get(), &AndroidSdkManager::packageReloadFinished,
this, [this, openSslOneShot]() {
QObject::disconnect(*openSslOneShot);
downloadOpenSslRepo(true);
delete openSslOneShot;
});
});
auto showErrorDialog = [this](const QString &error) {
QMessageBox::warning(this, AndroidSdkDownloader::dialogTitle(), error);
};
connect(sdkDownloader, &AndroidSdkDownloader::sdkDownloaderError, this, showErrorDialog);
}
}
}