Android: Edge towards AndroidApkBuildStep aspectification

Unexport AndroidApkBuildStep, remove AndroidBuildApkWidget file
pair, de-Q_OBJECT-ify AndroidBuildApkWidget (and as roadkill
PasswordInputDialog).

Change-Id: Id3b51dd33774aac70a4f23a8ab4cfb556ed1f2b5
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
hjk
2020-09-14 08:13:20 +02:00
parent df696a34b5
commit ca61a35910
7 changed files with 383 additions and 496 deletions

View File

@@ -8,7 +8,6 @@ add_qtc_plugin(Android
android_global.h
androidavdmanager.cpp androidavdmanager.h
androidbuildapkstep.cpp androidbuildapkstep.h
androidbuildapkwidget.cpp androidbuildapkwidget.h
androidconfigurations.cpp androidconfigurations.h
androidconstants.h
androidcreatekeystorecertificate.cpp androidcreatekeystorecertificate.h androidcreatekeystorecertificate.ui

View File

@@ -42,7 +42,6 @@ HEADERS += \
avddialog.h \
android_global.h \
androidbuildapkstep.h \
androidbuildapkwidget.h \
androidsdkmanager.h \
androidavdmanager.h \
adbcommandswidget.h \
@@ -88,7 +87,6 @@ SOURCES += \
javaindenter.cpp \
avddialog.cpp \
androidbuildapkstep.cpp \
androidbuildapkwidget.cpp \
androidsdkmanager.cpp \
androidavdmanager.cpp \
adbcommandswidget.cpp \

View File

@@ -34,8 +34,6 @@ Project {
"androidcreatekeystorecertificate.ui",
"androidbuildapkstep.cpp",
"androidbuildapkstep.h",
"androidbuildapkwidget.cpp",
"androidbuildapkwidget.h",
"androiddeployqtstep.cpp",
"androiddeployqtstep.h",
"androiddebugsupport.cpp",

View File

@@ -26,12 +26,14 @@
#include "androidbuildapkstep.h"
#include "androidbuildapkwidget.h"
#include "androidconfigurations.h"
#include "androidconstants.h"
#include "androidcreatekeystorecertificate.h"
#include "androidextralibrarylistmodel.h"
#include "androidmanager.h"
#include "androidsdkmanager.h"
#include "certificatesmodel.h"
#include "createandroidmanifestwizard.h"
#include "javaparser.h"
@@ -39,11 +41,12 @@
#include <coreplugin/icore.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildstep.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/buildsystem.h>
#include <projectexplorer/processparameters.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/target.h>
#include <projectexplorer/taskhub.h>
@@ -51,36 +54,44 @@
#include <qtsupport/qtkitinformation.h>
#include <utils/algorithm.h>
#include <utils/fancylineedit.h>
#include <utils/infolabel.h>
#include <utils/pathchooser.h>
#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>
#include <QCheckBox>
#include <QComboBox>
#include <QDateTime>
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QFormLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLabel>
#include <QLineEdit>
#include <QListView>
#include <QLoggingCategory>
#include <QMessageBox>
#include <QProcess>
#include <QPushButton>
#include <QTimer>
#include <QToolButton>
#include <QVBoxLayout>
#include <algorithm>
#include <memory>
using namespace ProjectExplorer;
using namespace QtSupport;
using namespace Utils;
using namespace Android::Internal;
namespace {
static Q_LOGGING_CATEGORY(buildapkstepLog, "qtc.android.build.androidbuildapkstep", QtWarningMsg)
}
namespace Android {
namespace Internal {
static Q_LOGGING_CATEGORY(buildapkstepLog, "qtc.android.build.androidbuildapkstep", QtWarningMsg)
const QVersionNumber gradleScriptRevokedSdkVersion(25, 3, 0);
const char KeystoreLocationKey[] = "KeystoreLocation";
@@ -89,7 +100,7 @@ const char VerboseOutputKey[] = "VerboseOutput";
class PasswordInputDialog : public QDialog
{
Q_OBJECT
Q_DECLARE_TR_FUNCTIONS(Android::Internal::AndroidBuildApkStep)
public:
enum Context{
@@ -114,6 +125,368 @@ private:
this);
};
// AndroidBuildApkWidget
class AndroidBuildApkWidget : public BuildStepConfigWidget
{
Q_DECLARE_TR_FUNCTIONS(Android::Internal::AndroidBuildApkStep)
public:
explicit AndroidBuildApkWidget(AndroidBuildApkStep *step);
private:
void setCertificates();
void updateSigningWarning();
void signPackageCheckBoxToggled(bool checked);
void onOpenSslCheckBoxChanged();
bool isOpenSslLibsIncluded();
QString openSslIncludeFileContent(const FilePath &projectPath);
QWidget *createApplicationGroup();
QWidget *createSignPackageGroup();
QWidget *createAdvancedGroup();
QWidget *createAdditionalLibrariesGroup();
private:
AndroidBuildApkStep *m_step = nullptr;
QCheckBox *m_signPackageCheckBox = nullptr;
InfoLabel *m_signingDebugWarningLabel = nullptr;
QComboBox *m_certificatesAliasComboBox = nullptr;
QCheckBox *m_addDebuggerCheckBox = nullptr;
QCheckBox *m_openSslCheckBox = nullptr;
};
AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step)
: BuildStepConfigWidget(step), m_step(step)
{
setDisplayName("<b>" + tr("Build Android APK") + "</b>");
setSummaryText(displayName());
auto vbox = new QVBoxLayout(this);
vbox->addWidget(createSignPackageGroup());
vbox->addWidget(createApplicationGroup());
vbox->addWidget(createAdvancedGroup());
vbox->addWidget(createAdditionalLibrariesGroup());
connect(m_step->buildConfiguration(), &BuildConfiguration::buildTypeChanged,
this, &AndroidBuildApkWidget::updateSigningWarning);
connect(m_signPackageCheckBox, &QAbstractButton::clicked,
m_addDebuggerCheckBox, &QWidget::setEnabled);
signPackageCheckBoxToggled(m_step->signPackage());
updateSigningWarning();
}
QWidget *AndroidBuildApkWidget::createApplicationGroup()
{
const int minApiSupported = AndroidManager::apiLevelRange().first;
QStringList targets = AndroidConfig::apiLevelNamesFor(AndroidConfigurations::sdkManager()->
filteredSdkPlatforms(minApiSupported));
targets.removeDuplicates();
auto group = new QGroupBox(tr("Application"), this);
auto targetSDKComboBox = new QComboBox();
targetSDKComboBox->addItems(targets);
targetSDKComboBox->setCurrentIndex(targets.indexOf(m_step->buildTargetSdk()));
const auto cbActivated = QOverload<int>::of(&QComboBox::activated);
connect(targetSDKComboBox, cbActivated, this, [this, targetSDKComboBox](int idx) {
const QString sdk = targetSDKComboBox->itemText(idx);
m_step->setBuildTargetSdk(sdk);
AndroidManager::updateGradleProperties(m_step->target(), QString()); // FIXME: Use real key.
});
auto formLayout = new QFormLayout(group);
formLayout->addRow(tr("Android build SDK:"), targetSDKComboBox);
auto createAndroidTemplatesButton = new QPushButton(tr("Create Templates"));
createAndroidTemplatesButton->setToolTip(
tr("Create an Android package for Custom Java code, assets, and Gradle configurations."));
connect(createAndroidTemplatesButton, &QAbstractButton::clicked, this, [this] {
CreateAndroidManifestWizard wizard(m_step->buildSystem());
wizard.exec();
});
formLayout->addRow(tr("Android customization:"), createAndroidTemplatesButton);
return group;
}
QWidget *AndroidBuildApkWidget::createSignPackageGroup()
{
QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
auto group = new QGroupBox(tr("Application Signature"), this);
auto keystoreLocationLabel = new QLabel(tr("Keystore:"), group);
keystoreLocationLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
auto keystoreLocationChooser = new PathChooser(group);
keystoreLocationChooser->setExpectedKind(PathChooser::File);
keystoreLocationChooser->lineEdit()->setReadOnly(true);
keystoreLocationChooser->setPath(m_step->keystorePath().toUserOutput());
keystoreLocationChooser->setInitialBrowsePathBackup(QDir::homePath());
keystoreLocationChooser->setPromptDialogFilter(tr("Keystore files (*.keystore *.jks)"));
keystoreLocationChooser->setPromptDialogTitle(tr("Select Keystore File"));
connect(keystoreLocationChooser, &PathChooser::pathChanged, this, [this](const QString &path) {
FilePath file = FilePath::fromString(path);
m_step->setKeystorePath(file);
m_signPackageCheckBox->setChecked(!file.isEmpty());
if (!file.isEmpty())
setCertificates();
});
auto keystoreCreateButton = new QPushButton(tr("Create..."), group);
connect(keystoreCreateButton, &QAbstractButton::clicked, this, [this, keystoreLocationChooser] {
AndroidCreateKeystoreCertificate d;
if (d.exec() != QDialog::Accepted)
return;
keystoreLocationChooser->setPath(d.keystoreFilePath().toUserOutput());
m_step->setKeystorePath(d.keystoreFilePath());
m_step->setKeystorePassword(d.keystorePassword());
m_step->setCertificateAlias(d.certificateAlias());
m_step->setCertificatePassword(d.certificatePassword());
setCertificates();
});
m_signPackageCheckBox = new QCheckBox(tr("Sign package"), group);
m_signPackageCheckBox->setChecked(m_step->signPackage());
m_signingDebugWarningLabel = new Utils::InfoLabel(tr("Signing a debug package"),
Utils::InfoLabel::Warning, group);
m_signingDebugWarningLabel->hide();
auto certificateAliasLabel = new QLabel(tr("Certificate alias:"), group);
certificateAliasLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
m_certificatesAliasComboBox = new QComboBox(group);
m_certificatesAliasComboBox->setEnabled(false);
QSizePolicy sizePolicy2(QSizePolicy::Fixed, QSizePolicy::Fixed);
sizePolicy2.setHorizontalStretch(0);
sizePolicy2.setVerticalStretch(0);
m_certificatesAliasComboBox->setSizePolicy(sizePolicy2);
m_certificatesAliasComboBox->setMinimumSize(QSize(300, 0));
auto horizontalLayout_2 = new QHBoxLayout;
horizontalLayout_2->addWidget(keystoreLocationLabel);
horizontalLayout_2->addWidget(keystoreLocationChooser);
horizontalLayout_2->addWidget(keystoreCreateButton);
auto horizontalLayout_3 = new QHBoxLayout;
horizontalLayout_3->addWidget(m_signingDebugWarningLabel);
horizontalLayout_3->addWidget(certificateAliasLabel);
horizontalLayout_3->addWidget(m_certificatesAliasComboBox);
auto vbox = new QVBoxLayout(group);
vbox->addLayout(horizontalLayout_2);
vbox->addWidget(m_signPackageCheckBox);
vbox->addLayout(horizontalLayout_3);
connect(m_signPackageCheckBox, &QAbstractButton::toggled,
this, &AndroidBuildApkWidget::signPackageCheckBoxToggled);
auto updateAlias = [this](int idx) {
QString alias = m_certificatesAliasComboBox->itemText(idx);
if (!alias.isEmpty())
m_step->setCertificateAlias(alias);
};
const auto cbActivated = QOverload<int>::of(&QComboBox::activated);
const auto cbCurrentIndexChanged = QOverload<int>::of(&QComboBox::currentIndexChanged);
connect(m_certificatesAliasComboBox, cbActivated, this, updateAlias);
connect(m_certificatesAliasComboBox, cbCurrentIndexChanged, this, updateAlias);
return group;
}
QWidget *AndroidBuildApkWidget::createAdvancedGroup()
{
auto group = new QGroupBox(tr("Advanced Actions"), this);
auto openPackageLocationCheckBox = new QCheckBox(tr("Open package location after build"), group);
openPackageLocationCheckBox->setChecked(m_step->openPackageLocation());
connect(openPackageLocationCheckBox, &QAbstractButton::toggled,
this, [this](bool checked) { m_step->setOpenPackageLocation(checked); });
m_addDebuggerCheckBox = new QCheckBox(tr("Add debug server"), group);
m_addDebuggerCheckBox->setEnabled(false);
m_addDebuggerCheckBox->setToolTip(tr("Packages debug server with "
"the APK to enable debugging. For the signed APK this option is unchecked by default."));
m_addDebuggerCheckBox->setChecked(m_step->addDebugger());
connect(m_addDebuggerCheckBox, &QAbstractButton::toggled,
m_step, &AndroidBuildApkStep::setAddDebugger);
auto verboseOutputCheckBox = new QCheckBox(tr("Verbose output"), group);
verboseOutputCheckBox->setChecked(m_step->verboseOutput());
auto vbox = new QVBoxLayout(group);
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(m_step->kit());
if (version && version->supportsMultipleQtAbis()) {
auto buildAAB = new QCheckBox(tr("Build .aab (Android App Bundle)"), group);
buildAAB->setChecked(m_step->buildAAB());
connect(buildAAB, &QAbstractButton::toggled, m_step, &AndroidBuildApkStep::setBuildAAB);
vbox->addWidget(buildAAB);
}
vbox->addWidget(openPackageLocationCheckBox);
vbox->addWidget(verboseOutputCheckBox);
vbox->addWidget(m_addDebuggerCheckBox);
connect(verboseOutputCheckBox, &QAbstractButton::toggled,
this, [this](bool checked) { m_step->setVerboseOutput(checked); });
return group;
}
QWidget *AndroidBuildApkWidget::createAdditionalLibrariesGroup()
{
auto group = new QGroupBox(tr("Additional Libraries"));
group->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
auto libsModel = new AndroidExtraLibraryListModel(m_step->buildSystem(), this);
connect(libsModel, &AndroidExtraLibraryListModel::enabledChanged, this,
[this, group](const bool enabled) {
group->setEnabled(enabled);
m_openSslCheckBox->setChecked(isOpenSslLibsIncluded());
});
auto libsView = new QListView;
libsView->setSelectionMode(QAbstractItemView::ExtendedSelection);
libsView->setToolTip(tr("List of extra libraries to include in Android package and load on startup."));
libsView->setModel(libsModel);
auto addLibButton = new QToolButton;
addLibButton->setText(tr("Add..."));
addLibButton->setToolTip(tr("Select library to include in package."));
addLibButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
addLibButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
connect(addLibButton, &QAbstractButton::clicked, this, [this, libsModel] {
QStringList fileNames = QFileDialog::getOpenFileNames(this,
tr("Select additional libraries"),
QDir::homePath(),
tr("Libraries (*.so)"));
if (!fileNames.isEmpty())
libsModel->addEntries(fileNames);
});
auto removeLibButton = new QToolButton;
removeLibButton->setText(tr("Remove"));
removeLibButton->setToolTip(tr("Remove currently selected library from list."));
connect(removeLibButton, &QAbstractButton::clicked, this, [libsModel, libsView] {
QModelIndexList removeList = libsView->selectionModel()->selectedIndexes();
libsModel->removeEntries(removeList);
});
auto libsButtonLayout = new QVBoxLayout;
libsButtonLayout->addWidget(addLibButton);
libsButtonLayout->addWidget(removeLibButton);
libsButtonLayout->addStretch(1);
m_openSslCheckBox = new QCheckBox(tr("Include prebuilt OpenSSL libraries"));
m_openSslCheckBox->setToolTip(tr("This is useful for apps that use SSL operations. The path "
"can be defined in Tools > Options > Devices > Android."));
connect(m_openSslCheckBox, &QAbstractButton::clicked, this,
&AndroidBuildApkWidget::onOpenSslCheckBoxChanged);
auto grid = new QGridLayout(group);
grid->addWidget(m_openSslCheckBox, 0, 0);
grid->addWidget(libsView, 1, 0);
grid->addLayout(libsButtonLayout, 1, 1);
QItemSelectionModel *libSelection = libsView->selectionModel();
connect(libSelection, &QItemSelectionModel::selectionChanged, this, [libSelection, removeLibButton] {
removeLibButton->setEnabled(libSelection->hasSelection());
});
Target *target = m_step->target();
const QString buildKey = target->activeBuildKey();
const ProjectNode *node = target->project()->findNodeForBuildKey(buildKey);
group->setEnabled(node && !node->parseInProgress());
return group;
}
void AndroidBuildApkWidget::signPackageCheckBoxToggled(bool checked)
{
m_certificatesAliasComboBox->setEnabled(checked);
m_step->setSignPackage(checked);
m_addDebuggerCheckBox->setChecked(!checked);
updateSigningWarning();
if (!checked)
return;
if (!m_step->keystorePath().isEmpty())
setCertificates();
}
void AndroidBuildApkWidget::onOpenSslCheckBoxChanged()
{
Utils::FilePath projectPath = m_step->buildConfiguration()->buildSystem()->projectFilePath();
QFile projectFile(projectPath.toString());
if (!projectFile.open(QIODevice::ReadWrite | QIODevice::Text)) {
qWarning() << "Cound't open project file to add OpenSSL extra libs: " << projectPath;
return;
}
const QString searchStr = openSslIncludeFileContent(projectPath);
QTextStream textStream(&projectFile);
QString fileContent = textStream.readAll();
if (!m_openSslCheckBox->isChecked()) {
fileContent.remove("\n" + searchStr);
} else if (!fileContent.contains(searchStr, Qt::CaseSensitive)) {
fileContent.append(searchStr + "\n");
}
projectFile.resize(0);
textStream << fileContent;
projectFile.close();
}
bool AndroidBuildApkWidget::isOpenSslLibsIncluded()
{
Utils::FilePath projectPath = m_step->buildConfiguration()->buildSystem()->projectFilePath();
const QString searchStr = openSslIncludeFileContent(projectPath);
QFile projectFile(projectPath.toString());
projectFile.open(QIODevice::ReadOnly);
QTextStream textStream(&projectFile);
QString fileContent = textStream.readAll();
projectFile.close();
return fileContent.contains(searchStr, Qt::CaseSensitive);
}
QString AndroidBuildApkWidget::openSslIncludeFileContent(const FilePath &projectPath)
{
QString openSslPath = AndroidConfigurations::currentConfig().openSslLocation().toString();
if (projectPath.endsWith(".pro"))
return "android: include(" + openSslPath + "/openssl.pri)";
if (projectPath.endsWith("CMakeLists.txt"))
return "if (ANDROID)\n include(" + openSslPath + "/CMakeLists.txt)\nendif()";
return QString();
}
void AndroidBuildApkWidget::setCertificates()
{
QAbstractItemModel *certificates = m_step->keystoreCertificates();
if (certificates) {
m_signPackageCheckBox->setChecked(certificates);
m_certificatesAliasComboBox->setModel(certificates);
}
}
void AndroidBuildApkWidget::updateSigningWarning()
{
bool nonRelease = m_step->buildType() != BuildConfiguration::Release;
bool visible = m_step->signPackage() && nonRelease;
m_signingDebugWarningLabel->setVisible(visible);
}
// AndroidBuildApkStep
AndroidBuildApkStep::AndroidBuildApkStep(BuildStepList *parent, Utils::Id id)
: AbstractProcessStep(parent, id),
m_buildTargetSdk(AndroidConfig::apiLevelNameFor(AndroidConfigurations::
@@ -710,8 +1083,6 @@ QString PasswordInputDialog::getPassword(Context context, std::function<bool (co
}
namespace Internal {
// AndroidBuildApkStepFactory
AndroidBuildApkStepFactory::AndroidBuildApkStepFactory()
@@ -725,5 +1096,3 @@ AndroidBuildApkStepFactory::AndroidBuildApkStepFactory()
} // namespace Internal
} // namespace Android
#include "androidbuildapkstep.moc"

View File

@@ -37,8 +37,9 @@ class QAbstractItemModel;
QT_END_NAMESPACE
namespace Android {
namespace Internal {
class ANDROID_EXPORT AndroidBuildApkStep : public ProjectExplorer::AbstractProcessStep
class AndroidBuildApkStep : public ProjectExplorer::AbstractProcessStep
{
Q_OBJECT
@@ -110,8 +111,6 @@ private:
QString m_inputFile;
};
namespace Internal {
class AndroidBuildApkStepFactory : public ProjectExplorer::BuildStepFactory
{
public:

View File

@@ -1,398 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
** Copyright (C) 2016 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 "androidbuildapkwidget.h"
#include "androidbuildapkstep.h"
#include "androidconfigurations.h"
#include "androidextralibrarylistmodel.h"
#include "androidcreatekeystorecertificate.h"
#include "androidmanager.h"
#include "androidsdkmanager.h"
#include "createandroidmanifestwizard.h"
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildsystem.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtkitinformation.h>
#include <utils/infolabel.h>
#include <utils/fancylineedit.h>
#include <utils/pathchooser.h>
#include <QCheckBox>
#include <QComboBox>
#include <QGroupBox>
#include <QFileDialog>
#include <QFormLayout>
#include <QLabel>
#include <QListView>
#include <QPushButton>
#include <QToolButton>
#include <QVBoxLayout>
#include <algorithm>
using namespace ProjectExplorer;
using namespace Utils;
namespace Android {
namespace Internal {
AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step)
: BuildStepConfigWidget(step), m_step(step)
{
setDisplayName("<b>" + tr("Build Android APK") + "</b>");
setSummaryText(displayName());
auto vbox = new QVBoxLayout(this);
vbox->addWidget(createSignPackageGroup());
vbox->addWidget(createApplicationGroup());
vbox->addWidget(createAdvancedGroup());
vbox->addWidget(createAdditionalLibrariesGroup());
connect(m_step->buildConfiguration(), &BuildConfiguration::buildTypeChanged,
this, &AndroidBuildApkWidget::updateSigningWarning);
connect(m_signPackageCheckBox, &QAbstractButton::clicked,
m_addDebuggerCheckBox, &QWidget::setEnabled);
signPackageCheckBoxToggled(m_step->signPackage());
updateSigningWarning();
}
QWidget *AndroidBuildApkWidget::createApplicationGroup()
{
const int minApiSupported = AndroidManager::apiLevelRange().first;
QStringList targets = AndroidConfig::apiLevelNamesFor(AndroidConfigurations::sdkManager()->
filteredSdkPlatforms(minApiSupported));
targets.removeDuplicates();
auto group = new QGroupBox(tr("Application"), this);
auto targetSDKComboBox = new QComboBox();
targetSDKComboBox->addItems(targets);
targetSDKComboBox->setCurrentIndex(targets.indexOf(m_step->buildTargetSdk()));
const auto cbActivated = QOverload<int>::of(&QComboBox::activated);
connect(targetSDKComboBox, cbActivated, this, [this, targetSDKComboBox](int idx) {
const QString sdk = targetSDKComboBox->itemText(idx);
m_step->setBuildTargetSdk(sdk);
AndroidManager::updateGradleProperties(step()->target(), QString()); // FIXME: Use real key.
});
auto formLayout = new QFormLayout(group);
formLayout->addRow(tr("Android build SDK:"), targetSDKComboBox);
auto createAndroidTemplatesButton = new QPushButton(tr("Create Templates"));
createAndroidTemplatesButton->setToolTip(
tr("Create an Android package for Custom Java code, assets, and Gradle configurations."));
connect(createAndroidTemplatesButton, &QAbstractButton::clicked, this, [this] {
CreateAndroidManifestWizard wizard(m_step->buildSystem());
wizard.exec();
});
formLayout->addRow(tr("Android customization:"), createAndroidTemplatesButton);
return group;
}
QWidget *AndroidBuildApkWidget::createSignPackageGroup()
{
QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
auto group = new QGroupBox(tr("Application Signature"), this);
auto keystoreLocationLabel = new QLabel(tr("Keystore:"), group);
keystoreLocationLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
auto keystoreLocationChooser = new PathChooser(group);
keystoreLocationChooser->setExpectedKind(PathChooser::File);
keystoreLocationChooser->lineEdit()->setReadOnly(true);
keystoreLocationChooser->setPath(m_step->keystorePath().toUserOutput());
keystoreLocationChooser->setInitialBrowsePathBackup(QDir::homePath());
keystoreLocationChooser->setPromptDialogFilter(tr("Keystore files (*.keystore *.jks)"));
keystoreLocationChooser->setPromptDialogTitle(tr("Select Keystore File"));
connect(keystoreLocationChooser, &PathChooser::pathChanged, this, [this](const QString &path) {
FilePath file = FilePath::fromString(path);
m_step->setKeystorePath(file);
m_signPackageCheckBox->setChecked(!file.isEmpty());
if (!file.isEmpty())
setCertificates();
});
auto keystoreCreateButton = new QPushButton(tr("Create..."), group);
connect(keystoreCreateButton, &QAbstractButton::clicked, this, [this, keystoreLocationChooser] {
AndroidCreateKeystoreCertificate d;
if (d.exec() != QDialog::Accepted)
return;
keystoreLocationChooser->setPath(d.keystoreFilePath().toUserOutput());
m_step->setKeystorePath(d.keystoreFilePath());
m_step->setKeystorePassword(d.keystorePassword());
m_step->setCertificateAlias(d.certificateAlias());
m_step->setCertificatePassword(d.certificatePassword());
setCertificates();
});
m_signPackageCheckBox = new QCheckBox(tr("Sign package"), group);
m_signPackageCheckBox->setChecked(m_step->signPackage());
m_signingDebugWarningLabel = new Utils::InfoLabel(tr("Signing a debug package"),
Utils::InfoLabel::Warning, group);
m_signingDebugWarningLabel->hide();
auto certificateAliasLabel = new QLabel(tr("Certificate alias:"), group);
certificateAliasLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
m_certificatesAliasComboBox = new QComboBox(group);
m_certificatesAliasComboBox->setEnabled(false);
QSizePolicy sizePolicy2(QSizePolicy::Fixed, QSizePolicy::Fixed);
sizePolicy2.setHorizontalStretch(0);
sizePolicy2.setVerticalStretch(0);
m_certificatesAliasComboBox->setSizePolicy(sizePolicy2);
m_certificatesAliasComboBox->setMinimumSize(QSize(300, 0));
auto horizontalLayout_2 = new QHBoxLayout;
horizontalLayout_2->addWidget(keystoreLocationLabel);
horizontalLayout_2->addWidget(keystoreLocationChooser);
horizontalLayout_2->addWidget(keystoreCreateButton);
auto horizontalLayout_3 = new QHBoxLayout;
horizontalLayout_3->addWidget(m_signingDebugWarningLabel);
horizontalLayout_3->addWidget(certificateAliasLabel);
horizontalLayout_3->addWidget(m_certificatesAliasComboBox);
auto vbox = new QVBoxLayout(group);
vbox->addLayout(horizontalLayout_2);
vbox->addWidget(m_signPackageCheckBox);
vbox->addLayout(horizontalLayout_3);
connect(m_signPackageCheckBox, &QAbstractButton::toggled,
this, &AndroidBuildApkWidget::signPackageCheckBoxToggled);
auto updateAlias = [this](int idx) {
QString alias = m_certificatesAliasComboBox->itemText(idx);
if (!alias.isEmpty())
m_step->setCertificateAlias(alias);
};
const auto cbActivated = QOverload<int>::of(&QComboBox::activated);
const auto cbCurrentIndexChanged = QOverload<int>::of(&QComboBox::currentIndexChanged);
connect(m_certificatesAliasComboBox, cbActivated, this, updateAlias);
connect(m_certificatesAliasComboBox, cbCurrentIndexChanged, this, updateAlias);
return group;
}
QWidget *AndroidBuildApkWidget::createAdvancedGroup()
{
auto group = new QGroupBox(tr("Advanced Actions"), this);
auto openPackageLocationCheckBox = new QCheckBox(tr("Open package location after build"), group);
openPackageLocationCheckBox->setChecked(m_step->openPackageLocation());
connect(openPackageLocationCheckBox, &QAbstractButton::toggled,
this, [this](bool checked) { m_step->setOpenPackageLocation(checked); });
m_addDebuggerCheckBox = new QCheckBox(tr("Add debug server"), group);
m_addDebuggerCheckBox->setEnabled(false);
m_addDebuggerCheckBox->setToolTip(tr("Packages debug server with "
"the APK to enable debugging. For the signed APK this option is unchecked by default."));
m_addDebuggerCheckBox->setChecked(m_step->addDebugger());
connect(m_addDebuggerCheckBox, &QAbstractButton::toggled,
m_step, &AndroidBuildApkStep::setAddDebugger);
auto verboseOutputCheckBox = new QCheckBox(tr("Verbose output"), group);
verboseOutputCheckBox->setChecked(m_step->verboseOutput());
auto vbox = new QVBoxLayout(group);
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(step()->kit());
if (version && version->supportsMultipleQtAbis()) {
auto buildAAB = new QCheckBox(tr("Build .aab (Android App Bundle)"), group);
buildAAB->setChecked(m_step->buildAAB());
connect(buildAAB, &QAbstractButton::toggled, m_step, &AndroidBuildApkStep::setBuildAAB);
vbox->addWidget(buildAAB);
}
vbox->addWidget(openPackageLocationCheckBox);
vbox->addWidget(verboseOutputCheckBox);
vbox->addWidget(m_addDebuggerCheckBox);
connect(verboseOutputCheckBox, &QAbstractButton::toggled,
this, [this](bool checked) { m_step->setVerboseOutput(checked); });
return group;
}
QWidget *AndroidBuildApkWidget::createAdditionalLibrariesGroup()
{
auto group = new QGroupBox(tr("Additional Libraries"));
group->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
auto libsModel = new AndroidExtraLibraryListModel(m_step->buildSystem(), this);
connect(libsModel, &AndroidExtraLibraryListModel::enabledChanged, this,
[this, group](const bool enabled) {
group->setEnabled(enabled);
m_openSslCheckBox->setChecked(isOpenSslLibsIncluded());
});
auto libsView = new QListView;
libsView->setSelectionMode(QAbstractItemView::ExtendedSelection);
libsView->setToolTip(tr("List of extra libraries to include in Android package and load on startup."));
libsView->setModel(libsModel);
auto addLibButton = new QToolButton;
addLibButton->setText(tr("Add..."));
addLibButton->setToolTip(tr("Select library to include in package."));
addLibButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
addLibButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
connect(addLibButton, &QAbstractButton::clicked, this, [this, libsModel] {
QStringList fileNames = QFileDialog::getOpenFileNames(this,
tr("Select additional libraries"),
QDir::homePath(),
tr("Libraries (*.so)"));
if (!fileNames.isEmpty())
libsModel->addEntries(fileNames);
});
auto removeLibButton = new QToolButton;
removeLibButton->setText(tr("Remove"));
removeLibButton->setToolTip(tr("Remove currently selected library from list."));
connect(removeLibButton, &QAbstractButton::clicked, this, [libsModel, libsView] {
QModelIndexList removeList = libsView->selectionModel()->selectedIndexes();
libsModel->removeEntries(removeList);
});
auto libsButtonLayout = new QVBoxLayout;
libsButtonLayout->addWidget(addLibButton);
libsButtonLayout->addWidget(removeLibButton);
libsButtonLayout->addStretch(1);
m_openSslCheckBox = new QCheckBox(tr("Include prebuilt OpenSSL libraries"));
m_openSslCheckBox->setToolTip(tr("This is useful for apps that use SSL operations. The path "
"can be defined in Tools > Options > Devices > Android."));
connect(m_openSslCheckBox, &QAbstractButton::clicked, this,
&AndroidBuildApkWidget::onOpenSslCheckBoxChanged);
auto grid = new QGridLayout(group);
grid->addWidget(m_openSslCheckBox, 0, 0);
grid->addWidget(libsView, 1, 0);
grid->addLayout(libsButtonLayout, 1, 1);
QItemSelectionModel *libSelection = libsView->selectionModel();
connect(libSelection, &QItemSelectionModel::selectionChanged, this, [libSelection, removeLibButton] {
removeLibButton->setEnabled(libSelection->hasSelection());
});
Target *target = m_step->target();
const QString buildKey = target->activeBuildKey();
const ProjectNode *node = target->project()->findNodeForBuildKey(buildKey);
group->setEnabled(node && !node->parseInProgress());
return group;
}
void AndroidBuildApkWidget::signPackageCheckBoxToggled(bool checked)
{
m_certificatesAliasComboBox->setEnabled(checked);
m_step->setSignPackage(checked);
m_addDebuggerCheckBox->setChecked(!checked);
updateSigningWarning();
if (!checked)
return;
if (!m_step->keystorePath().isEmpty())
setCertificates();
}
void AndroidBuildApkWidget::onOpenSslCheckBoxChanged()
{
Utils::FilePath projectPath = m_step->buildConfiguration()->buildSystem()->projectFilePath();
QFile projectFile(projectPath.toString());
if (!projectFile.open(QIODevice::ReadWrite | QIODevice::Text)) {
qWarning() << "Cound't open project file to add OpenSSL extra libs: " << projectPath;
return;
}
const QString searchStr = openSslIncludeFileContent(projectPath);
QTextStream textStream(&projectFile);
QString fileContent = textStream.readAll();
if (!m_openSslCheckBox->isChecked()) {
fileContent.remove("\n" + searchStr);
} else if (!fileContent.contains(searchStr, Qt::CaseSensitive)) {
fileContent.append(searchStr + "\n");
}
projectFile.resize(0);
textStream << fileContent;
projectFile.close();
}
bool AndroidBuildApkWidget::isOpenSslLibsIncluded()
{
Utils::FilePath projectPath = m_step->buildConfiguration()->buildSystem()->projectFilePath();
const QString searchStr = openSslIncludeFileContent(projectPath);
QFile projectFile(projectPath.toString());
projectFile.open(QIODevice::ReadOnly);
QTextStream textStream(&projectFile);
QString fileContent = textStream.readAll();
projectFile.close();
return fileContent.contains(searchStr, Qt::CaseSensitive);
}
QString AndroidBuildApkWidget::openSslIncludeFileContent(const Utils::FilePath &projectPath)
{
QString openSslPath = AndroidConfigurations::currentConfig().openSslLocation().toString();
if (projectPath.endsWith(".pro"))
return "android: include(" + openSslPath + "/openssl.pri)";
if (projectPath.endsWith("CMakeLists.txt"))
return "if (ANDROID)\n include(" + openSslPath + "/CMakeLists.txt)\nendif()";
return QString();
}
void AndroidBuildApkWidget::setCertificates()
{
QAbstractItemModel *certificates = m_step->keystoreCertificates();
if (certificates) {
m_signPackageCheckBox->setChecked(certificates);
m_certificatesAliasComboBox->setModel(certificates);
}
}
void AndroidBuildApkWidget::updateSigningWarning()
{
bool nonRelease = m_step->buildType() != BuildConfiguration::Release;
bool visible = m_step->signPackage() && nonRelease;
m_signingDebugWarningLabel->setVisible(visible);
}
} // Internal
} // Android

View File

@@ -1,78 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
** Copyright (C) 2016 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.
**
****************************************************************************/
#pragma once
#include "android_global.h"
#include "androidbuildapkstep.h"
#include <projectexplorer/buildstep.h>
QT_BEGIN_NAMESPACE
class QCheckBox;
class QComboBox;
class QLabel;
QT_END_NAMESPACE
namespace Utils {
class InfoLabel;
}
namespace Android {
namespace Internal {
class AndroidBuildApkWidget : public ProjectExplorer::BuildStepConfigWidget
{
Q_OBJECT
public:
explicit AndroidBuildApkWidget(AndroidBuildApkStep *step);
private:
void setCertificates();
void updateSigningWarning();
void signPackageCheckBoxToggled(bool checked);
void onOpenSslCheckBoxChanged();
bool isOpenSslLibsIncluded();
QString openSslIncludeFileContent(const Utils::FilePath &projectPath);
QWidget *createApplicationGroup();
QWidget *createSignPackageGroup();
QWidget *createAdvancedGroup();
QWidget *createAdditionalLibrariesGroup();
private:
AndroidBuildApkStep *m_step = nullptr;
QCheckBox *m_signPackageCheckBox = nullptr;
Utils::InfoLabel *m_signingDebugWarningLabel = nullptr;
QComboBox *m_certificatesAliasComboBox = nullptr;
QCheckBox *m_addDebuggerCheckBox = nullptr;
QCheckBox *m_openSslCheckBox = nullptr;
};
} // namespace Internal
} // namespace Android