diff --git a/src/plugins/android/android.pro b/src/plugins/android/android.pro index 3d63124af5a83fc5ba36d2f3163734e6c68c65ef..6ef13cc781a009cc8cdcd04573392cbd4814634c 100644 --- a/src/plugins/android/android.pro +++ b/src/plugins/android/android.pro @@ -50,7 +50,8 @@ HEADERS += \ androidrunnable.h \ androidtoolmanager.h \ androidsdkmanager.h \ - androidavdmanager.h + androidavdmanager.h \ + androidrunconfigurationwidget.h SOURCES += \ androidconfigurations.cpp \ @@ -94,7 +95,8 @@ SOURCES += \ androidrunnable.cpp \ androidtoolmanager.cpp \ androidsdkmanager.cpp \ - androidavdmanager.cpp + androidavdmanager.cpp \ + androidrunconfigurationwidget.cpp FORMS += \ androidsettingswidget.ui \ @@ -102,7 +104,8 @@ FORMS += \ androidcreatekeystorecertificate.ui \ androiddevicedialog.ui \ androiddeployqtwidget.ui \ - androidbuildapkwidget.ui + androidbuildapkwidget.ui \ + androidrunconfigurationwidget.ui RESOURCES = android.qrc diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index c3a2551bae01385bcff6d2afa831f0820f180070..5e5d5a45742769feb2851d07ecfa74d01567e843 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -78,6 +78,9 @@ Project { "androidqtversionfactory.h", "androidrunconfiguration.cpp", "androidrunconfiguration.h", + "androidrunconfigurationwidget.cpp", + "androidrunconfigurationwidget.h", + "androidrunconfigurationwidget.ui", "androidruncontrol.cpp", "androidruncontrol.h", "androidrunfactories.cpp", diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index 681bc91ef79bdde9d523e5e2bb7bcbf9bebd6108..7b69ed2364f91e7f3b485b7d719b645df5da0ced 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -27,6 +27,7 @@ #include "androidglobal.h" #include "androidtoolchain.h" #include "androidmanager.h" +#include "androidrunconfigurationwidget.h" #include <projectexplorer/kitinformation.h> #include <projectexplorer/target.h> @@ -38,6 +39,8 @@ using namespace ProjectExplorer; namespace Android { +using namespace Internal; +const char amStartArgsKey[] = "Android.AmStartArgsKey"; AndroidRunConfiguration::AndroidRunConfiguration(Target *parent, Core::Id id) : RunConfiguration(parent, id) @@ -49,9 +52,18 @@ AndroidRunConfiguration::AndroidRunConfiguration(Target *parent, AndroidRunConfi { } +void AndroidRunConfiguration::setAmStartExtraArgs(const QStringList &args) +{ + m_amStartExtraArgs = args; +} + QWidget *AndroidRunConfiguration::createConfigurationWidget() { - return 0;// no special running configurations + auto configWidget = new AndroidRunConfigurationWidget(); + configWidget->setAmStartArgs(m_amStartExtraArgs); + connect(configWidget, &AndroidRunConfigurationWidget::amStartArgsChanged, + this, &AndroidRunConfiguration::setAmStartExtraArgs); + return configWidget; } Utils::OutputFormatter *AndroidRunConfiguration::createOutputFormatter() const @@ -59,4 +71,21 @@ Utils::OutputFormatter *AndroidRunConfiguration::createOutputFormatter() const return new QtSupport::QtOutputFormatter(target()->project()); } +bool AndroidRunConfiguration::fromMap(const QVariantMap &map) +{ + m_amStartExtraArgs = map.value(amStartArgsKey).toStringList(); + return RunConfiguration::fromMap(map); +} + +QVariantMap AndroidRunConfiguration::toMap() const +{ + QVariantMap res = RunConfiguration::toMap(); + res[amStartArgsKey] = m_amStartExtraArgs; + return res; +} + +const QStringList &AndroidRunConfiguration::amStartExtraArgs() const +{ + return m_amStartExtraArgs; +} } // namespace Android diff --git a/src/plugins/android/androidrunconfiguration.h b/src/plugins/android/androidrunconfiguration.h index 7f4e1a941ef56a7a442d23d1daeb47dc67b7f489..3ba7d25d7dbd1be7bcc1f61682f5d11bf2a1a1e1 100644 --- a/src/plugins/android/androidrunconfiguration.h +++ b/src/plugins/android/androidrunconfiguration.h @@ -44,8 +44,19 @@ public: QWidget *createConfigurationWidget() override; Utils::OutputFormatter *createOutputFormatter() const override; + bool fromMap(const QVariantMap &map) override; + QVariantMap toMap() const override; + + const QStringList &amStartExtraArgs() const; + protected: AndroidRunConfiguration(ProjectExplorer::Target *parent, AndroidRunConfiguration *source); + +private: + void setAmStartExtraArgs(const QStringList &args); + +private: + QStringList m_amStartExtraArgs; }; } // namespace Android diff --git a/src/plugins/android/androidrunconfigurationwidget.cpp b/src/plugins/android/androidrunconfigurationwidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba4d038408d18a32c7b33154d6fcae1607969b84 --- /dev/null +++ b/src/plugins/android/androidrunconfigurationwidget.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "androidrunconfigurationwidget.h" +#include "ui_androidrunconfigurationwidget.h" + +#include "utils/utilsicons.h" +#include "utils/qtcprocess.h" + +namespace Android { +namespace Internal { + +AndroidRunConfigurationWidget::AndroidRunConfigurationWidget(QWidget *parent): + Utils::DetailsWidget(parent), + m_ui(new Ui::AndroidRunConfigurationWidget) +{ + auto detailsWidget = new QWidget(this); + m_ui->setupUi(detailsWidget); + m_ui->m_warningIconLabel->setPixmap(Utils::Icons::WARNING.pixmap()); + + setWidget(detailsWidget); + setSummaryText(tr("Android run settings")); + + connect(m_ui->m_amStartArgsEdit, &QLineEdit::editingFinished, [this]() { + QString optionText = m_ui->m_amStartArgsEdit->text().simplified(); + emit amStartArgsChanged(optionText.split(' ')); + }); +} + +AndroidRunConfigurationWidget::~AndroidRunConfigurationWidget() +{ +} + +void AndroidRunConfigurationWidget::setAmStartArgs(const QStringList &args) +{ + if (m_ui->m_amStartArgsEdit && !args.isEmpty()) + m_ui->m_amStartArgsEdit->setText(Utils::QtcProcess::joinArgs(args, Utils::OsTypeLinux)); +} + +} // namespace Internal +} // namespace Android + diff --git a/src/plugins/android/androidrunconfigurationwidget.h b/src/plugins/android/androidrunconfigurationwidget.h new file mode 100644 index 0000000000000000000000000000000000000000..14d1d923dbb5afba6706b2e359bdfc33e57eac57 --- /dev/null +++ b/src/plugins/android/androidrunconfigurationwidget.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "androidrunconfiguration.h" + +#include "projectexplorer/runconfiguration.h" +#include "utils/detailswidget.h" + + +namespace Android { +namespace Internal { + +namespace Ui { + class AndroidRunConfigurationWidget; +} + +class AndroidRunConfigurationWidget : public Utils::DetailsWidget +{ + Q_OBJECT +public: + AndroidRunConfigurationWidget(QWidget *parent = nullptr); + ~AndroidRunConfigurationWidget(); + + void setAmStartArgs(const QStringList &args); + +signals: + void amStartArgsChanged(QStringList args); + +private: + std::unique_ptr<Ui::AndroidRunConfigurationWidget> m_ui; +}; + +} // namespace Internal +} // namespace Android + diff --git a/src/plugins/android/androidrunconfigurationwidget.ui b/src/plugins/android/androidrunconfigurationwidget.ui new file mode 100644 index 0000000000000000000000000000000000000000..cd7ed3df801f60505cf89ed393a8bf73be1d4a9a --- /dev/null +++ b/src/plugins/android/androidrunconfigurationwidget.ui @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Android::Internal::AndroidRunConfigurationWidget</class> + <widget class="QWidget" name="Android::Internal::AndroidRunConfigurationWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>625</width> + <height>73</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="2"> + <widget class="QLineEdit" name="m_amStartArgsEdit"/> + </item> + <item row="1" column="2"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Conflicting "am start" options might result in the app startup failure.</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="m_warningIconLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="1" column="0"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="0" colspan="2"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Activity manager start options:</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/plugins/android/androidrunnable.cpp b/src/plugins/android/androidrunnable.cpp index f91d7cf63e1d55ee1522e4ca009720803cc62a84..ae70bd71dd24878aa7b57385180e6c004c14a15b 100644 --- a/src/plugins/android/androidrunnable.cpp +++ b/src/plugins/android/androidrunnable.cpp @@ -29,4 +29,9 @@ namespace Android { void *AndroidRunnable::staticTypeId = &AndroidRunnable::staticTypeId; +AndroidRunnable::AndroidRunnable() +{ + qRegisterMetaType<AndroidRunnable>("AndroidRunnable"); +} + } // namespace Android diff --git a/src/plugins/android/androidrunnable.h b/src/plugins/android/androidrunnable.h index 0c1a8942504a634127a1195d909f9e8c7deec390..89ca03d1361a06ee02df04855cd5faa977fb58cd 100644 --- a/src/plugins/android/androidrunnable.h +++ b/src/plugins/android/androidrunnable.h @@ -32,9 +32,10 @@ namespace Android { struct ANDROID_EXPORT AndroidRunnable { + AndroidRunnable(); QString packageName; QString intentName; - QString commandLineArguments; + QStringList amStartExtraArgs; Utils::Environment environment; QVector<QStringList> beforeStartADBCommands; QVector<QStringList> afterFinishADBCommands; @@ -48,7 +49,7 @@ inline bool operator==(const AndroidRunnable &r1, const AndroidRunnable &r2) { return r1.packageName == r2.packageName && r1.intentName == r2.intentName - && r1.commandLineArguments == r2.commandLineArguments + && r1.amStartExtraArgs == r2.amStartExtraArgs && r1.environment == r2.environment && r1.beforeStartADBCommands == r2.beforeStartADBCommands && r1.afterFinishADBCommands == r2.afterFinishADBCommands @@ -61,3 +62,4 @@ inline bool operator!=(const AndroidRunnable &r1, const AndroidRunnable &r2) } } // namespace Android +Q_DECLARE_METATYPE(Android::AndroidRunnable) diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index 301ac00b2f54e844e13190b30b61640263a0e59f..f6d4ce2032539c2795f8bd50a7a2d0a480cd5eb4 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -217,8 +217,8 @@ public: const QStringList &selector); ~AndroidRunnerWorker(); - void asyncStart(const QString &intentName, const QVector<QStringList> &adbCommands); - void asyncStop(const QVector<QStringList> &adbCommands); + void asyncStart(const AndroidRunnable &runnable); + void asyncStop(const AndroidRunnable &runnable); void setAdbParameters(const QString &packageName, const QStringList &selector); void handleRemoteDebuggerRunning(); @@ -359,8 +359,7 @@ void AndroidRunnerWorker::forceStop() } } -void AndroidRunnerWorker::asyncStart(const QString &intentName, - const QVector<QStringList> &adbCommands) +void AndroidRunnerWorker::asyncStart(const AndroidRunnable &runnable) { forceStop(); @@ -378,10 +377,12 @@ void AndroidRunnerWorker::asyncStart(const QString &intentName, if (m_useCppDebugger) runAdb({"shell", "rm", m_pongFile}); // Remove pong file. - foreach (const QStringList &entry, adbCommands) - runAdb({entry}); + for (const QStringList &entry: runnable.beforeStartADBCommands) + runAdb(entry); - QStringList args = {"shell", "am", "start", "-n", intentName}; + QStringList args({"shell", "am", "start"}); + args << runnable.amStartExtraArgs; + args << "-n" << runnable.intentName; if (m_useCppDebugger) { if (!runAdb({"forward", "--remove", "tcp:" + m_localGdbServerPort.toString()})){ @@ -565,7 +566,7 @@ void AndroidRunnerWorker::handleRemoteDebuggerRunning() // emit remoteProcessStarted(m_localGdbServerPort, m_qmlPort); } -void AndroidRunnerWorker::asyncStop(const QVector<QStringList> &adbCommands) +void AndroidRunnerWorker::asyncStop(const AndroidRunnable &runnable) { if (!m_pidFinder.isFinished()) m_pidFinder.cancel(); @@ -573,8 +574,8 @@ void AndroidRunnerWorker::asyncStop(const QVector<QStringList> &adbCommands) if (m_processPID != -1) { forceStop(); } - for (const QStringList &entry : adbCommands) - runAdb({entry}); + for (const QStringList &entry: runnable.afterFinishADBCommands) + runAdb(entry); } void AndroidRunnerWorker::setAdbParameters(const QString &packageName, const QStringList &selector) @@ -690,6 +691,9 @@ AndroidRunner::AndroidRunner(RunControl *runControl) m_androidRunnable.intentName.indexOf(QLatin1Char('/'))); m_androidRunnable.deviceSerialNumber = AndroidManager::deviceSerialNumber(m_target); + auto androidRunConfig = qobject_cast<AndroidRunConfiguration *>(runControl->runConfiguration()); + m_androidRunnable.amStartExtraArgs = androidRunConfig->amStartExtraArgs(); + m_worker.reset(new AndroidRunnerWorker(runControl, m_androidRunnable.packageName, AndroidDeviceInfo::adbSelector(m_androidRunnable.deviceSerialNumber))); m_worker->moveToThread(&m_thread); @@ -730,7 +734,7 @@ void AndroidRunner::start() } } - emit asyncStart(m_androidRunnable.intentName, m_androidRunnable.beforeStartADBCommands); + emit asyncStart(m_androidRunnable); } void AndroidRunner::stop() @@ -742,7 +746,7 @@ void AndroidRunner::stop() return; } - emit asyncStop(m_androidRunnable.afterFinishADBCommands); + emit asyncStop(m_androidRunnable); } void AndroidRunner::remoteOutput(const QString &output) @@ -816,7 +820,7 @@ void AndroidRunner::checkAVD() if (avdManager.isAvdBooted(serialNumber)) { m_checkAVDTimer.stop(); AndroidManager::setDeviceSerialNumber(m_target, serialNumber); - emit asyncStart(m_androidRunnable.intentName, m_androidRunnable.beforeStartADBCommands); + emit asyncStart(m_androidRunnable); } else if (!config.isConnected(serialNumber)) { // device was disconnected m_checkAVDTimer.stop(); diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index 7b9719a6225ecee1905fbd8a4802e854a7285e3d..9c5f3dd7814e6aee0cac02580fcd43275ab06d2d 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -66,8 +66,8 @@ public: virtual void remoteErrorOutput(const QString &output); signals: - void asyncStart(const QString &intentName, const QVector<QStringList> &adbCommands); - void asyncStop(const QVector<QStringList> &adbCommands); + void asyncStart(const AndroidRunnable &runnable); + void asyncStop(const AndroidRunnable &runnable); void remoteDebuggerRunning(); void adbParametersChanged(const QString &packageName, const QStringList &selector); diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.cpp b/src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.cpp index ece47f031a5009b15d2ef2dae6ae136f7dccb226..6cb626ee7ef396020a963b9a223b7ef692a61891 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.cpp +++ b/src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.cpp @@ -89,7 +89,7 @@ bool QmakeAndroidRunConfiguration::fromMap(const QVariantMap &map) m_parseSuccess = project->validParse(m_proFilePath); m_parseInProgress = project->parseInProgress(m_proFilePath); - return RunConfiguration::fromMap(map); + return AndroidRunConfiguration::fromMap(map); } QVariantMap QmakeAndroidRunConfiguration::toMap() const @@ -102,7 +102,7 @@ QVariantMap QmakeAndroidRunConfiguration::toMap() const } const QDir projectDir = QDir(project->projectDirectory().toString()); - QVariantMap map(RunConfiguration::toMap()); + QVariantMap map(AndroidRunConfiguration::toMap()); map.insert(PRO_FILE_KEY, projectDir.relativeFilePath(m_proFilePath.toString())); return map; } diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidrunfactories.cpp b/src/plugins/qmakeandroidsupport/qmakeandroidrunfactories.cpp index 824c568ae08fe307e36b495d5a93474f30e0153b..2f93281adad576077f9d94b7238aa416e812b248 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidrunfactories.cpp +++ b/src/plugins/qmakeandroidsupport/qmakeandroidrunfactories.cpp @@ -70,7 +70,9 @@ bool QmakeAndroidRunConfigurationFactory::canCreate(Target *parent, Core::Id id) bool QmakeAndroidRunConfigurationFactory::canRestore(Target *parent, const QVariantMap &map) const { - return canCreate(parent, ProjectExplorer::idFromMap(map)); + if (!canHandle(parent)) + return false; + return ProjectExplorer::idFromMap(map).name().startsWith(ANDROID_RC_ID_PREFIX); } bool QmakeAndroidRunConfigurationFactory::canClone(Target *parent, RunConfiguration *source) const diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidsupport.cpp b/src/plugins/qmakeandroidsupport/qmakeandroidsupport.cpp index 08cf8d5708241c583bcc4f73293f93b36b27b54b..42ff3b047cbb71dc9bf5d8ba54d0546a0e9062b5 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidsupport.cpp +++ b/src/plugins/qmakeandroidsupport/qmakeandroidsupport.cpp @@ -143,15 +143,18 @@ Utils::FileName QmakeAndroidSupport::manifestSourcePath(const ProjectExplorer::T { ProjectExplorer::RunConfiguration *rc = target->activeRunConfiguration(); if (auto qrc = qobject_cast<QmakeAndroidRunConfiguration *>(rc)) { - Utils::FileName proFilePath = qrc->proFilePath(); const auto project = static_cast<QmakeProjectManager::QmakeProject *>(target->project()); - const QmakeProFileNode *node = project->rootProjectNode()->findProFileFor(proFilePath); - if (node) { - QString packageSource = node->singleVariableValue(Variable::AndroidPackageSourceDir); - if (!packageSource.isEmpty()) { - Utils::FileName manifest = Utils::FileName::fromUserInput(packageSource + QLatin1String("/AndroidManifest.xml")); - if (manifest.exists()) - return manifest; + if (project->rootProjectNode()) { + const QmakeProFileNode *node = + project->rootProjectNode()->findProFileFor(qrc->proFilePath()); + if (node) { + QString packageSource = node->singleVariableValue(Variable::AndroidPackageSourceDir); + if (!packageSource.isEmpty()) { + const auto manifest = Utils::FileName::fromUserInput(packageSource + + "/AndroidManifest.xml"); + if (manifest.exists()) + return manifest; + } } } }