forked from qt-creator/qt-creator
Android: Make Android manager activity start arguments configurable
Change-Id: I2e09029e4eb0b8a57fda53efff3d42f109bfe905 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -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
|
||||
|
63
src/plugins/android/androidrunconfigurationwidget.cpp
Normal file
63
src/plugins/android/androidrunconfigurationwidget.cpp
Normal file
@@ -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
|
||||
|
58
src/plugins/android/androidrunconfigurationwidget.h
Normal file
58
src/plugins/android/androidrunconfigurationwidget.h
Normal file
@@ -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
|
||||
|
67
src/plugins/android/androidrunconfigurationwidget.ui
Normal file
67
src/plugins/android/androidrunconfigurationwidget.ui
Normal file
@@ -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>
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user