forked from qt-creator/qt-creator
Change-Id: I8b808cf374fcdc124c5b2b7d9a113e6d64b17f2f Reviewed-by: BogDan Vatra <bog_dan_ro@yahoo.com> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@digia.com>
335 lines
12 KiB
C++
335 lines
12 KiB
C++
/**************************************************************************
|
|
**
|
|
** This file is part of Qt Creator
|
|
**
|
|
** Copyright (c) 2012 BogDan Vatra <bog_dan_ro@yahoo.com>
|
|
**
|
|
** Contact: http://www.qt-project.org/
|
|
**
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
**
|
|
** This file may be used under the terms of the GNU Lesser General Public
|
|
** License version 2.1 as published by the Free Software Foundation and
|
|
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
|
** Please review the following information to ensure the GNU Lesser General
|
|
** Public License version 2.1 requirements will be met:
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** Other Usage
|
|
**
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
|
**
|
|
**
|
|
**************************************************************************/
|
|
|
|
#include "androiddeploystep.h"
|
|
|
|
#include "androidconstants.h"
|
|
#include "androiddeploystepwidget.h"
|
|
#include "androidglobal.h"
|
|
#include "androidpackagecreationstep.h"
|
|
#include "androidrunconfiguration.h"
|
|
#include "androidmanager.h"
|
|
|
|
#include <projectexplorer/buildconfiguration.h>
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
|
#include <projectexplorer/target.h>
|
|
#include <qt4projectmanager/qt4buildconfiguration.h>
|
|
#include <qt4projectmanager/qt4project.h>
|
|
#include <qt4projectmanager/qt4nodes.h>
|
|
|
|
#include <qtsupport/qtkitinformation.h>
|
|
|
|
#include <QDir>
|
|
|
|
#define ASSERT_STATE(state) ASSERT_STATE_GENERIC(State, state, m_state)
|
|
|
|
using namespace ProjectExplorer;
|
|
using namespace Qt4ProjectManager;
|
|
|
|
namespace Android {
|
|
namespace Internal {
|
|
|
|
static const char USE_LOCAL_QT_KEY[] = "Qt4ProjectManager.AndroidDeployStep.UseLocalQtLibs";
|
|
|
|
const Core::Id AndroidDeployStep::Id("Qt4ProjectManager.AndroidDeployStep");
|
|
|
|
AndroidDeployStep::AndroidDeployStep(ProjectExplorer::BuildStepList *parent)
|
|
: BuildStep(parent, Id)
|
|
{
|
|
ctor();
|
|
}
|
|
|
|
AndroidDeployStep::AndroidDeployStep(ProjectExplorer::BuildStepList *parent,
|
|
AndroidDeployStep *other)
|
|
: BuildStep(parent, other)
|
|
{
|
|
ctor();
|
|
}
|
|
|
|
AndroidDeployStep::~AndroidDeployStep() { }
|
|
|
|
void AndroidDeployStep::ctor()
|
|
{
|
|
//: AndroidDeployStep default display name
|
|
setDefaultDisplayName(tr("Deploy to Android device"));
|
|
m_deployAction = NoDeploy;
|
|
m_useLocalQtLibs = false;
|
|
}
|
|
|
|
bool AndroidDeployStep::init()
|
|
{
|
|
m_packageName = AndroidManager::packageName(target());
|
|
const QString targetSDK = AndroidManager::targetSDK(target());
|
|
|
|
writeOutput(tr("Please wait, searching for a suitable device for target:%1.").arg(targetSDK));
|
|
m_deviceAPILevel = targetSDK.mid(targetSDK.indexOf(QLatin1Char('-')) + 1).toInt();
|
|
m_deviceSerialNumber = AndroidConfigurations::instance().getDeployDeviceSerialNumber(&m_deviceAPILevel);
|
|
if (!m_deviceSerialNumber.length()) {
|
|
m_deviceSerialNumber.clear();
|
|
raiseError(tr("Cannot deploy: no devices or emulators found for your package."));
|
|
return false;
|
|
}
|
|
|
|
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit());
|
|
if (!version)
|
|
return false;
|
|
|
|
const Qt4BuildConfiguration *bc = static_cast<Qt4BuildConfiguration *>(target()->activeBuildConfiguration());
|
|
if (!bc)
|
|
return false;
|
|
|
|
m_qtVersionSourcePath = version->sourcePath().toString();
|
|
m_qtVersionQMakeBuildConfig = bc->qmakeBuildConfiguration();
|
|
m_androidDirPath = AndroidManager::dirPath(target());
|
|
m_apkPathDebug = AndroidManager::apkPath(target(), AndroidManager::DebugBuild).toString();
|
|
m_apkPathRelease = AndroidManager::apkPath(target(), AndroidManager::ReleaseBuildSigned).toString();
|
|
m_buildDirectory = static_cast<Qt4Project *>(target()->project())->rootQt4ProjectNode()->buildDir();
|
|
m_runQASIPackagePath = m_QASIPackagePath;
|
|
m_runDeployAction = m_deployAction;
|
|
return true;
|
|
}
|
|
|
|
void AndroidDeployStep::run(QFutureInterface<bool> &fi)
|
|
{
|
|
fi.reportResult(deployPackage());
|
|
}
|
|
|
|
BuildStepConfigWidget *AndroidDeployStep::createConfigWidget()
|
|
{
|
|
return new AndroidDeployStepWidget(this);
|
|
}
|
|
|
|
AndroidDeployStep::AndroidDeployAction AndroidDeployStep::deployAction()
|
|
{
|
|
return m_deployAction;
|
|
}
|
|
|
|
bool AndroidDeployStep::useLocalQtLibs()
|
|
{
|
|
return m_useLocalQtLibs;
|
|
}
|
|
|
|
bool AndroidDeployStep::fromMap(const QVariantMap &map)
|
|
{
|
|
m_useLocalQtLibs = map.value(QLatin1String(USE_LOCAL_QT_KEY), false).toBool();
|
|
return ProjectExplorer::BuildStep::fromMap(map);
|
|
}
|
|
|
|
QVariantMap AndroidDeployStep::toMap() const
|
|
{
|
|
QVariantMap map = ProjectExplorer::BuildStep::toMap();
|
|
map.insert(QLatin1String(USE_LOCAL_QT_KEY), m_useLocalQtLibs);
|
|
return map;
|
|
}
|
|
|
|
void AndroidDeployStep::setDeployAction(AndroidDeployStep::AndroidDeployAction deploy)
|
|
{
|
|
m_deployAction = deploy;
|
|
}
|
|
|
|
void AndroidDeployStep::setDeployQASIPackagePath(const QString &package)
|
|
{
|
|
m_QASIPackagePath = package;
|
|
m_deployAction = InstallQASI;
|
|
}
|
|
|
|
void AndroidDeployStep::setUseLocalQtLibs(bool useLocal)
|
|
{
|
|
m_useLocalQtLibs = useLocal;
|
|
}
|
|
|
|
bool AndroidDeployStep::runCommand(QProcess *buildProc,
|
|
const QString &program, const QStringList &arguments)
|
|
{
|
|
writeOutput(tr("Package deploy: Running command '%1 %2'.").arg(program).arg(arguments.join(QLatin1String(" "))), BuildStep::MessageOutput);
|
|
buildProc->start(program, arguments);
|
|
if (!buildProc->waitForStarted()) {
|
|
writeOutput(tr("Packaging error: Could not start command '%1 %2'. Reason: %3")
|
|
.arg(program).arg(arguments.join(QLatin1String(" "))).arg(buildProc->errorString()), BuildStep::ErrorMessageOutput);
|
|
return false;
|
|
}
|
|
buildProc->waitForFinished(-1);
|
|
if (buildProc->error() != QProcess::UnknownError
|
|
|| buildProc->exitCode() != 0) {
|
|
QString mainMessage = tr("Packaging Error: Command '%1 %2' failed.")
|
|
.arg(program).arg(arguments.join(QLatin1String(" ")));
|
|
if (buildProc->error() != QProcess::UnknownError)
|
|
mainMessage += tr(" Reason: %1").arg(buildProc->errorString());
|
|
else
|
|
mainMessage += tr("Exit code: %1").arg(buildProc->exitCode());
|
|
writeOutput(mainMessage, BuildStep::ErrorMessageOutput);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void AndroidDeployStep::handleBuildOutput()
|
|
{
|
|
QProcess *const buildProc = qobject_cast<QProcess *>(sender());
|
|
if (!buildProc)
|
|
return;
|
|
emit addOutput(QString::fromLocal8Bit(buildProc->readAllStandardOutput())
|
|
, BuildStep::NormalOutput);
|
|
}
|
|
|
|
void AndroidDeployStep::handleBuildError()
|
|
{
|
|
QProcess *const buildProc = qobject_cast<QProcess *>(sender());
|
|
if (!buildProc)
|
|
return;
|
|
emit addOutput(QString::fromLocal8Bit(buildProc->readAllStandardError())
|
|
, BuildStep::ErrorOutput);
|
|
}
|
|
|
|
QString AndroidDeployStep::deviceSerialNumber()
|
|
{
|
|
return m_deviceSerialNumber;
|
|
}
|
|
|
|
int AndroidDeployStep::deviceAPILevel()
|
|
{
|
|
return m_deviceAPILevel;
|
|
}
|
|
|
|
Utils::FileName AndroidDeployStep::localLibsRulesFilePath()
|
|
{
|
|
return AndroidManager::localLibsRulesFilePath(target());
|
|
}
|
|
|
|
void AndroidDeployStep::copyLibs(const QString &srcPath, const QString &destPath, QStringList &copiedLibs, const QStringList &filter)
|
|
{
|
|
QDir dir;
|
|
dir.mkpath(destPath);
|
|
QDirIterator libsIt(srcPath, filter, QDir::NoFilter, QDirIterator::Subdirectories);
|
|
int pos = srcPath.size();
|
|
while (libsIt.hasNext()) {
|
|
libsIt.next();
|
|
const QString destFile(destPath + libsIt.filePath().mid(pos));
|
|
if (libsIt.fileInfo().isDir()) {
|
|
dir.mkpath(destFile);
|
|
} else {
|
|
QFile::copy(libsIt.filePath(), destFile);
|
|
copiedLibs.append(destFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool AndroidDeployStep::deployPackage()
|
|
{
|
|
QProcess *const deployProc = new QProcess;
|
|
connect(deployProc, SIGNAL(readyReadStandardOutput()), this,
|
|
SLOT(handleBuildOutput()));
|
|
connect(deployProc, SIGNAL(readyReadStandardError()), this,
|
|
SLOT(handleBuildError()));
|
|
|
|
if (m_runDeployAction == DeployLocal) {
|
|
writeOutput(tr("Clean old Qt libraries"));
|
|
runCommand(deployProc, AndroidConfigurations::instance().adbToolPath().toString(),
|
|
QStringList() << QLatin1String("-s") << m_deviceSerialNumber
|
|
<< QLatin1String("shell") << QLatin1String("rm") << QLatin1String("-r") << QLatin1String("/data/local/qt"));
|
|
|
|
writeOutput(tr("Deploy Qt libraries. This may take some time, please wait."));
|
|
const QString tempPath = QDir::tempPath() + QLatin1String("/android_qt_libs_") + m_packageName;
|
|
AndroidPackageCreationStep::removeDirectory(tempPath);
|
|
QStringList stripFiles;
|
|
copyLibs(m_qtVersionSourcePath + QLatin1String("/lib"),
|
|
tempPath + QLatin1String("/lib"), stripFiles, QStringList() << QLatin1String("*.so"));
|
|
copyLibs(m_qtVersionSourcePath + QLatin1String("/plugins"),
|
|
tempPath + QLatin1String("/plugins"), stripFiles);
|
|
copyLibs(m_qtVersionSourcePath + QLatin1String("/imports"),
|
|
tempPath + QLatin1String("/imports"), stripFiles);
|
|
copyLibs(m_qtVersionSourcePath + QLatin1String("/jar"),
|
|
tempPath + QLatin1String("/jar"), stripFiles);
|
|
AndroidPackageCreationStep::stripAndroidLibs(stripFiles, target()->activeRunConfiguration()->abi().architecture());
|
|
runCommand(deployProc, AndroidConfigurations::instance().adbToolPath().toString(),
|
|
QStringList() << QLatin1String("-s") << m_deviceSerialNumber
|
|
<< QLatin1String("push") << tempPath << QLatin1String("/data/local/qt"));
|
|
AndroidPackageCreationStep::removeDirectory(tempPath);
|
|
emit (resetDelopyAction());
|
|
}
|
|
|
|
if (m_runDeployAction == InstallQASI) {
|
|
if (!runCommand(deployProc, AndroidConfigurations::instance().adbToolPath().toString(),
|
|
QStringList() << QLatin1String("-s") << m_deviceSerialNumber
|
|
<< QLatin1String("install") << QLatin1String("-r ") << m_runQASIPackagePath)) {
|
|
raiseError(tr("Qt Android smart installer installation failed"));
|
|
disconnect(deployProc, 0, this, 0);
|
|
deployProc->deleteLater();
|
|
return false;
|
|
}
|
|
emit resetDelopyAction();
|
|
}
|
|
deployProc->setWorkingDirectory(m_androidDirPath.toString());
|
|
|
|
writeOutput(tr("Installing package onto %1.").arg(m_deviceSerialNumber));
|
|
runCommand(deployProc, AndroidConfigurations::instance().adbToolPath().toString(),
|
|
QStringList() << QLatin1String("-s") << m_deviceSerialNumber << QLatin1String("uninstall") << m_packageName);
|
|
QString package = m_apkPathDebug;
|
|
|
|
if (!(m_qtVersionQMakeBuildConfig & QtSupport::BaseQtVersion::DebugBuild)
|
|
&& QFile::exists(m_apkPathRelease))
|
|
package = m_apkPathRelease;
|
|
|
|
if (!runCommand(deployProc, AndroidConfigurations::instance().adbToolPath().toString(),
|
|
QStringList() << QLatin1String("-s") << m_deviceSerialNumber << QLatin1String("install") << package)) {
|
|
raiseError(tr("Package installation failed."));
|
|
disconnect(deployProc, 0, this, 0);
|
|
deployProc->deleteLater();
|
|
return false;
|
|
}
|
|
|
|
writeOutput(tr("Pulling files necessary for debugging."));
|
|
runCommand(deployProc, AndroidConfigurations::instance().adbToolPath().toString(),
|
|
QStringList() << QLatin1String("-s") << m_deviceSerialNumber
|
|
<< QLatin1String("pull") << QLatin1String("/system/bin/app_process")
|
|
<< QString::fromLatin1("%1/app_process").arg(m_buildDirectory));
|
|
runCommand(deployProc, AndroidConfigurations::instance().adbToolPath().toString(),
|
|
QStringList() << QLatin1String("-s") << m_deviceSerialNumber << QLatin1String("pull")
|
|
<< QLatin1String("/system/lib/libc.so")
|
|
<< QString::fromLatin1("%1/libc.so").arg(m_buildDirectory));
|
|
disconnect(deployProc, 0, this, 0);
|
|
deployProc->deleteLater();
|
|
return true;
|
|
}
|
|
|
|
void AndroidDeployStep::raiseError(const QString &errorString)
|
|
{
|
|
emit addTask(Task(Task::Error, errorString, Utils::FileName::fromString(QString()), -1,
|
|
ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM));
|
|
}
|
|
|
|
void AndroidDeployStep::writeOutput(const QString &text, OutputFormat format)
|
|
{
|
|
emit addOutput(text, format);
|
|
}
|
|
|
|
} // namespace Internal
|
|
} // namespace Qt4ProjectManager
|