aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/android/androidmanifesteditorwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/android/androidmanifesteditorwidget.cpp')
-rw-r--r--src/plugins/android/androidmanifesteditorwidget.cpp694
1 files changed, 331 insertions, 363 deletions
diff --git a/src/plugins/android/androidmanifesteditorwidget.cpp b/src/plugins/android/androidmanifesteditorwidget.cpp
index 87c2218cfe..6efa02e98e 100644
--- a/src/plugins/android/androidmanifesteditorwidget.cpp
+++ b/src/plugins/android/androidmanifesteditorwidget.cpp
@@ -24,14 +24,16 @@
****************************************************************************/
#include "androidmanifesteditorwidget.h"
+#include "androidmanifesteditoriconcontainerwidget.h"
#include "androidmanifesteditor.h"
#include "androidconfigurations.h"
#include "androidconstants.h"
#include "androidmanifestdocument.h"
#include "androidmanager.h"
+#include "androidservicewidget.h"
+#include "splashiconcontainerwidget.h"
#include <coreplugin/icore.h>
-#include <coreplugin/infobar.h>
#include <coreplugin/editormanager/ieditor.h>
#include <qtsupport/qtkitinformation.h>
@@ -50,6 +52,7 @@
#include <utils/algorithm.h>
#include <utils/fileutils.h>
+#include <utils/infobar.h>
#include <utils/stylehelper.h>
#include <utils/utilsicons.h>
@@ -67,8 +70,9 @@
#include <QLabel>
#include <QLineEdit>
#include <QListView>
-#include <QLoggingCategory>
+#include <QMessageBox>
#include <QPushButton>
+#include <QRegularExpression>
#include <QScrollArea>
#include <QSpinBox>
#include <QTimer>
@@ -77,22 +81,17 @@
#include <algorithm>
#include <limits>
-
-namespace {
-static Q_LOGGING_CATEGORY(androidManifestEditorLog, "qtc.android.manifestEditor", QtWarningMsg)
-}
-
using namespace ProjectExplorer;
using namespace Android;
using namespace Android::Internal;
namespace {
-const QLatin1String packageNameRegExp("^([a-z]{1}[a-z0-9_]+(\\.[a-zA-Z]{1}[a-zA-Z0-9_]*)*)$");
const char infoBarId[] = "Android.AndroidManifestEditor.InfoBar";
bool checkPackageName(const QString &packageName)
{
- return QRegExp(packageNameRegExp).exactMatch(packageName);
+ const QLatin1String packageNameRegExp("^([a-z]{1}[a-z0-9_]+(\\.[a-zA-Z]{1}[a-zA-Z0-9_]*)*)$");
+ return QRegularExpression(packageNameRegExp).match(packageName).hasMatch();
}
Target *androidTarget(const Utils::FilePath &fileName)
@@ -252,54 +251,16 @@ void AndroidManifestEditorWidget::initializePage()
m_styleExtractMethod->setItemData(i, styleMethodsMap.at(i).at(1), Qt::ToolTipRole);
}
- auto iconLayout = new QHBoxLayout();
-
- createDPIButton(iconLayout,
- applicationGroupBox,
- m_masterIconButton, iconSize(LowDPI),
- tr("Master icon"), tr("Select master icon."));
-
- m_masterIconButton->setIcon(QIcon::fromTheme(QLatin1String("document-open"), Utils::Icons::OPENFILE.icon()));
-
- iconLayout->addStretch(1);
-
- QFrame* line = new QFrame();
- line->setFrameShape(QFrame::VLine);
- line->setFrameShadow(QFrame::Sunken);
- iconLayout->addWidget(line);
-
- iconLayout->addStretch(1);
-
- createDPIButton(iconLayout,
- applicationGroupBox,
- m_lIconButton, iconSize(LowDPI),
- tr("Low DPI icon"), tr("Select low DPI icon."),
- &m_lIconClearButton,
- &m_lIconScaleWarningLabel);
-
- iconLayout->addStretch(1);
-
- createDPIButton(iconLayout,
- applicationGroupBox,
- m_mIconButton, iconSize(MediumDPI),
- tr("Medium DPI icon"), tr("Select medium DPI icon."),
- &m_mIconClearButton,
- &m_mIconScaleWarningLabel);
-
- iconLayout->addStretch(1);
-
- createDPIButton(iconLayout,
- applicationGroupBox,
- m_hIconButton, iconSize(HighDPI),
- tr("High DPI icon"), tr("Select high DPI icon."),
- &m_hIconClearButton,
- &m_hIconScaleWarningLabel);
-
- iconLayout->addStretch(6);
-
+ m_iconButtons = new AndroidManifestEditorIconContainerWidget(applicationGroupBox, m_textEditorWidget);
formLayout->addRow(tr("Application icon:"), new QLabel());
+ formLayout->addRow(QString(), m_iconButtons);
+
+ m_splashButtons = new SplashIconContainerWidget(applicationGroupBox, m_textEditorWidget);
+ formLayout->addRow(tr("Splash screen:"), new QLabel());
+ formLayout->addRow(QString(), m_splashButtons);
- formLayout->addRow(QString(), iconLayout);
+ m_services = new AndroidServiceWidget(this);
+ formLayout->addRow(tr("Android services:"), m_services);
applicationGroupBox->setLayout(formLayout);
@@ -312,21 +273,14 @@ void AndroidManifestEditorWidget::initializePage()
connect(m_styleExtractMethod,
QOverload<int>::of(&QComboBox::currentIndexChanged),
this, setDirtyFunc);
-
- connect(m_masterIconButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::setMasterIcon);
- connect(m_lIconButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::setLDPIIcon);
- connect(m_mIconButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::setMDPIIcon);
- connect(m_hIconButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::setHDPIIcon);
- connect(m_lIconClearButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::clearLDPIIcon);
- connect(m_mIconClearButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::clearMDPIIcon);
- connect(m_hIconClearButton, &QAbstractButton::clicked,
- this, &AndroidManifestEditorWidget::clearHDPIIcon);
+ connect(m_services, &AndroidServiceWidget::servicesModified,
+ this, setDirtyFunc);
+ connect(m_splashButtons, &SplashIconContainerWidget::splashScreensModified,
+ this, setDirtyFunc);
+ connect(m_services, &AndroidServiceWidget::servicesModified,
+ this, &AndroidManifestEditorWidget::clearInvalidServiceInfo);
+ connect(m_services, &AndroidServiceWidget::servicesInvalid,
+ this, &AndroidManifestEditorWidget::setInvalidServiceInfo);
}
@@ -602,6 +556,14 @@ AndroidManifestEditorWidget::EditorPage AndroidManifestEditorWidget::activePage(
return AndroidManifestEditorWidget::EditorPage(currentIndex());
}
+bool servicesValid(const QList<AndroidServiceData> &services)
+{
+ for (auto &&x : services)
+ if (!x.isValid())
+ return false;
+ return true;
+}
+
bool AndroidManifestEditorWidget::setActivePage(EditorPage page)
{
EditorPage prevPage = activePage();
@@ -610,6 +572,11 @@ bool AndroidManifestEditorWidget::setActivePage(EditorPage page)
return true;
if (page == Source) {
+ if (!servicesValid(m_services->services())) {
+ QMessageBox::critical(nullptr, tr("Service Definition Invalid"),
+ tr("Cannot switch to source when there are invalid services."));
+ return false;
+ }
syncToEditor();
} else {
if (!syncToWidgets())
@@ -630,16 +597,16 @@ bool AndroidManifestEditorWidget::setActivePage(EditorPage page)
void AndroidManifestEditorWidget::preSave()
{
- if (activePage() != Source)
+ if (activePage() != Source) {
+ if (!servicesValid(m_services->services())) {
+ QMessageBox::critical(nullptr, tr("Service Definition Invalid"),
+ tr("Cannot save when there are invalid services."));
+ return;
+ }
syncToEditor();
-
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- copyIcon(LowDPI, baseDir, m_lIconPath);
- copyIcon(MediumDPI, baseDir, m_mIconPath);
- copyIcon(HighDPI, baseDir, m_hIconPath);
+ }
// no need to emit changed() since this is called as part of saving
-
updateInfoBar();
}
@@ -754,13 +721,13 @@ void AndroidManifestEditorWidget::updateSdkVersions()
void AndroidManifestEditorWidget::updateInfoBar(const QString &errorMessage, int line, int column)
{
- Core::InfoBar *infoBar = m_textEditorWidget->textDocument()->infoBar();
+ Utils::InfoBar *infoBar = m_textEditorWidget->textDocument()->infoBar();
QString text;
if (line < 0)
text = tr("Could not parse file: \"%1\".").arg(errorMessage);
else
text = tr("%2: Could not parse file: \"%1\".").arg(errorMessage).arg(line);
- Core::InfoBarEntry infoBarEntry(infoBarId, text);
+ Utils::InfoBarEntry infoBarEntry(infoBarId, text);
infoBarEntry.setCustomButtonInfo(tr("Goto error"), [this]() {
m_textEditorWidget->gotoLine(m_errorLine, m_errorColumn);
});
@@ -774,9 +741,28 @@ void AndroidManifestEditorWidget::updateInfoBar(const QString &errorMessage, int
void AndroidManifestEditorWidget::hideInfoBar()
{
- Core::InfoBar *infoBar = m_textEditorWidget->textDocument()->infoBar();
+ Utils::InfoBar *infoBar = m_textEditorWidget->textDocument()->infoBar();
infoBar->removeInfo(infoBarId);
- m_timerParseCheck.stop();
+ m_timerParseCheck.stop();
+}
+
+static const char kServicesInvalid[] = "AndroidServiceDefinitionInvalid";
+
+void AndroidManifestEditorWidget::setInvalidServiceInfo()
+{
+ Utils::Id id(kServicesInvalid);
+ if (m_textEditorWidget->textDocument()->infoBar()->containsInfo(id))
+ return;
+ Utils::InfoBarEntry info(id,
+ tr("Services invalid. "
+ "Manifest cannot be saved. Correct the service definitions before saving."));
+ m_textEditorWidget->textDocument()->infoBar()->addInfo(info);
+
+}
+
+void AndroidManifestEditorWidget::clearInvalidServiceInfo()
+{
+ m_textEditorWidget->textDocument()->infoBar()->removeInfo(Utils::Id(kServicesInvalid));
}
void setApiLevel(QComboBox *box, const QDomElement &element, const QString &attribute)
@@ -820,33 +806,66 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
QDomElement activityElem = applicationElement.firstChildElement(QLatin1String("activity"));
m_activityNameLineEdit->setText(activityElem.attribute(QLatin1String("android:label")));
- QDomElement metadataElem = activityElem.firstChildElement(QLatin1String("meta-data"));
+ QString appIconValue = applicationElement.attribute(QLatin1String("android:icon"));
+ if (!appIconValue.isEmpty()) {
+ QLatin1String drawable = QLatin1String("@drawable/");
+ if (appIconValue.startsWith(drawable)) {
+ QString appIconName = appIconValue.mid(drawable.size());
+ m_iconButtons->setIconFileName(appIconName);
+ }
+ }
- const int parseItemsCount = 2;
- int counter = 0;
+ QDomElement metadataElem = activityElem.firstChildElement(QLatin1String("meta-data"));
+ enum ActivityParseGuard {none = 0, libName = 1, styleExtract = 2, stickySplash = 4, splashImages = 8, done = 16};
+ int activityParseGuard = ActivityParseGuard::none;
+ enum SplashImageParseGuard {splashNone = 0, splash = 1, portraitSplash = 2, landscapeSplash = 4, splashDone = 8};
+ int splashParseGuard = SplashImageParseGuard::splashNone;
while (!metadataElem.isNull()) {
- if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")) {
+ if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")
+ && !(activityParseGuard & ActivityParseGuard::libName)) {
m_targetLineEdit->setEditText(metadataElem.attribute(QLatin1String("android:value")));
- ++counter;
+ activityParseGuard |= ActivityParseGuard::libName;
} else if (metadataElem.attribute(QLatin1String("android:name"))
- == QLatin1String("android.app.extract_android_style")) {
+ == QLatin1String("android.app.extract_android_style")
+ && !(activityParseGuard & ActivityParseGuard::styleExtract)) {
m_styleExtractMethod->setCurrentText(
metadataElem.attribute(QLatin1String("android:value")));
- ++counter;
+ activityParseGuard |= ActivityParseGuard::styleExtract;
+ } else if (metadataElem.attribute(QLatin1String("android:name"))
+ == QLatin1String("android.app.splash_screen_sticky")
+ && !(activityParseGuard & ActivityParseGuard::stickySplash)) {
+ QString sticky = metadataElem.attribute(QLatin1String("android:value"));
+ m_splashButtons->setSticky(sticky == QLatin1String("true"));
+ activityParseGuard |= ActivityParseGuard::stickySplash;
+ } else if (metadataElem.attribute(QLatin1String("android:name"))
+ .startsWith(QLatin1String("android.app.splash_screen_drawable"))
+ && !(activityParseGuard & ActivityParseGuard::splashImages)
+ && !(splashParseGuard & SplashImageParseGuard::splashDone)) {
+ QString attrName = metadataElem.attribute(QLatin1String("android:name"));
+ QLatin1String drawable = QLatin1String("@drawable/");
+ QString splashImageValue = metadataElem.attribute(QLatin1String("android:resource"));
+ QString splashImageName;
+ if (splashImageValue.startsWith(drawable)) {
+ splashImageName = splashImageValue.mid(drawable.size());
+ }
+ if (attrName == QLatin1String("android.app.splash_screen_drawable")) {
+ m_splashButtons->setImageFileName(splashImageName);
+ splashParseGuard |= SplashImageParseGuard::splash;
+ } else if (attrName == QLatin1String("android.app.splash_screen_drawable_portrait")) {
+ m_splashButtons->setPortraitImageFileName(splashImageName);
+ splashParseGuard |= SplashImageParseGuard::portraitSplash;
+ } else if (attrName == QLatin1String("android.app.splash_screen_drawable_landscape")) {
+ m_splashButtons->setLandscapeImageFileName(splashImageName);
+ splashParseGuard |= SplashImageParseGuard::landscapeSplash;
+ }
+ if (splashParseGuard & SplashImageParseGuard::splashDone)
+ activityParseGuard |= ActivityParseGuard::splashImages;
}
-
- if (counter == parseItemsCount)
+ if (activityParseGuard == ActivityParseGuard::done)
break;
metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data"));
}
- copyIcon(LowDPI, baseDir, baseDir + iconPath(LowDPI));
- copyIcon(MediumDPI, baseDir, baseDir + iconPath(MediumDPI));
- copyIcon(HighDPI, baseDir, baseDir + iconPath(HighDPI));
- m_lIconButton->setIcon(icon(baseDir, LowDPI));
- m_mIconButton->setIcon(icon(baseDir, MediumDPI));
- m_hIconButton->setIcon(icon(baseDir, HighDPI));
-
disconnect(m_defaultPermissonsCheckBox, &QCheckBox::stateChanged,
this, &AndroidManifestEditorWidget::defaultPermissionOrFeatureCheckBoxClicked);
disconnect(m_defaultFeaturesCheckBox, &QCheckBox::stateChanged,
@@ -886,6 +905,36 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
m_permissionsModel->setPermissions(permissions);
updateAddRemovePermissionButtons();
+ QList<AndroidServiceData> services;
+ QDomElement serviceElem = applicationElement.firstChildElement(QLatin1String("service"));
+ while (!serviceElem.isNull()) {
+ AndroidServiceData service;
+ service.setClassName(serviceElem.attribute(QLatin1String("android:name")));
+ QString process = serviceElem.attribute(QLatin1String("android:process"));
+ service.setRunInExternalProcess(!process.isEmpty());
+ service.setExternalProcessName(process);
+ QDomElement serviceMetadataElem = serviceElem.firstChildElement(QLatin1String("meta-data"));
+ while (!serviceMetadataElem.isNull()) {
+ QString metadataName = serviceMetadataElem.attribute(QLatin1String("android:name"));
+ if (metadataName == QLatin1String("android.app.lib_name")) {
+ QString metadataValue = serviceMetadataElem.attribute(QLatin1String("android:value"));
+ service.setRunInExternalLibrary(metadataValue != QLatin1String("-- %%INSERT_APP_LIB_NAME%% --"));
+ service.setExternalLibraryName(metadataValue);
+ }
+ else if (metadataName == QLatin1String("android.app.arguments")) {
+ QString metadataValue = serviceMetadataElem.attribute(QLatin1String("android:value"));
+ service.setServiceArguments(metadataValue);
+ }
+ serviceMetadataElem = serviceMetadataElem.nextSiblingElement(QLatin1String("meta-data"));
+ }
+ services << service;
+ serviceElem = serviceElem.nextSiblingElement(QLatin1String("service"));
+ }
+ m_services->setServices(services);
+
+ m_iconButtons->loadIcons();
+ m_splashButtons->loadImages();
+
m_stayClean = false;
m_dirty = false;
}
@@ -1048,12 +1097,10 @@ void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXm
QStringList keys = {QLatin1String("android:label")};
QStringList values = {m_appNameLineEdit->text()};
QStringList remove;
- bool ensureIconAttribute = !m_lIconPath.isEmpty()
- || !m_mIconPath.isEmpty()
- || !m_hIconPath.isEmpty();
+ bool ensureIconAttribute = m_iconButtons->hasIcons();
if (ensureIconAttribute) {
keys << QLatin1String("android:icon");
- values << QLatin1String("@drawable/icon");
+ values << (QLatin1String("@drawable/") + m_iconButtons->iconFileName());
} else
remove << QLatin1String("android:icon");
@@ -1064,13 +1111,19 @@ void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXm
while (!reader.atEnd()) {
if (reader.isEndElement()) {
+ parseNewServices(writer);
writer.writeCurrentToken(reader);
+ m_services->servicesSaved();
return;
} else if (reader.isStartElement()) {
if (reader.name() == QLatin1String("activity"))
parseActivity(reader, writer);
+ else if (reader.name() == QLatin1String("service"))
+ parseService(reader, writer);
else
parseUnknownElement(reader, writer);
+ } else if (reader.isWhitespace()) {
+ /* no copying of whitespace */
} else {
writer.writeCurrentToken(reader);
}
@@ -1079,6 +1132,164 @@ void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXm
}
}
+static void writeMetadataElement(const char *name,
+ const char *attributeName,
+ const QString &value,
+ QXmlStreamWriter &writer)
+{
+ writer.writeStartElement(QLatin1String("meta-data"));
+ writer.writeAttribute(QLatin1String("android:name"), QLatin1String(name));
+ writer.writeAttribute(QLatin1String(attributeName), value);
+ writer.writeEndElement();
+
+}
+
+void AndroidManifestEditorWidget::parseSplashScreen(QXmlStreamWriter &writer)
+{
+ if (m_splashButtons->hasImages())
+ writeMetadataElement("android.app.splash_screen_drawable",
+ "android:resource", QLatin1String("@drawable/") + m_splashButtons->imageFileName(),
+ writer);
+ if (m_splashButtons->hasPortraitImages())
+ writeMetadataElement("android.app.splash_screen_drawable_portrait",
+ "android:resource", QLatin1String("@drawable/") + m_splashButtons->portraitImageFileName(),
+ writer);
+ if (m_splashButtons->hasLandscapeImages())
+ writeMetadataElement("android.app.splash_screen_drawable_landscape",
+ "android:resource", QLatin1String("@drawable/") + m_splashButtons->landscapeImageFileName(),
+ writer);
+ if (m_splashButtons->isSticky())
+ writeMetadataElement("android.app.splash_screen_sticky",
+ "android:value", "true",
+ writer);
+}
+
+static int findService(const QString &name, const QList<AndroidServiceData> &data)
+{
+ for (int i = 0; i < data.size(); ++i) {
+ if (data[i].className() == name)
+ return i;
+ }
+ return -1;
+}
+
+static void writeMetadataElement(const char *name,
+ const char *attributeName,
+ const char *value,
+ QXmlStreamWriter &writer)
+{
+ writer.writeStartElement(QLatin1String("meta-data"));
+ writer.writeAttribute(QLatin1String("android:name"), QLatin1String(name));
+ writer.writeAttribute(QLatin1String(attributeName), QLatin1String(value));
+ writer.writeEndElement();
+
+}
+
+static void addServiceArgumentsAndLibName(const AndroidServiceData &service, QXmlStreamWriter &writer)
+{
+ if (!service.isRunInExternalLibrary() && !service.serviceArguments().isEmpty())
+ writeMetadataElement("android.app.arguments", "android:value", service.serviceArguments(), writer);
+ if (service.isRunInExternalLibrary() && !service.externalLibraryName().isEmpty())
+ writeMetadataElement("android.app.lib_name", "android:value", service.externalLibraryName(), writer);
+ else
+ writeMetadataElement("android.app.lib_name", "android:value", "-- %%INSERT_APP_LIB_NAME%% --", writer);
+}
+
+static void addServiceMetadata(QXmlStreamWriter &writer)
+{
+ writeMetadataElement("android.app.qt_sources_resource_id", "android:resource", "@array/qt_sources", writer);
+ writeMetadataElement("android.app.repository", "android:value", "default", writer);
+ writeMetadataElement("android.app.qt_libs_resource_id", "android:resource", "@array/qt_libs", writer);
+ writeMetadataElement("android.app.bundled_libs_resource_id", "android:resource", "@array/bundled_libs", writer);
+ writeMetadataElement("android.app.bundle_local_qt_libs", "android:value", "-- %%BUNDLE_LOCAL_QT_LIBS%% --", writer);
+ writeMetadataElement("android.app.use_local_qt_libs", "android:value", "-- %%USE_LOCAL_QT_LIBS%% --", writer);
+ writeMetadataElement("android.app.libs_prefix", "android:value", "/data/local/tmp/qt/", writer);
+ writeMetadataElement("android.app.load_local_libs_resource_id", "android:resource", "@array/load_local_libs", writer);
+ writeMetadataElement("android.app.load_local_jars", "android:value", "-- %%INSERT_LOCAL_JARS%% --", writer);
+ writeMetadataElement("android.app.static_init_classes", "android:value", "-- %%INSERT_INIT_CLASSES%% --", writer);
+}
+
+void AndroidManifestEditorWidget::parseService(QXmlStreamReader &reader, QXmlStreamWriter &writer)
+{
+ Q_ASSERT(reader.isStartElement());
+ const auto &services = m_services->services();
+ QString serviceName = reader.attributes().value(QLatin1String("android:name")).toString();
+ int serviceIndex = findService(serviceName, services);
+ const AndroidServiceData* serviceFound = (serviceIndex >= 0) ? &services[serviceIndex] : nullptr;
+ if (serviceFound && serviceFound->isValid()) {
+ writer.writeStartElement(reader.name().toString());
+ writer.writeAttribute(QLatin1String("android:name"), serviceFound->className());
+ if (serviceFound->isRunInExternalProcess())
+ writer.writeAttribute(QLatin1String("android:process"), serviceFound->externalProcessName());
+ }
+
+ reader.readNext();
+
+ bool bundleTagFound = false;
+
+ while (!reader.atEnd()) {
+ if (reader.isEndElement()) {
+ if (serviceFound && serviceFound->isValid()) {
+ addServiceArgumentsAndLibName(*serviceFound, writer);
+ if (serviceFound->isRunInExternalProcess() && !bundleTagFound)
+ addServiceMetadata(writer);
+ writer.writeCurrentToken(reader);
+ }
+ return;
+ } else if (reader.isStartElement()) {
+ if (serviceFound && !serviceFound->isValid())
+ parseUnknownElement(reader, writer, true);
+ else if (reader.name() == QLatin1String("meta-data")) {
+ QString metaTagName = reader.attributes().value(QLatin1String("android:name")).toString();
+ if (serviceFound) {
+ if (metaTagName == QLatin1String("android.app.bundle_local_qt_libs"))
+ bundleTagFound = true;
+ if (metaTagName == QLatin1String("android.app.arguments"))
+ parseUnknownElement(reader, writer, true);
+ else if (metaTagName == QLatin1String("android.app.lib_name"))
+ parseUnknownElement(reader, writer, true);
+ else if (serviceFound->isRunInExternalProcess()
+ || metaTagName == QLatin1String("android.app.background_running"))
+ parseUnknownElement(reader, writer);
+ else
+ parseUnknownElement(reader, writer, true);
+ } else
+ parseUnknownElement(reader, writer, true);
+ } else
+ parseUnknownElement(reader, writer, true);
+ } else if (reader.isWhitespace()) {
+ /* no copying of whitespace */
+ } else {
+ if (serviceFound)
+ writer.writeCurrentToken(reader);
+ }
+ reader.readNext();
+ }
+}
+
+void AndroidManifestEditorWidget::parseNewServices(QXmlStreamWriter &writer)
+{
+ const auto &services = m_services->services();
+ for (const auto &x : services) {
+ if (x.isNewService() && x.isValid()) {
+ writer.writeStartElement(QLatin1String("service"));
+ writer.writeAttribute(QLatin1String("android:name"), x.className());
+ if (x.isRunInExternalProcess()) {
+ writer.writeAttribute(QLatin1String("android:process"),
+ x.externalProcessName());
+ }
+ addServiceArgumentsAndLibName(x, writer);
+ if (x.isRunInExternalProcess())
+ addServiceMetadata(writer);
+ writer.writeStartElement(QLatin1String("meta-data"));
+ writer.writeAttribute(QLatin1String("android:name"), QLatin1String("android.app.background_running"));
+ writer.writeAttribute(QLatin1String("android:value"), QLatin1String("true"));
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+ }
+}
+
void AndroidManifestEditorWidget::parseActivity(QXmlStreamReader &reader, QXmlStreamWriter &writer)
{
Q_ASSERT(reader.isStartElement());
@@ -1096,6 +1307,7 @@ void AndroidManifestEditorWidget::parseActivity(QXmlStreamReader &reader, QXmlSt
while (!reader.atEnd()) {
if (reader.isEndElement()) {
+ parseSplashScreen(writer);
if (!found) {
writer.writeEmptyElement(QLatin1String("meta-data"));
writer.writeAttribute(QLatin1String("android:name"),
@@ -1106,10 +1318,16 @@ void AndroidManifestEditorWidget::parseActivity(QXmlStreamReader &reader, QXmlSt
writer.writeCurrentToken(reader);
return;
} else if (reader.isStartElement()) {
- if (reader.name() == QLatin1String("meta-data"))
- found = parseMetaData(reader, writer) || found; // ORDER MATTERS
- else
+ if (reader.name() == QLatin1String("meta-data")) {
+ QString metaTagName = reader.attributes().value(QLatin1String("android:name")).toString();
+ if (metaTagName.startsWith(QLatin1String("android.app.splash_screen")))
+ parseUnknownElement(reader, writer, true);
+ else
+ found = parseMetaData(reader, writer) || found; // ORDER MATTERS
+ } else
parseUnknownElement(reader, writer);
+ } else if (reader.isWhitespace()) {
+ /* no copying of whitespace */
} else {
writer.writeCurrentToken(reader);
}
@@ -1256,273 +1474,29 @@ QString AndroidManifestEditorWidget::parseComment(QXmlStreamReader &reader, QXml
return commentText;
}
-void AndroidManifestEditorWidget::parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer)
+void AndroidManifestEditorWidget::parseUnknownElement(QXmlStreamReader &reader, QXmlStreamWriter &writer,
+ bool ignore)
{
Q_ASSERT(reader.isStartElement());
- writer.writeCurrentToken(reader);
+ if (!ignore)
+ writer.writeCurrentToken(reader);
reader.readNext();
while (!reader.atEnd()) {
if (reader.isEndElement()) {
- writer.writeCurrentToken(reader);
+ if (!ignore)
+ writer.writeCurrentToken(reader);
return;
} else if (reader.isStartElement()) {
- parseUnknownElement(reader, writer);
+ parseUnknownElement(reader, writer, ignore);
} else {
- writer.writeCurrentToken(reader);
+ if (!ignore)
+ writer.writeCurrentToken(reader);
}
reader.readNext();
}
}
-QString AndroidManifestEditorWidget::iconPath(IconDPI dpi)
-{
- switch (dpi) {
- case HighDPI:
- return QString("/res/drawable-hdpi/icon.png");
- case MediumDPI:
- return QString("/res/drawable-mdpi/icon.png");
- case LowDPI:
- return QString("/res/drawable-ldpi/icon.png");
- }
- return {};
-}
-
-QSize AndroidManifestEditorWidget::iconSize(IconDPI dpi)
-{
- switch (dpi) {
- case HighDPI:
- return QSize(72, 72);
- case MediumDPI:
- return QSize(48, 48);
- case LowDPI:
- return QSize(32, 32);
- }
- return QSize(72, 72);
-}
-
-void AndroidManifestEditorWidget::updateIconPath(const QString &newPath, IconDPI dpi)
-{
- switch (dpi) {
- case HighDPI:
- m_hIconPath = newPath;
- break;
- case MediumDPI:
- m_mIconPath = newPath;
- break;
- case LowDPI:
- m_lIconPath = newPath;
- break;
- }
-}
-
-QIcon AndroidManifestEditorWidget::icon(const QString &baseDir, IconDPI dpi)
-{
-
- if (dpi == HighDPI && !m_hIconPath.isEmpty())
- return QIcon(m_hIconPath);
-
- if (dpi == MediumDPI && !m_mIconPath.isEmpty())
- return QIcon(m_mIconPath);
-
- if (dpi == LowDPI && !m_lIconPath.isEmpty())
- return QIcon(m_lIconPath);
-
- QString fileName = baseDir + iconPath(dpi);
- if (fileName.isEmpty())
- return QIcon();
- return QIcon(fileName);
-}
-
-void AndroidManifestEditorWidget::copyIcon(IconDPI dpi, const QString &baseDir, const QString &filePath)
-{
- const QString targetPath = baseDir + iconPath(dpi);
- if (targetPath.isEmpty()) {
- qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot copy icon.";
- return;
- }
- QFileInfo targetFile(targetPath);
- if (filePath != targetPath)
- removeIcon(dpi, baseDir);
- QImage original(filePath);
- if (!targetPath.isEmpty() && !original.isNull()) {
- if (filePath != targetPath) {
- QDir dir;
- dir.mkpath(QFileInfo(targetPath).absolutePath());
- QSize targetSize = iconSize(dpi);
- QImage scaled = original.scaled(targetSize.width(), targetSize.height(),
- Qt::KeepAspectRatio, Qt::SmoothTransformation);
- toggleIconScaleWarning(dpi, scaled.width() > original.width() || scaled.height() > original.height());
- scaled.save(targetPath);
- }
- updateIconPath(targetPath, dpi);
- }
-}
-
-void AndroidManifestEditorWidget::removeIcon(IconDPI dpi, const QString &baseDir)
-{
- const QString targetPath = baseDir + iconPath(dpi);
- if (targetPath.isEmpty()) {
- qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot remove icon.";
- return;
- }
- QFileInfo targetFile(targetPath);
- if (targetFile.exists()) {
- QDir rmRf(targetFile.absoluteDir());
- rmRf.removeRecursively();
- }
- toggleIconScaleWarning(dpi, false);
-}
-
-void AndroidManifestEditorWidget::toggleIconScaleWarning(IconDPI dpi, bool visible)
-{
- switch (dpi) {
- case HighDPI:
- m_hIconScaleWarningLabel->setVisible(visible);
- break;
- case MediumDPI:
- m_mIconScaleWarningLabel->setVisible(visible);
- break;
- case LowDPI:
- m_lIconScaleWarningLabel->setVisible(visible);
- break;
- }
-}
-
-const auto fileDialogIconFiles = QWidget::tr("Images (*.png *.jpg *.webp *.svg)");
-
-void AndroidManifestEditorWidget::setMasterIcon()
-{
- QString file = QFileDialog::getOpenFileName(this, tr("Choose Master Icon"), QDir::homePath(), fileDialogIconFiles);
- if (file.isEmpty())
- return;
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- copyIcon(LowDPI, baseDir, file);
- copyIcon(MediumDPI, baseDir, file);
- copyIcon(HighDPI, baseDir, file);
- m_lIconButton->setIcon(icon(baseDir, LowDPI));
- m_mIconButton->setIcon(icon(baseDir, MediumDPI));
- m_hIconButton->setIcon(icon(baseDir, HighDPI));
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::setLDPIIcon()
-{
- QString file = QFileDialog::getOpenFileName(this, tr("Choose Low DPI Icon"), QDir::homePath(), fileDialogIconFiles);
- if (file.isEmpty())
- return;
- m_lIconPath = file;
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- copyIcon(LowDPI, baseDir, m_lIconPath);
- m_lIconButton->setIcon(icon(baseDir, LowDPI));
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::setMDPIIcon()
-{
- QString file = QFileDialog::getOpenFileName(this, tr("Choose Medium DPI Icon"), QDir::homePath(), fileDialogIconFiles);
- if (file.isEmpty())
- return;
- m_mIconPath = file;
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- copyIcon(MediumDPI, baseDir, m_mIconPath);
- m_mIconButton->setIcon(icon(baseDir, MediumDPI));
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::setHDPIIcon()
-{
- QString file = QFileDialog::getOpenFileName(this, tr("Choose High DPI Icon"), QDir::homePath(), fileDialogIconFiles);
- if (file.isEmpty())
- return;
- m_hIconPath = file;
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- copyIcon(HighDPI, baseDir, m_hIconPath);
- m_hIconButton->setIcon(icon(baseDir, HighDPI));
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::clearLDPIIcon()
-{
- m_lIconPath.clear();
- m_lIconButton->setIcon(QIcon());
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- removeIcon(LowDPI, baseDir);
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::clearMDPIIcon()
-{
- m_mIconPath.clear();
- m_mIconButton->setIcon(QIcon());
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- removeIcon(MediumDPI, baseDir);
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::clearHDPIIcon()
-{
- m_hIconPath.clear();
- m_hIconButton->setIcon(QIcon());
- QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
- removeIcon(HighDPI, baseDir);
- syncToEditor();
-}
-
-void AndroidManifestEditorWidget::createDPIButton(QHBoxLayout *layout,
- QWidget *parent,
- QToolButton *&button,
- const QSize &buttonSize,
- const QString &title,
- const QString &tooltip,
- QToolButton **clearButton,
- QLabel **scaleWarningLabel)
-{
- auto iconLayout = new QVBoxLayout();
- auto iconTitle = new QLabel(title, parent);
- auto iconButtonLayout = new QGridLayout();
- button = new QToolButton(parent);
- button->setMinimumSize(buttonSize);
- button->setMaximumSize(buttonSize);
- button->setToolTip(tooltip);
- button->setIconSize(buttonSize);
- QSize clearAndWarningSize(16, 16);
- if (clearButton) {
- *clearButton = new QToolButton(parent);
- (*clearButton)->setMinimumSize(clearAndWarningSize);
- (*clearButton)->setMaximumSize(clearAndWarningSize);
- (*clearButton)->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon());
- }
- if (scaleWarningLabel) {
- *scaleWarningLabel = new QLabel(parent);
- (*scaleWarningLabel)->setMinimumSize(clearAndWarningSize);
- (*scaleWarningLabel)->setMaximumSize(clearAndWarningSize);
- (*scaleWarningLabel)->setPixmap(Utils::Icons::WARNING.icon().pixmap(clearAndWarningSize));
- (*scaleWarningLabel)->setToolTip(tr("Icon scaled up"));
- (*scaleWarningLabel)->setVisible(false);
- }
- auto label = new QLabel(tr("Click to select"), parent);
- iconLayout->addWidget(iconTitle);
- iconLayout->setAlignment(iconTitle, Qt::AlignHCenter);
- iconButtonLayout->setColumnMinimumWidth(0, 16);
- iconButtonLayout->addWidget(button, 0, 1, 1, 3);
- iconButtonLayout->setAlignment(button, Qt::AlignVCenter);
- if (clearButton) {
- iconButtonLayout->addWidget(*clearButton, 0, 4, 1, 1);
- iconButtonLayout->setAlignment(*clearButton, Qt::AlignTop);
- }
- if (scaleWarningLabel) {
- iconButtonLayout->addWidget(*scaleWarningLabel, 0, 0, 1, 1);
- iconButtonLayout->setAlignment(*scaleWarningLabel, Qt::AlignTop);
- }
- iconLayout->addLayout(iconButtonLayout);
- iconLayout->setAlignment(iconButtonLayout, Qt::AlignHCenter);
- iconLayout->addWidget(label);
- iconLayout->setAlignment(label, Qt::AlignHCenter);
-
- layout->addLayout(iconLayout);
-}
-
void AndroidManifestEditorWidget::defaultPermissionOrFeatureCheckBoxClicked()
{
setDirty(true);
@@ -1660,9 +1634,3 @@ AndroidManifestTextEditorWidget::AndroidManifestTextEditorWidget(AndroidManifest
m_context->setContext(Core::Context(Constants::ANDROID_MANIFEST_EDITOR_CONTEXT));
Core::ICore::addContextObject(m_context);
}
-
-AndroidManifestTextEditorWidget::~AndroidManifestTextEditorWidget()
-{
- Core::ICore::removeContextObject(m_context);
-}
-