Commit a30a1817 authored by Vikas Pachdha's avatar Vikas Pachdha

Android: Make Android manager activity start arguments configurable

Change-Id: I2e09029e4eb0b8a57fda53efff3d42f109bfe905
Reviewed-by: default avatarhjk <hjk@qt.io>
parent 18fddf82
......@@ -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
......
......@@ -78,6 +78,9 @@ Project {
"androidqtversionfactory.h",
"androidrunconfiguration.cpp",
"androidrunconfiguration.h",
"androidrunconfigurationwidget.cpp",
"androidrunconfigurationwidget.h",
"androidrunconfigurationwidget.ui",
"androidruncontrol.cpp",
"androidruncontrol.h",
"androidrunfactories.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
......@@ -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
/****************************************************************************
**
** 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
/****************************************************************************
**
** 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
<?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 &quot;am start&quot; 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>
......@@ -29,4 +29,9 @@ namespace Android {
void *AndroidRunnable::staticTypeId = &AndroidRunnable::staticTypeId;
AndroidRunnable::AndroidRunnable()
{
qRegisterMetaType<AndroidRunnable>("AndroidRunnable");
}
} // namespace Android
......@@ -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)
......@@ -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();
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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
......
......@@ -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;
}
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment