Merge remote-tracking branch 'origin/4.12'

Conflicts:
	src/plugins/cmakeprojectmanager/tealeafreader.cpp
	src/plugins/cmakeprojectmanager/tealeafreader.h
	src/plugins/projectexplorer/miniprojecttargetselector.cpp

Change-Id: I88d85be3903f57a55fddb7901e771a4822db1b85
This commit is contained in:
Eike Ziller
2020-03-04 08:15:50 +01:00
368 changed files with 8945 additions and 6485 deletions

View File

@@ -100,6 +100,7 @@ namespace {
const QLatin1String SettingsGroup("AndroidConfigurations");
const QLatin1String SDKLocationKey("SDKLocation");
const QLatin1String CustomNdkLocationsKey("CustomNdkLocations");
const QLatin1String SdkFullyConfiguredKey("AllEssentialsInstalled");
const QLatin1String SDKManagerToolArgsKey("SDKManagerToolArgs");
const QLatin1String OpenJDKLocationKey("OpenJDKLocation");
@@ -235,6 +236,7 @@ void AndroidConfig::load(const QSettings &settings)
// user settings
m_partitionSize = settings.value(PartitionSizeKey, 1024).toInt();
m_sdkLocation = FilePath::fromString(settings.value(SDKLocationKey).toString());
m_customNdkList = settings.value(CustomNdkLocationsKey).toStringList();
m_sdkManagerToolArgs = settings.value(SDKManagerToolArgsKey).toStringList();
m_openJDKLocation = FilePath::fromString(settings.value(OpenJDKLocationKey).toString());
m_keystoreLocation = FilePath::fromString(settings.value(KeystoreLocationKey).toString());
@@ -246,12 +248,14 @@ void AndroidConfig::load(const QSettings &settings)
&& settings.value(changeTimeStamp).toInt() != QFileInfo(sdkSettingsFileName()).lastModified().toMSecsSinceEpoch() / 1000) {
// persisten settings
m_sdkLocation = FilePath::fromString(reader.restoreValue(SDKLocationKey, m_sdkLocation.toString()).toString());
m_customNdkList = reader.restoreValue(CustomNdkLocationsKey).toStringList();
m_sdkManagerToolArgs = reader.restoreValue(SDKManagerToolArgsKey, m_sdkManagerToolArgs).toStringList();
m_openJDKLocation = FilePath::fromString(reader.restoreValue(OpenJDKLocationKey, m_openJDKLocation.toString()).toString());
m_automaticKitCreation = reader.restoreValue(AutomaticKitCreationKey, m_automaticKitCreation).toBool();
m_sdkFullyConfigured = reader.restoreValue(SdkFullyConfiguredKey, m_sdkFullyConfigured).toBool();
// persistent settings
}
m_customNdkList.removeAll("");
parseDependenciesJson();
}
@@ -263,6 +267,7 @@ void AndroidConfig::save(QSettings &settings) const
// user settings
settings.setValue(SDKLocationKey, m_sdkLocation.toString());
settings.setValue(CustomNdkLocationsKey, m_customNdkList);
settings.setValue(SDKManagerToolArgsKey, m_sdkManagerToolArgs);
settings.setValue(OpenJDKLocationKey, m_openJDKLocation.toString());
settings.setValue(KeystoreLocationKey, m_keystoreLocation.toString());
@@ -353,6 +358,22 @@ QVector<int> AndroidConfig::availableNdkPlatforms(const BaseQtVersion *qtVersion
return availableNdkPlatforms;
}
QStringList AndroidConfig::getCustomNdkList() const
{
return m_customNdkList;
}
void AndroidConfig::addCustomNdk(const QString &customNdk)
{
if (!m_customNdkList.contains(customNdk))
m_customNdkList.append(customNdk);
}
void AndroidConfig::removeCustomNdk(const QString &customNdk)
{
m_customNdkList.removeAll(customNdk);
}
QStringList AndroidConfig::apiLevelNamesFor(const SdkPlatformList &platforms)
{
return Utils::transform(platforms, AndroidConfig::apiLevelNameFor);
@@ -415,9 +436,9 @@ FilePath AndroidConfig::aaptToolPath() const
return aaptToolPath.pathAppended(toolPath);
}
FilePath AndroidConfig::toolchainPath(const BaseQtVersion *qtVersion) const
FilePath AndroidConfig::toolchainPathFromNdk(const Utils::FilePath &ndkLocation) const
{
const FilePath toolchainPath = ndkLocation(qtVersion).pathAppended("toolchains/llvm/prebuilt/");
const FilePath toolchainPath = ndkLocation.pathAppended("toolchains/llvm/prebuilt/");
// detect toolchain host
QStringList hostPatterns;
@@ -443,23 +464,41 @@ FilePath AndroidConfig::toolchainPath(const BaseQtVersion *qtVersion) const
return {};
}
FilePath AndroidConfig::clangPath(const BaseQtVersion *qtVersion) const
FilePath AndroidConfig::toolchainPath(const BaseQtVersion *qtVersion) const
{
const FilePath path = toolchainPath(qtVersion);
return toolchainPathFromNdk(ndkLocation(qtVersion));
}
FilePath AndroidConfig::clangPathFromNdk(const Utils::FilePath &ndkLocation) const
{
const FilePath path = toolchainPathFromNdk(ndkLocation);
if (path.isEmpty())
return {};
return path.pathAppended(HostOsInfo::withExecutableSuffix("bin/clang"));
}
FilePath AndroidConfig::clangPath(const BaseQtVersion *qtVersion) const
{
return clangPathFromNdk(ndkLocation(qtVersion));
}
FilePath AndroidConfig::gdbPath(const ProjectExplorer::Abi &abi, const BaseQtVersion *qtVersion) const
{
const FilePath path = ndkLocation(qtVersion).pathAppended(
QString("prebuilt/%1/bin/gdb%2").arg(toolchainHost(qtVersion), QTC_HOST_EXE_SUFFIX));
return gdbPathFromNdk(abi, ndkLocation(qtVersion));
}
FilePath AndroidConfig::gdbPathFromNdk(const Abi &abi, const FilePath &ndkLocation) const
{
const FilePath path = ndkLocation.pathAppended(
QString("prebuilt/%1/bin/gdb%2").arg(toolchainHostFromNdk(ndkLocation), QTC_HOST_EXE_SUFFIX));
if (path.exists())
return path;
// fallback for old NDKs (e.g. 10e)
return ndkLocation(qtVersion).pathAppended(QString("toolchains/%1-4.9/prebuilt/%2/bin/%3-gdb%4")
.arg(toolchainPrefix(abi), toolchainHost(qtVersion), toolsPrefix(abi), QTC_HOST_EXE_SUFFIX));
return ndkLocation.pathAppended(QString("toolchains/%1-4.9/prebuilt/%2/bin/%3-gdb%4")
.arg(toolchainPrefix(abi),
toolchainHostFromNdk(ndkLocation),
toolsPrefix(abi),
QTC_HOST_EXE_SUFFIX));
}
FilePath AndroidConfig::makePath(const BaseQtVersion *qtVersion) const
@@ -733,6 +772,16 @@ bool AndroidConfig::useNativeUiTools() const
return !version.isNull() && version <= QVersionNumber(25, 3 ,0);
}
bool AndroidConfig::isValidNdk(const QString &ndkLocation) const
{
auto ndkPath = Utils::FilePath::fromUserInput(ndkLocation);
const Utils::FilePath ndkPlatformsDir = ndkPath.pathAppended("platforms");
return ndkPath.exists() && ndkPath.pathAppended("toolchains").exists()
&& ndkPlatformsDir.exists() && !ndkPlatformsDir.toString().contains(' ')
&& !ndkVersion(ndkPath).isNull();
}
QString AndroidConfig::bestNdkPlatformMatch(int target, const BaseQtVersion *qtVersion) const
{
target = std::max(AndroidManager::apiLevelRange().first, target);
@@ -1076,10 +1125,53 @@ void AndroidConfigurations::registerNewToolChains()
const QList<ToolChain *> existingAndroidToolChains
= ToolChainManager::toolChains(Utils::equal(&ToolChain::typeId,
Core::Id(Constants::ANDROID_TOOLCHAIN_TYPEID)));
const QList<ToolChain *> newToolchains
= AndroidToolChainFactory::autodetectToolChainsForNdk(existingAndroidToolChains);
QList<ToolChain *> newToolchains = AndroidToolChainFactory::autodetectToolChains(
existingAndroidToolChains);
foreach (ToolChain *tc, newToolchains)
ToolChainManager::registerToolChain(tc);
registerCustomToolChainsAndDebuggers();
}
void AndroidConfigurations::registerCustomToolChainsAndDebuggers()
{
const QList<ToolChain *> existingAndroidToolChains = ToolChainManager::toolChains(
Utils::equal(&ToolChain::typeId, Core::Id(Constants::ANDROID_TOOLCHAIN_TYPEID)));
QList<FilePath> customNdks = Utils::transform(currentConfig().getCustomNdkList(),
FilePath::fromString);
QList<ToolChain *> customToolchains
= AndroidToolChainFactory::autodetectToolChainsFromNdks(existingAndroidToolChains,
customNdks,
true);
for (ToolChain *tc : customToolchains) {
ToolChainManager::registerToolChain(tc);
const FilePath ndk = static_cast<AndroidToolChain *>(tc)->ndkLocation();
const FilePath command = AndroidConfigurations::currentConfig()
.gdbPathFromNdk(tc->targetAbi(), ndk);
const Debugger::DebuggerItem *existing = Debugger::DebuggerItemManager::findByCommand(
command);
QString abiStr
= static_cast<AndroidToolChain *>(tc)->platformLinkerFlags().at(1).split('-').first();
Abi abi = Abi::abiFromTargetTriplet(abiStr);
if (existing && existing->abis().contains(abi))
continue;
Debugger::DebuggerItem debugger;
debugger.setCommand(command);
debugger.setEngineType(Debugger::GdbEngineType);
debugger.setUnexpandedDisplayName(
AndroidConfigurations::tr("Custom Android Debugger (%1, NDK %2)")
.arg(abiStr,
AndroidConfigurations::currentConfig().ndkVersion(ndk).toString()));
debugger.setAutoDetected(true);
debugger.setAbi(abi);
debugger.reinitializeFromFile();
Debugger::DebuggerItemManager::registerDebugger(debugger);
}
}
void AndroidConfigurations::removeOldToolChains()
@@ -1090,22 +1182,75 @@ void AndroidConfigurations::removeOldToolChains()
}
}
static QVariant findOrRegisterDebugger(ToolChain *tc, const BaseQtVersion *qtVersion)
void AndroidConfigurations::removeUnusedDebuggers()
{
const FilePath command = AndroidConfigurations::currentConfig().gdbPath(tc->targetAbi(), qtVersion);
QList<FilePath> uniqueNdks;
const QList<QtSupport::BaseQtVersion *> qtVersions
= QtSupport::QtVersionManager::versions([](const QtSupport::BaseQtVersion *v) {
return v->type() == Constants::ANDROIDQT;
});
for (const QtSupport::BaseQtVersion *qt : qtVersions) {
FilePath ndkLocation = currentConfig().ndkLocation(qt);
if (!uniqueNdks.contains(ndkLocation))
uniqueNdks.append(ndkLocation);
}
uniqueNdks.append(Utils::transform(currentConfig().getCustomNdkList(), FilePath::fromString));
const QList<Debugger::DebuggerItem> allDebuggers = Debugger::DebuggerItemManager::debuggers();
for (const Debugger::DebuggerItem &debugger : allDebuggers) {
if (!debugger.displayName().contains("Android"))
continue;
bool isChildOfNdk = false;
for (const FilePath &path : uniqueNdks) {
if (debugger.command().isChildOf(path)) {
isChildOfNdk = true;
break;
}
}
if (!isChildOfNdk && debugger.isAutoDetected())
Debugger::DebuggerItemManager::deregisterDebugger(debugger.id());
}
}
static QVariant findOrRegisterDebugger(ToolChain *tc,
const QStringList &abisList,
const BaseQtVersion *qtVersion)
{
const FilePath command = AndroidConfigurations::currentConfig().gdbPath(tc->targetAbi(),
qtVersion);
// check if the debugger is already registered, but ignoring the display name
const Debugger::DebuggerItem *existing = Debugger::DebuggerItemManager::findByCommand(command);
QList<Abi> abis = Utils::transform(abisList, Abi::abiFromTargetTriplet);
auto containsAbis = [abis](const Abis &secondAbis) {
for (const Abi &abi : secondAbis) {
if (!abis.contains(abi))
return false;
}
return true;
};
if (existing && existing->engineType() == Debugger::GdbEngineType && existing->isAutoDetected()
&& existing->abis() == Abis{tc->targetAbi()})
&& containsAbis(existing->abis())) {
// update debugger info with new
return existing->id();
}
// debugger not found, register a new one
Debugger::DebuggerItem debugger;
debugger.setCommand(command);
debugger.setEngineType(Debugger::GdbEngineType);
debugger.setUnexpandedDisplayName(
AndroidConfigurations::tr("Android Debugger for %1").arg(tc->displayName()));
AndroidConfigurations::tr("Android Debugger (%1, NDK %2)")
.arg(abisList.join(", "),
AndroidConfigurations::currentConfig().ndkVersion(qtVersion).toString()));
debugger.setAutoDetected(true);
debugger.setAbi(tc->targetAbi());
debugger.setAbis(abis.toVector());
debugger.reinitializeFromFile();
return Debugger::DebuggerItemManager::registerDebugger(debugger);
}
@@ -1136,6 +1281,8 @@ void AndroidConfigurations::updateAutomaticKitList()
return false;
});
removeUnusedDebuggers();
QHash<Abi, QList<const QtSupport::BaseQtVersion *> > qtVersionsForArch;
const QList<QtSupport::BaseQtVersion *> qtVersions
= QtSupport::QtVersionManager::versions([](const QtSupport::BaseQtVersion *v) {
@@ -1199,10 +1346,11 @@ void AndroidConfigurations::updateAutomaticKitList()
ToolChainKitAspect::setToolChain(k, tc);
QtSupport::QtKitAspect::setQtVersion(k, qt);
DeviceKitAspect::setDevice(k, device);
Debugger::DebuggerKitAspect::setDebugger(k, findOrRegisterDebugger(tc, QtKitAspect::qtVersion(k)));
QStringList abis = static_cast<const AndroidQtVersion *>(qt)->androidAbis();
Debugger::DebuggerKitAspect::setDebugger(k, findOrRegisterDebugger(tc, abis, QtKitAspect::qtVersion(k)));
k->makeSticky();
k->setUnexpandedDisplayName(tr("Android for %1 (Clang %2)")
.arg(static_cast<const AndroidQtVersion *>(qt)->androidAbis().join(","))
.arg(abis.join(","))
.arg(qt->displayName()));
k->setValueSilently(Constants::ANDROID_KIT_NDK, currentConfig().ndkLocation(qt).toString());
k->setValueSilently(Constants::ANDROID_KIT_SDK, currentConfig().sdkLocation().toString());

View File

@@ -160,9 +160,12 @@ public:
Utils::FilePath aaptToolPath() const;
Utils::FilePath toolchainPath(const QtSupport::BaseQtVersion *qtVersion) const;
Utils::FilePath toolchainPathFromNdk(const Utils::FilePath &ndkLocation) const;
Utils::FilePath clangPath(const QtSupport::BaseQtVersion *qtVersion) const;
Utils::FilePath clangPathFromNdk(const Utils::FilePath &ndkLocation) const;
Utils::FilePath gdbPath(const ProjectExplorer::Abi &abi, const QtSupport::BaseQtVersion *qtVersion) const;
Utils::FilePath gdbPathFromNdk(const ProjectExplorer::Abi &abi, const Utils::FilePath &ndkLocation) const;
Utils::FilePath makePath(const QtSupport::BaseQtVersion *qtVersion) const;
Utils::FilePath makePathFromNdk(const Utils::FilePath &ndkLocation) const;
@@ -188,6 +191,11 @@ public:
bool sdkFullyConfigured() const { return m_sdkFullyConfigured; };
void setSdkFullyConfigured(bool allEssentialsInstalled) { m_sdkFullyConfigured = allEssentialsInstalled; };
bool isValidNdk(const QString &ndkLocation) const;
QStringList getCustomNdkList() const;
void addCustomNdk(const QString &customNdk);
void removeCustomNdk(const QString &customNdk);
private:
static QString getDeviceProperty(const Utils::FilePath &adbToolPath,
const QString &device, const QString &property);
@@ -216,6 +224,7 @@ private:
QStringList m_commonEssentialPkgs;
SdkForQtVersions m_defaultSdkDepends;
QList<SdkForQtVersions> m_specificQtVersions;
QStringList m_customNdkList;
bool m_sdkFullyConfigured = false;
//caches
@@ -237,6 +246,8 @@ public:
static QString defaultDevice(ProjectExplorer::Project *project, const QString &abi); // serial number or avd name
static void clearDefaultDevices(ProjectExplorer::Project *project);
static void registerNewToolChains();
static void registerCustomToolChainsAndDebuggers();
static void removeUnusedDebuggers();
static void removeOldToolChains();
static void updateAutomaticKitList();
static bool force32bitEmulator();

View File

@@ -240,6 +240,18 @@ void AndroidManifestEditorWidget::initializePage()
m_targetLineEdit->installEventFilter(this);
formLayout->addRow(tr("Run:"), m_targetLineEdit);
m_styleExtractMethod = new QComboBox(applicationGroupBox);
formLayout->addRow(tr("Style extraction:"), m_styleExtractMethod);
const QList<QStringList> styleMethodsMap = {
{"default", "In most cases this will be the same as \"full\", but it can also be something else if needed, e.g. for compatibility reasons."},
{"full", "Useful for Qt Widgets & Qt Quick Controls 1 apps."},
{"minimal", "Useful for Qt Quick Controls 2 apps, it is much faster than \"full\"."},
{"none", "Useful for apps that don't use Qt Widgets, Qt Quick Controls 1 or Qt Quick Controls 2."}};
for (int i = 0; i <styleMethodsMap.size(); ++i) {
m_styleExtractMethod->addItem(styleMethodsMap.at(i).first());
m_styleExtractMethod->setItemData(i, styleMethodsMap.at(i).at(1), Qt::ToolTipRole);
}
auto iconLayout = new QHBoxLayout();
createDPIButton(iconLayout,
@@ -297,6 +309,9 @@ void AndroidManifestEditorWidget::initializePage()
this, setDirtyFunc);
connect(m_targetLineEdit, &QComboBox::currentTextChanged,
this, setDirtyFunc);
connect(m_styleExtractMethod,
QOverload<int>::of(&QComboBox::currentIndexChanged),
this, setDirtyFunc);
connect(m_masterIconButton, &QAbstractButton::clicked,
this, &AndroidManifestEditorWidget::setMasterIcon);
@@ -331,17 +346,6 @@ void AndroidManifestEditorWidget::initializePage()
m_defaultFeaturesCheckBox->setText(tr("Include default features for Qt modules."));
layout->addWidget(m_defaultFeaturesCheckBox, 1, 0);
m_permissionsModel = new PermissionsModel(this);
m_permissionsListView = new QListView(permissionsGroupBox);
m_permissionsListView->setModel(m_permissionsModel);
m_permissionsListView->setMinimumSize(QSize(0, 200));
layout->addWidget(m_permissionsListView, 2, 0, 3, 1);
m_removePermissionButton = new QPushButton(permissionsGroupBox);
m_removePermissionButton->setText(tr("Remove"));
layout->addWidget(m_removePermissionButton, 2, 1);
m_permissionsComboBox = new QComboBox(permissionsGroupBox);
m_permissionsComboBox->insertItems(0, QStringList()
<< QLatin1String("android.permission.ACCESS_CHECKIN_PROPERTIES")
@@ -476,11 +480,22 @@ void AndroidManifestEditorWidget::initializePage()
<< QLatin1String("android.permission.WRITE_USER_DICTIONARY")
);
m_permissionsComboBox->setEditable(true);
layout->addWidget(m_permissionsComboBox, 6, 0);
layout->addWidget(m_permissionsComboBox, 2, 0);
m_addPermissionButton = new QPushButton(permissionsGroupBox);
m_addPermissionButton->setText(tr("Add"));
layout->addWidget(m_addPermissionButton, 6, 1);
layout->addWidget(m_addPermissionButton, 2, 1);
m_permissionsModel = new PermissionsModel(this);
m_permissionsListView = new QListView(permissionsGroupBox);
m_permissionsListView->setModel(m_permissionsModel);
m_permissionsListView->setMinimumSize(QSize(0, 200));
layout->addWidget(m_permissionsListView, 3, 0, 3, 1);
m_removePermissionButton = new QPushButton(permissionsGroupBox);
m_removePermissionButton->setText(tr("Remove"));
layout->addWidget(m_removePermissionButton, 3, 1);
permissionsGroupBox->setLayout(layout);
@@ -804,11 +819,21 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
QDomElement metadataElem = activityElem.firstChildElement(QLatin1String("meta-data"));
const int parseItemsCount = 2;
int counter = 0;
while (!metadataElem.isNull()) {
if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")) {
m_targetLineEdit->setEditText(metadataElem.attribute(QLatin1String("android:value")));
break;
++counter;
} else if (metadataElem.attribute(QLatin1String("android:name"))
== QLatin1String("android.app.extract_android_style")) {
m_styleExtractMethod->setCurrentText(
metadataElem.attribute(QLatin1String("android:value")));
++counter;
}
if (counter == parseItemsCount)
break;
metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data"));
}
@@ -1093,15 +1118,24 @@ bool AndroidManifestEditorWidget::parseMetaData(QXmlStreamReader &reader, QXmlSt
{
Q_ASSERT(reader.isStartElement());
bool found = false;
const int parseItemsCount = 2;
int counter = 0;
QXmlStreamAttributes attributes = reader.attributes();
QXmlStreamAttributes result;
QStringList keys;
QStringList values;
if (attributes.value(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")) {
QStringList keys = QStringList("android:value");
QStringList values = QStringList(m_targetLineEdit->currentText());
keys = QStringList("android:value");
values = QStringList(m_targetLineEdit->currentText());
result = modifyXmlStreamAttributes(attributes, keys, values);
found = true;
++counter;
} else if (attributes.value(QLatin1String("android:name"))
== QLatin1String("android.app.extract_android_style")) {
keys = QStringList("android:value");
values = QStringList(m_styleExtractMethod->currentText());
result = modifyXmlStreamAttributes(attributes, keys, values);
++counter;
} else {
result = attributes;
}
@@ -1114,7 +1148,7 @@ bool AndroidManifestEditorWidget::parseMetaData(QXmlStreamReader &reader, QXmlSt
while (!reader.atEnd()) {
if (reader.isEndElement()) {
writer.writeCurrentToken(reader);
return found;
return counter == parseItemsCount;
} else if (reader.isStartElement()) {
parseUnknownElement(reader, writer);
} else {
@@ -1122,7 +1156,7 @@ bool AndroidManifestEditorWidget::parseMetaData(QXmlStreamReader &reader, QXmlSt
}
reader.readNext();
}
return found; // should never be reached
return counter == parseItemsCount; // should never be reached
}
void AndroidManifestEditorWidget::parseUsesSdk(QXmlStreamReader &reader, QXmlStreamWriter & writer)

View File

@@ -189,6 +189,7 @@ private:
QLineEdit *m_appNameLineEdit;
QLineEdit *m_activityNameLineEdit;
QComboBox *m_targetLineEdit;
QComboBox *m_styleExtractMethod;
QToolButton *m_masterIconButton;
QToolButton *m_lIconButton;
QToolButton *m_lIconClearButton;

View File

@@ -177,8 +177,8 @@ void AndroidPlugin::kitsRestored()
&AndroidPlugin::askUserAboutAndroidSetup, Qt::QueuedConnection);
}
AndroidConfigurations::updateAutomaticKitList();
AndroidConfigurations::registerNewToolChains();
AndroidConfigurations::updateAutomaticKitList();
connect(QtSupport::QtVersionManager::instance(), &QtSupport::QtVersionManager::qtVersionsChanged,
AndroidConfigurations::instance(), &AndroidConfigurations::updateAutomaticKitList);
disconnect(KitManager::instance(), &KitManager::kitsLoaded,

View File

@@ -133,6 +133,7 @@ private:
bool sdkToolsOk() const;
Utils::FilePath getDefaultSdkPath();
void showEvent(QShowEvent *event) override;
void addCustomNdkItem();
Ui_AndroidSettingsWidget *m_ui;
AndroidSdkManagerWidget *m_sdkManagerWidget = nullptr;
@@ -342,7 +343,7 @@ void AndroidSettingsWidget::showEvent(QShowEvent *event)
// Reloading SDK packages (force) is still synchronous. Use zero timer
// to let settings dialog open first.
QTimer::singleShot(0, std::bind(&AndroidSdkManager::reloadPackages,
m_sdkManager.get(), true));
m_sdkManager.get(), false));
m_isInitialReloadDone = true;
}
}
@@ -352,6 +353,22 @@ void AndroidSettingsWidget::updateNdkList()
m_ui->ndkListComboBox->clear();
for (const Ndk *ndk : m_sdkManager->installedNdkPackages())
m_ui->ndkListComboBox->addItem(ndk->installedLocation().toString());
for (const QString &ndk : m_androidConfig.getCustomNdkList()) {
if (m_androidConfig.isValidNdk(ndk))
m_ui->ndkListComboBox->addItem(ndk);
else
m_androidConfig.removeCustomNdk(ndk);
}
}
void AndroidSettingsWidget::addCustomNdkItem()
{
const QString ndkPath = QDir::toNativeSeparators(m_ui->customNdkPathChooser->rawPath());
m_androidConfig.addCustomNdk(ndkPath);
if (m_ui->ndkListComboBox->findData(ndkPath) == -1)
m_ui->ndkListComboBox->addItem(ndkPath);
m_ui->ndkListComboBox->setCurrentText(ndkPath);
}
AndroidSettingsWidget::AndroidSettingsWidget()
@@ -435,8 +452,23 @@ AndroidSettingsWidget::AndroidSettingsWidget()
connect(m_ui->SDKLocationPathChooser, &Utils::PathChooser::rawPathChanged,
this, &AndroidSettingsWidget::onSdkPathChanged);
connect(m_ui->ndkListComboBox, QOverload<const QString &>::of(&QComboBox::currentIndexChanged),
[this](const QString) { validateNdk(); });
connect(m_ui->ndkListComboBox,
QOverload<const QString &>::of(&QComboBox::currentIndexChanged),
[this](const QString &ndk) {
validateNdk();
m_ui->removeCustomNdkButton->setEnabled(m_androidConfig.getCustomNdkList().contains(ndk));
});
connect(m_ui->customNdkPathChooser, &Utils::PathChooser::rawPathChanged, this, [this]() {
const QString ndkPath = m_ui->customNdkPathChooser->rawPath();
m_ui->addCustomNdkButton->setEnabled(m_androidConfig.isValidNdk(ndkPath));
});
connect(m_ui->addCustomNdkButton, &QPushButton::clicked, this,
&AndroidSettingsWidget::addCustomNdkItem);
connect(m_ui->removeCustomNdkButton, &QPushButton::clicked, this, [this]() {
m_androidConfig.removeCustomNdk(m_ui->ndkListComboBox->currentText());
m_ui->ndkListComboBox->removeItem(m_ui->ndkListComboBox->currentIndex());
});
connect(&m_virtualDevicesWatcher, &QFutureWatcherBase::finished,
this, &AndroidSettingsWidget::updateAvds);
connect(m_ui->AVDRefreshPushButton, &QAbstractButton::clicked,

View File

@@ -93,7 +93,7 @@
<item row="0" column="0">
<widget class="QLabel" name="SDKLocationLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -106,21 +106,24 @@
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QToolButton" name="downloadSDKToolButton">
<property name="toolTip">
<string>Download Android SDK</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="ndkComboBoxLabel">
<widget class="QLabel" name="customNdkLabel">
<property name="text">
<string>Android NDK list:</string>
<string>Add custom NDK:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<item row="1" column="6">
<widget class="QToolButton" name="downloadNDKToolButton">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="1" colspan="4">
<widget class="Utils::PathChooser" name="SDKLocationPathChooser" native="true"/>
</item>
<item row="0" column="5">
<widget class="QToolButton" name="sdkToolsAutoDownloadButton">
<property name="toolTip">
<string>Automatically download Android SDK Tools to selected location.</string>
@@ -130,29 +133,74 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="5">
<item row="3" column="0" colspan="7">
<widget class="Utils::DetailsWidget" name="androidDetailsWidget" native="true"/>
</item>
<item row="1" column="4">
<widget class="QToolButton" name="downloadNDKToolButton">
<item row="2" column="0">
<widget class="QLabel" name="ndkComboBoxLabel">
<property name="text">
<string/>
<string>Android NDK list:</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="Utils::PathChooser" name="SDKLocationPathChooser" native="true">
<item row="0" column="6">
<widget class="QToolButton" name="downloadSDKToolButton">
<property name="toolTip">
<string>Download Android SDK</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="Utils::PathChooser" name="customNdkPathChooser" native="true">
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="addCustomNdkButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Add the selected custom NDK. The toolchains and debuggers will be created automatically.</string>
</property>
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item row="1" column="2">
<item row="2" column="1" colspan="3">
<widget class="QComboBox" name="ndkListComboBox"/>
</item>
<item row="2" column="4">
<widget class="QPushButton" name="removeCustomNdkButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Remove the selected custom NDK.</string>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -351,6 +399,10 @@
<extends>QWidget</extends>
<header location="global">utils/pathchooser.h</header>
<container>1</container>
<slots>
<signal>editingFinished()</signal>
<signal>browsingFinished()</signal>
</slots>
</customwidget>
<customwidget>
<class>Utils::DetailsWidget</class>

View File

@@ -93,14 +93,22 @@ AndroidToolChain::~AndroidToolChain() = default;
bool AndroidToolChain::isValid() const
{
if (m_ndkLocation.isEmpty()) {
QStringList ndkParts(compilerCommand().toString().split("toolchains/llvm/prebuilt/"));
if (ndkParts.size() > 1) {
QString ndkLocation(ndkParts.first());
if (ndkLocation.endsWith('/'))
ndkLocation.chop(1);
m_ndkLocation = FilePath::fromString(ndkLocation);
}
}
const bool isChildofNdk = compilerCommand().isChildOf(m_ndkLocation);
// If we're restoring a toolchain we set NDK path ourselves so it's enough to check against SDK
const bool isChildofSdk = compilerCommand().isChildOf(
AndroidConfigurations::currentConfig().sdkLocation());
return ClangToolChain::isValid() && typeId() == Constants::ANDROID_TOOLCHAIN_TYPEID
&& targetAbi().isValid()
&& (isChildofNdk || isChildofSdk)
&& targetAbi().isValid() && (isChildofNdk || isChildofSdk)
&& !originalTargetTriple().isEmpty();
}
@@ -163,7 +171,7 @@ AndroidToolChainFactory::AndroidToolChainFactory()
ToolChainList AndroidToolChainFactory::autoDetect(const ToolChainList &alreadyKnown)
{
return autodetectToolChainsForNdk(alreadyKnown);
return autodetectToolChains(alreadyKnown);
}
static FilePath clangPlusPlusPath(const FilePath &clangPath)
@@ -173,7 +181,7 @@ static FilePath clangPlusPlusPath(const FilePath &clangPath)
QFileInfo(clangPath.toString()).baseName() + "++"));
}
static QList<QtSupport::BaseQtVersion *> androidQtVersionsWithUniqueNdk()
static QList<FilePath> uniqueNdksForCurrentQtVersions()
{
AndroidConfig config = AndroidConfigurations::currentConfig();
@@ -182,36 +190,40 @@ static QList<QtSupport::BaseQtVersion *> androidQtVersionsWithUniqueNdk()
return v->targetDeviceTypes().contains(Android::Constants::ANDROID_DEVICE_TYPE);
});
auto shouldRemove = [config](const QtSupport::BaseQtVersion *first,
const QtSupport::BaseQtVersion *second) {
return config.ndkLocation(first) == config.ndkLocation(second);
};
QList<FilePath> uniqueNdks;
for (const QtSupport::BaseQtVersion *version : androidQtVersions) {
FilePath ndk = config.ndkLocation(version);
if (!uniqueNdks.contains(ndk))
uniqueNdks.append(ndk);
}
QList<QtSupport::BaseQtVersion *>::iterator it = std::unique(androidQtVersions.begin(),
androidQtVersions.end(),
shouldRemove);
androidQtVersions.erase(it, androidQtVersions.end());
return androidQtVersions;
return uniqueNdks;
}
ToolChainList AndroidToolChainFactory::autodetectToolChainsForNdk(const ToolChainList &alreadyKnown)
ToolChainList AndroidToolChainFactory::autodetectToolChains(const ToolChainList &alreadyKnown)
{
const QList<Utils::FilePath> uniqueNdks = uniqueNdksForCurrentQtVersions();
return autodetectToolChainsFromNdks(alreadyKnown, uniqueNdks);
}
ToolChainList AndroidToolChainFactory::autodetectToolChainsFromNdks(
const ToolChainList &alreadyKnown,
const QList<Utils::FilePath> &ndkLocations,
const bool isCustom)
{
QList<ToolChain *> result;
const QList<QtSupport::BaseQtVersion *> androidQtVersions = androidQtVersionsWithUniqueNdk();
const AndroidConfig config = AndroidConfigurations::currentConfig();
for (const QtSupport::BaseQtVersion *qtVersion : androidQtVersions) {
FilePath clangPath = config.clangPath(qtVersion);
for (const Utils::FilePath &ndkLocation : ndkLocations) {
qCDebug(androidTCLog) << "Detecting toolchains from Android NDK:" << ndkLocation;
FilePath clangPath = config.clangPathFromNdk(ndkLocation);
if (!clangPath.exists()) {
qCDebug(androidTCLog) << "Clang toolchains detection fails. Can not find Clang"
<< clangPath;
return result;
continue;
}
qCDebug(androidTCLog) << "Detecting toolchains from Android NDK:"
<< config.ndkLocation(qtVersion);
for (const Core::Id &lang : LanguageIds) {
FilePath compilerCommand = clangPath;
if (lang == ProjectExplorer::Constants::CXX_LANGUAGE_ID)
@@ -229,10 +241,11 @@ ToolChainList AndroidToolChainFactory::autodetectToolChainsForNdk(const ToolChai
const QString target = targetItr.key();
ToolChain *tc = findToolChain(compilerCommand, lang, target, alreadyKnown);
const QString displayName(QString("Android Clang (%1, %2, NDK %3)")
QLatin1String customStr = isCustom ? QLatin1String("Custom ") : QLatin1String();
const QString displayName(customStr + QString("Android Clang (%1, %2, NDK %3)")
.arg(ToolChainManager::displayNameOfLanguageId(lang),
AndroidConfig::displayName(abi),
config.ndkVersion(qtVersion).toString()));
config.ndkVersion(ndkLocation).toString()));
if (tc) {
qCDebug(androidTCLog) << "Tool chain already known" << abi.toString() << lang;
// make sure to update the toolchain with current name format
@@ -241,7 +254,7 @@ ToolChainList AndroidToolChainFactory::autodetectToolChainsForNdk(const ToolChai
} else {
qCDebug(androidTCLog) << "New Clang toolchain found" << abi.toString() << lang;
auto atc = new AndroidToolChain();
atc->setNdkLocation(config.ndkLocation(qtVersion));
atc->setNdkLocation(ndkLocation);
atc->setOriginalTargetTriple(target);
atc->setLanguage(lang);
atc->setTargetAbi(ClangTargets[target]);

View File

@@ -59,7 +59,7 @@ private:
friend class AndroidToolChainFactory;
Utils::FilePath m_ndkLocation;
mutable Utils::FilePath m_ndkLocation;
};
class AndroidToolChainFactory : public ProjectExplorer::ToolChainFactory
@@ -78,7 +78,10 @@ public:
QString version;
};
static ToolChainList autodetectToolChainsForNdk(const ToolChainList &alreadyKnown);
static ToolChainList autodetectToolChains(const ToolChainList &alreadyKnown);
static ToolChainList autodetectToolChainsFromNdks(const ToolChainList &alreadyKnown,
const QList<Utils::FilePath> &ndkLocations,
const bool isCustom = false);
};
} // namespace Internal

View File

@@ -29,7 +29,6 @@
#include <texteditor/codeassist/keywordscompletionassist.h>
#include <coreplugin/editormanager/ieditorfactory.h>
#include <texteditor/normalindenter.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/texteditorconstants.h>