summaryrefslogtreecommitdiff
path: root/src/plugins/android/androidmanifesteditorwidget.cpp
diff options
context:
space:
mode:
authorVille Voutilainen <ville.voutilainen@qt.io>2020-05-07 09:07:39 +0300
committerVille Voutilainen <ville.voutilainen@qt.io>2020-05-25 11:18:09 +0000
commit52188918c0d4c90c38be99eb2c4586dd3a11b67f (patch)
tree3bdab8da448f5fa9c1d770d39b7c614844100285 /src/plugins/android/androidmanifesteditorwidget.cpp
parent14666c801aeaa4a7b12ed43e33f50e71f4345269 (diff)
downloadqt-creator-52188918c0d4c90c38be99eb2c4586dd3a11b67f.tar.gz
Android: add service editor to manifest editor
Task-number: QTCREATORBUG-23937 Change-Id: Iec0435721504df744ec985bd3e5cefcc0700e852 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
Diffstat (limited to 'src/plugins/android/androidmanifesteditorwidget.cpp')
-rw-r--r--src/plugins/android/androidmanifesteditorwidget.cpp238
1 files changed, 231 insertions, 7 deletions
diff --git a/src/plugins/android/androidmanifesteditorwidget.cpp b/src/plugins/android/androidmanifesteditorwidget.cpp
index 7e1dbf540e..3a7296b508 100644
--- a/src/plugins/android/androidmanifesteditorwidget.cpp
+++ b/src/plugins/android/androidmanifesteditorwidget.cpp
@@ -30,6 +30,7 @@
#include "androidconstants.h"
#include "androidmanifestdocument.h"
#include "androidmanager.h"
+#include "androidservicewidget.h"
#include <coreplugin/icore.h>
#include <coreplugin/infobar.h>
@@ -68,6 +69,7 @@
#include <QLabel>
#include <QLineEdit>
#include <QListView>
+#include <QMessageBox>
#include <QPushButton>
#include <QScrollArea>
#include <QSpinBox>
@@ -253,6 +255,9 @@ void AndroidManifestEditorWidget::initializePage()
formLayout->addRow(QString(), m_iconButtons);
+ m_services = new AndroidServiceWidget(this);
+ formLayout->addRow(tr("Android services:"), m_services);
+
applicationGroupBox->setLayout(formLayout);
connect(m_appNameLineEdit, &QLineEdit::textEdited,
@@ -264,6 +269,12 @@ void AndroidManifestEditorWidget::initializePage()
connect(m_styleExtractMethod,
QOverload<int>::of(&QComboBox::currentIndexChanged),
this, setDirtyFunc);
+ connect(m_services, &AndroidServiceWidget::servicesModified,
+ this, setDirtyFunc);
+ connect(m_services, &AndroidServiceWidget::servicesModified,
+ this, &AndroidManifestEditorWidget::clearInvalidServiceInfo);
+ connect(m_services, &AndroidServiceWidget::servicesInvalid,
+ this, &AndroidManifestEditorWidget::setInvalidServiceInfo);
}
@@ -539,6 +550,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();
@@ -547,6 +566,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())
@@ -567,8 +591,14 @@ 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();
+ }
// no need to emit changed() since this is called as part of saving
updateInfoBar();
@@ -707,7 +737,26 @@ void AndroidManifestEditorWidget::hideInfoBar()
{
Core::InfoBar *infoBar = m_textEditorWidget->textDocument()->infoBar();
infoBar->removeInfo(infoBarId);
- m_timerParseCheck.stop();
+ m_timerParseCheck.stop();
+}
+
+static const char kServicesInvalid[] = "AndroidServiceDefinitionInvalid";
+
+void AndroidManifestEditorWidget::setInvalidServiceInfo()
+{
+ Core::Id id(kServicesInvalid);
+ if (m_textEditorWidget->textDocument()->infoBar()->containsInfo(id))
+ return;
+ Core::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(Core::Id(kServicesInvalid));
}
void setApiLevel(QComboBox *box, const QDomElement &element, const QString &attribute)
@@ -810,6 +859,33 @@ 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_stayClean = false;
@@ -988,13 +1064,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);
}
@@ -1003,6 +1085,144 @@ void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXm
}
}
+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 writeServiceMetadataElement(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 writeServiceMetadataElement(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();
+
+}
+
+static void addServiceArgumentsAndLibName(const AndroidServiceData &service, QXmlStreamWriter &writer)
+{
+ if (!service.isRunInExternalLibrary() && !service.serviceArguments().isEmpty())
+ writeServiceMetadataElement("android.app.arguments", "android:value", service.serviceArguments(), writer);
+ if (service.isRunInExternalLibrary() && !service.externalLibraryName().isEmpty())
+ writeServiceMetadataElement("android.app.lib_name", "android:value", service.externalLibraryName(), writer);
+ else
+ writeServiceMetadataElement("android.app.lib_name", "android:value", "-- %%INSERT_APP_LIB_NAME%% --", writer);
+}
+
+static void addServiceMetadata(QXmlStreamWriter &writer)
+{
+ writeServiceMetadataElement("android.app.qt_sources_resource_id", "android:resource", "@array/qt_sources", writer);
+ writeServiceMetadataElement("android.app.repository", "android:value", "default", writer);
+ writeServiceMetadataElement("android.app.qt_libs_resource_id", "android:resource", "@array/qt_libs", writer);
+ writeServiceMetadataElement("android.app.bundled_libs_resource_id", "android:resource", "@array/bundled_libs", writer);
+ writeServiceMetadataElement("android.app.bundle_local_qt_libs", "android:value", "-- %%BUNDLE_LOCAL_QT_LIBS%% --", writer);
+ writeServiceMetadataElement("android.app.use_local_qt_libs", "android:value", "-- %%USE_LOCAL_QT_LIBS%% --", writer);
+ writeServiceMetadataElement("android.app.libs_prefix", "android:value", "/data/local/tmp/qt/", writer);
+ writeServiceMetadataElement("android.app.load_local_libs_resource_id", "android:resource", "@array/load_local_libs", writer);
+ writeServiceMetadataElement("android.app.load_local_jars", "android:value", "-- %%INSERT_LOCAL_JARS%% --", writer);
+ writeServiceMetadataElement("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());
@@ -1180,20 +1400,24 @@ 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();
}