Android: Remove Necessitas support

Change-Id: I082acfad3b20d5e096fbb2ca3db775bb527eaf7a
Reviewed-by: BogDan Vatra <bogdan@kde.org>
This commit is contained in:
BogDan Vatra
2014-05-07 15:03:43 +03:00
committed by Daniel Teske
parent c4451570e7
commit 381b04fa04
28 changed files with 21 additions and 3959 deletions

View File

@@ -17,12 +17,6 @@ HEADERS += \
androidtoolchain.h \
androidpackageinstallationstep.h \
androidpackageinstallationfactory.h \
androidpackagecreationstep.h \
androidpackagecreationfactory.h \
androidpackagecreationwidget.h \
androiddeploystep.h \
androiddeploystepwidget.h \
androiddeploystepfactory.h \
androiderrormessage.h \
androidglobal.h \
androidrunner.h \
@@ -69,12 +63,6 @@ SOURCES += \
androidtoolchain.cpp \
androidpackageinstallationstep.cpp \
androidpackageinstallationfactory.cpp \
androidpackagecreationstep.cpp \
androidpackagecreationfactory.cpp \
androidpackagecreationwidget.cpp \
androiddeploystep.cpp \
androiddeploystepwidget.cpp \
androiddeploystepfactory.cpp \
androiderrormessage.cpp \
androidrunner.cpp \
androiddebugsupport.cpp \
@@ -111,8 +99,6 @@ SOURCES += \
FORMS += \
androidsettingswidget.ui \
androidpackagecreationwidget.ui \
androiddeploystepwidget.ui \
addnewavddialog.ui \
androidcreatekeystorecertificate.ui \
androiddevicedialog.ui \

View File

@@ -39,13 +39,6 @@ QtcPlugin {
"androiddevicedialog.ui",
"androiddeployconfiguration.cpp",
"androiddeployconfiguration.h",
"androiddeploystep.cpp",
"androiddeploystep.h",
"androiddeploystepfactory.cpp",
"androiddeploystepfactory.h",
"androiddeploystepwidget.cpp",
"androiddeploystepwidget.h",
"androiddeploystepwidget.ui",
"androiddeployqtwidget.cpp",
"androiddeployqtwidget.h",
"androiddeployqtwidget.ui",
@@ -70,13 +63,6 @@ QtcPlugin {
"androidmanifesteditorfactory.h",
"androidmanifesteditorwidget.cpp",
"androidmanifesteditorwidget.h",
"androidpackagecreationfactory.cpp",
"androidpackagecreationfactory.h",
"androidpackagecreationstep.cpp",
"androidpackagecreationstep.h",
"androidpackagecreationwidget.cpp",
"androidpackagecreationwidget.h",
"androidpackagecreationwidget.ui",
"androidpackageinstallationfactory.cpp",
"androidpackageinstallationfactory.h",
"androidpackageinstallationstep.cpp",

View File

@@ -844,7 +844,7 @@ QString AndroidConfig::bestNdkPlatformMatch(const QString &targetAPI) const
if (apiLevel <= target)
return QString::fromLatin1("android-%1").arg(apiLevel);
}
return QLatin1String("android-8");
return QLatin1String("android-9");
}
FileName AndroidConfig::sdkLocation() const

View File

@@ -29,7 +29,6 @@
#include "androiddebugsupport.h"
#include "androiddeploystep.h"
#include "androidglobal.h"
#include "androidrunner.h"
#include "androidmanager.h"

View File

@@ -29,9 +29,7 @@
#include "androiddeployconfiguration.h"
#include "androidconstants.h"
#include "androiddeploystep.h"
#include "androidpackageinstallationstep.h"
#include "androidpackagecreationstep.h"
#include "androiddeployqtstep.h"
#include "androidmanager.h"
@@ -76,14 +74,8 @@ DeployConfiguration *AndroidDeployConfigurationFactory::create(Target *parent, C
{
AndroidDeployConfiguration *dc = new AndroidDeployConfiguration(parent, id);
if (id == ANDROID_DEPLOYCONFIGURATION_ID) {
dc->stepList()->insertStep(0, new AndroidPackageInstallationStep(AndroidPackageInstallationStep::ProjectDirectory, dc->stepList()));
dc->stepList()->insertStep(1, new AndroidPackageCreationStep(dc->stepList()));
dc->stepList()->insertStep(2, new AndroidDeployStep(dc->stepList()));
} else {
dc->stepList()->insertStep(0, new AndroidPackageInstallationStep(AndroidPackageInstallationStep::BuildDirectory, dc->stepList()));
dc->stepList()->insertStep(1, new AndroidDeployQtStep(dc->stepList()));
}
dc->stepList()->insertStep(0, new AndroidPackageInstallationStep(AndroidPackageInstallationStep::BuildDirectory, dc->stepList()));
dc->stepList()->insertStep(1, new AndroidDeployQtStep(dc->stepList()));
return dc;
}
@@ -136,17 +128,13 @@ QList<Core::Id> AndroidDeployConfigurationFactory::availableCreationIds(Target *
QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(parent->kit());
if (qt->type() != QLatin1String(Constants::ANDROIDQT))
return ids;
if (qt->qtVersion() < QtSupport::QtVersionNumber(5, 2, 0))
ids << Core::Id(ANDROID_DEPLOYCONFIGURATION_ID);
else
ids << Core::Id(ANDROID_DEPLOYCONFIGURATION2_ID);
ids << Core::Id(ANDROID_DEPLOYCONFIGURATION_ID);
return ids;
}
QString AndroidDeployConfigurationFactory::displayNameForId(Core::Id id) const
{
if (id.name().startsWith(ANDROID_DC_PREFIX)
|| id.name().startsWith(ANDROID_DC2_PREFIX))
if (id.name().startsWith(ANDROID_DC_PREFIX))
return tr("Deploy on Android");
return QString();
}

View File

@@ -35,12 +35,9 @@
namespace Android {
namespace Internal {
const char ANDROID_DEPLOYCONFIGURATION_ID[] = "Qt4ProjectManager.AndroidDeployConfiguration";
const char ANDROID_DC_PREFIX[] = "Qt4ProjectManager.AndroidDeployConfiguration.";
// Qt 5.2 has a new form of deployment
const char ANDROID_DEPLOYCONFIGURATION2_ID[] = "Qt4ProjectManager.AndroidDeployConfiguration2";
const char ANDROID_DC2_PREFIX[] = "Qt4ProjectManager.AndroidDeployConfiguration2.";
const char ANDROID_DEPLOYCONFIGURATION_ID[] = "Qt4ProjectManager.AndroidDeployConfiguration2";
const char ANDROID_DC_PREFIX[] = "Qt4ProjectManager.AndroidDeployConfiguration2.";
class AndroidDeployConfiguration : public ProjectExplorer::DeployConfiguration
{

View File

@@ -81,9 +81,6 @@ QList<Core::Id> AndroidDeployQtStepFactory::availableCreationIds(ProjectExplorer
return QList<Core::Id>();
if (parent->contains(AndroidDeployQtStep::Id))
return QList<Core::Id>();
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(parent->target()->kit());
if (!qtVersion || qtVersion->qtVersion() < QtSupport::QtVersionNumber(5, 2, 0))
return QList<Core::Id>();
return QList<Core::Id>() << AndroidDeployQtStep::Id;
}

View File

@@ -1,501 +0,0 @@
/**************************************************************************
**
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "androiddeploystep.h"
#include "androidconstants.h"
#include "androiddeploystepwidget.h"
#include "androidglobal.h"
#include "androidpackagecreationstep.h"
#include "androidrunconfiguration.h"
#include "androidmanager.h"
#include "androidtoolchain.h"
#include "androiddevicedialog.h"
#include <coreplugin/messagemanager.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/deployconfiguration.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/target.h>
#include <qmakeprojectmanager/qmakebuildconfiguration.h>
#include <qmakeprojectmanager/qmakeproject.h>
#include <qmakeprojectmanager/qmakenodes.h>
#include <qtsupport/qtkitinformation.h>
#include <QDir>
#define ASSERT_STATE(state) ASSERT_STATE_GENERIC(State, state, m_state)
using namespace Core;
using namespace ProjectExplorer;
using namespace QmakeProjectManager;
namespace Android {
namespace Internal {
static const char USE_LOCAL_QT_KEY[] = "Qt4ProjectManager.AndroidDeployStep.UseLocalQtLibs";
static const char DEPLOY_ACTION_KEY[] = "Qt4ProjectManager.AndroidDeployStep.DeployAction";
const 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;
QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target()->kit());
m_bundleQtAvailable = qt && qt->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0);
if (m_bundleQtAvailable)
m_deployAction = BundleLibraries;
connect(ProjectExplorer::KitManager::instance(), SIGNAL(kitUpdated(ProjectExplorer::Kit*)),
this, SLOT(kitUpdated(ProjectExplorer::Kit*)));
}
bool AndroidDeployStep::init()
{
m_packageName = AndroidManager::packageName(target());
m_deviceAPILevel = AndroidManager::minimumSDK(target());
m_targetArch = AndroidManager::targetArch(target());
AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(project(), m_deviceAPILevel, m_targetArch);
if (info.serialNumber.isEmpty()) // aborted
return false;
m_deviceAPILevel = info.sdk;
m_deviceSerialNumber = info.serialNumber;
if (info.type == AndroidDeviceInfo::Emulator)
m_avdName = m_deviceSerialNumber;
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit());
if (!version)
return false;
const QmakeBuildConfiguration *bc = static_cast<QmakeBuildConfiguration *>(target()->activeBuildConfiguration());
if (!bc)
return false;
m_signPackage = false;
// find AndroidPackageCreationStep
foreach (BuildStep *step, target()->activeDeployConfiguration()->stepList()->steps()) {
if (AndroidPackageCreationStep *apcs = qobject_cast<AndroidPackageCreationStep *>(step)) {
m_signPackage = apcs->signPackage();
break;
}
}
m_qtVersionSourcePath = version->qmakeProperty("QT_INSTALL_PREFIX");
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<QmakeProject *>(target()->project())->rootQmakeProjectNode()->buildDir();
m_runDeployAction = m_deployAction;
ToolChain *tc = ToolChainKitInformation::toolChain(target()->kit());
if (!tc || tc->type() != QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE)) {
raiseError(tr("No Android toolchain selected."));
return false;
}
m_ndkToolChainVersion = static_cast<AndroidToolChain *>(tc)->ndkToolChainVersion();
QString arch = static_cast<QmakeProject *>(project())->rootQmakeProjectNode()->singleVariableValue(QmakeProjectManager::AndroidArchVar);
if (!arch.isEmpty())
m_libgnustl = AndroidManager::libGnuStl(arch, m_ndkToolChainVersion);
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::fromMap(const QVariantMap &map)
{
m_deployAction = AndroidDeployAction(map.value(QLatin1String(DEPLOY_ACTION_KEY), NoDeploy).toInt());
QVariant useLocalQt = map.value(QLatin1String(USE_LOCAL_QT_KEY));
if (useLocalQt.isValid()) { // old settings
if (useLocalQt.toBool() && m_deployAction == NoDeploy)
m_deployAction = BundleLibraries;
}
if (m_deployAction == InstallQASI)
m_deployAction = NoDeploy;
QtSupport::BaseQtVersion *qtVersion
= QtSupport::QtKitInformation::qtVersion(target()->kit());
if (m_deployAction == BundleLibraries)
if (!qtVersion || qtVersion->qtVersion() < QtSupport::QtVersionNumber(5, 0, 0))
m_deployAction = NoDeploy; // the kit changed to a non qt5 kit
m_bundleQtAvailable = qtVersion && qtVersion->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0);
return ProjectExplorer::BuildStep::fromMap(map);
}
QVariantMap AndroidDeployStep::toMap() const
{
QVariantMap map = ProjectExplorer::BuildStep::toMap();
map.insert(QLatin1String(DEPLOY_ACTION_KEY), m_deployAction);
return map;
}
void AndroidDeployStep::kitUpdated(Kit *kit)
{
if (kit != target()->kit())
return;
QtSupport::BaseQtVersion *qtVersion
= QtSupport::QtKitInformation::qtVersion(target()->kit());
bool newBundleQtAvailable = qtVersion && qtVersion->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0);
if (m_bundleQtAvailable != newBundleQtAvailable) {
m_bundleQtAvailable = newBundleQtAvailable;
if (!m_bundleQtAvailable && m_deployAction == BundleLibraries)
m_deployAction = NoDeploy; // the kit changed to a non qt5 kit
emit deployOptionsChanged();
}
}
bool AndroidDeployStep::bundleQtOptionAvailable()
{
return m_bundleQtAvailable;
}
void AndroidDeployStep::setDeployAction(AndroidDeployStep::AndroidDeployAction deploy)
{
m_deployAction = deploy;
AndroidManager::updateDeploymentSettings(target());
}
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;
}
if (!buildProc->waitForFinished(2 * 60 * 1000)
|| 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 += QLatin1Char(' ') + 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;
}
unsigned int AndroidDeployStep::remoteModificationTime(const QString &fullDestination, QHash<QString, unsigned int> *cache)
{
QString destination = QFileInfo(fullDestination).absolutePath();
QProcess process;
QHash<QString, unsigned int>::const_iterator it = cache->find(fullDestination);
if (it != cache->constEnd())
return *it;
QStringList arguments = AndroidDeviceInfo::adbSelector(m_deviceSerialNumber);
arguments << QLatin1String("ls") << destination;
process.start(AndroidConfigurations::currentConfig().adbToolPath().toString(), arguments);
if (!process.waitForFinished(10000)
|| process.exitCode() != 0)
return 0;
QByteArray output = process.readAll();
output.replace("\r\n", "\n");
QList<QByteArray> lines = output.split('\n');
foreach (const QByteArray &line, lines) {
// do some checks if we got what we expected..
if (line.count() < (3 * 8 + 3))
continue;
if (line.at(8) != ' '
|| line.at(17) != ' '
|| line.at(26) != ' ')
continue;
bool ok;
int time = line.mid(18, 8).toUInt(&ok, 16);
if (!ok)
continue;
QString fileName = QString::fromLocal8Bit(line.mid(27));
cache->insert(destination + QLatin1Char('/') + fileName, time);
}
it = cache->find(fullDestination);
if (it != cache->constEnd())
return *it;
return 0;
}
void AndroidDeployStep::collectFiles(QList<DeployItem> *deployList, const QString &localPath, const QString &remotePath,
bool strip, const QStringList &filter)
{
QDirIterator libsIt(localPath, filter, QDir::NoFilter, QDirIterator::Subdirectories);
int pos = localPath.size();
while (libsIt.hasNext()) {
libsIt.next();
const QString destFile(remotePath + libsIt.filePath().mid(pos));
if (!libsIt.fileInfo().isDir()) {
deployList->append(DeployItem(libsIt.filePath(),
libsIt.fileInfo().lastModified().toTime_t(),
destFile, strip));
}
}
}
void AndroidDeployStep::fetchRemoteModificationTimes(QList<DeployItem> *deployList)
{
QHash<QString, unsigned int> cache;
for (int i = 0; i < deployList->count(); ++i) {
DeployItem &item = (*deployList)[i];
item.remoteTimeStamp
= remoteModificationTime(item.remoteFileName, &cache);
}
}
void AndroidDeployStep::filterModificationTimes(QList<DeployItem> *deployList)
{
QList<DeployItem>::iterator it = deployList->begin();
while (it != deployList->end()) {
int index = it - deployList->begin();
Q_UNUSED(index);
if ((*it).localTimeStamp <= (*it).remoteTimeStamp)
it = deployList->erase(it);
else
++it;
}
}
void AndroidDeployStep::copyFilesToTemp(QList<DeployItem> *deployList, const QString &tempDirectory, const QString &sourcePrefix)
{
QDir dir;
int pos = sourcePrefix.size();
for (int i = 0; i < deployList->count(); ++i) {
DeployItem &item = (*deployList)[i];
if (!item.needsStrip)
continue;
const QString destFile(tempDirectory + item.localFileName.mid(pos));
dir.mkpath(QFileInfo(destFile).absolutePath());
QFile::copy(item.localFileName, destFile);
item.localFileName = destFile;
}
}
void AndroidDeployStep::stripFiles(const QList<DeployItem> &deployList, Abi::Architecture architecture, const QString &ndkToolchainVersion)
{
QProcess stripProcess;
foreach (const DeployItem &item, deployList) {
stripProcess.start(AndroidConfigurations::currentConfig().stripPath(architecture, ndkToolchainVersion).toString(),
QStringList()<<QLatin1String("--strip-unneeded") << item.localFileName);
stripProcess.waitForStarted();
if (!stripProcess.waitForFinished())
stripProcess.kill();
}
}
void AndroidDeployStep::deployFiles(QProcess *process, const QList<DeployItem> &deployList)
{
foreach (const DeployItem &item, deployList) {
runCommand(process, AndroidConfigurations::currentConfig().adbToolPath().toString(),
AndroidDeviceInfo::adbSelector(m_deviceSerialNumber)
<< QLatin1String("push") << item.localFileName
<< item.remoteFileName);
}
}
bool AndroidDeployStep::deployPackage()
{
if (!m_avdName.isEmpty()) {
if (AndroidConfigurations::currentConfig().findAvd(m_deviceAPILevel, m_targetArch).isEmpty()
&& !AndroidConfigurations::currentConfig().startAVDAsync(m_avdName))
return false;
m_deviceSerialNumber = AndroidConfigurations::currentConfig().waitForAvd(m_deviceAPILevel, m_targetArch);
}
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("Deploy Qt libraries. This may take some time, please wait."));
const QString tempPath = QDir::tempPath() + QLatin1String("/android_qt_libs_") + m_packageName;
AndroidPackageCreationStep::removeDirectory(tempPath);
const QString remoteRoot = QLatin1String("/data/local/tmp/qt");
QList<DeployItem> deployList;
collectFiles(&deployList,
m_qtVersionSourcePath + QLatin1String("/lib"),
remoteRoot + QLatin1String("/lib"),
true,
QStringList() << QLatin1String("*.so"));
// don't use the libgnustl_shared.so from the qt directory
for (int i = 0; i < deployList.count(); ++i) {
if (deployList.at(i).remoteFileName == QLatin1String("/data/local/tmp/qt/lib/libgnustl_shared.so")) {
deployList.removeAt(i);
break;
}
}
// We want to deploy that *always*
// since even if the timestamps did not change, the toolchain might have changed
// leading to a different file
deployList.append(DeployItem(m_libgnustl,
QDateTime::currentDateTimeUtc().toTime_t(),
QLatin1String("/data/local/tmp/qt/lib/libgnustl_shared.so"), false));
collectFiles(&deployList,
m_qtVersionSourcePath + QLatin1String("/plugins"),
remoteRoot + QLatin1String("/plugins"),
true);
collectFiles(&deployList,
m_qtVersionSourcePath + QLatin1String("/imports"),
remoteRoot + QLatin1String("/imports"),
true);
collectFiles(&deployList,
m_qtVersionSourcePath + QLatin1String("/qml"),
remoteRoot + QLatin1String("/qml"),
true);
collectFiles(&deployList,
m_qtVersionSourcePath + QLatin1String("/jar"),
remoteRoot + QLatin1String("/jar"),
true);
fetchRemoteModificationTimes(&deployList);
filterModificationTimes(&deployList);
copyFilesToTemp(&deployList, tempPath, m_qtVersionSourcePath);
stripFiles(deployList, target()->activeRunConfiguration()->abi().architecture(), m_ndkToolChainVersion);
deployFiles(deployProc, deployList);
AndroidPackageCreationStep::removeDirectory(tempPath);
}
deployProc->setWorkingDirectory(m_androidDirPath.toString());
writeOutput(tr("Installing package onto %1.").arg(m_deviceSerialNumber));
runCommand(deployProc, AndroidConfigurations::currentConfig().adbToolPath().toString(),
AndroidDeviceInfo::adbSelector(m_deviceSerialNumber) << QLatin1String("uninstall") << m_packageName);
QString package = m_apkPathDebug;
if (m_signPackage && QFile::exists(m_apkPathRelease))
package = m_apkPathRelease;
if (!runCommand(deployProc, AndroidConfigurations::currentConfig().adbToolPath().toString(),
AndroidDeviceInfo::adbSelector(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::currentConfig().adbToolPath().toString(),
AndroidDeviceInfo::adbSelector(m_deviceSerialNumber)
<< QLatin1String("pull") << QLatin1String("/system/bin/app_process")
<< QString::fromLatin1("%1/app_process").arg(m_buildDirectory));
runCommand(deployProc, AndroidConfigurations::currentConfig().adbToolPath().toString(),
AndroidDeviceInfo::adbSelector(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_DEPLOYMENT));
}
void AndroidDeployStep::writeOutput(const QString &text, OutputFormat format)
{
emit addOutput(text, format);
}
} // namespace Internal
} // namespace Android

View File

@@ -1,161 +0,0 @@
/**************************************************************************
**
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef ANDROIDDEPLOYSTEP_H
#define ANDROIDDEPLOYSTEP_H
#include "androidconfigurations.h"
#include <projectexplorer/buildstep.h>
#include <qtsupport/baseqtversion.h>
#include <QProcess>
QT_BEGIN_NAMESPACE
class QEventLoop;
class QTimer;
QT_END_NAMESPACE
namespace Android {
namespace Internal {
class AndroidDeviceConfigListModel;
class AndroidPackageCreationStep;
class DeployItem
{
public:
DeployItem(const QString &_localFileName,
unsigned int _localTimeStamp,
const QString &_remoteFileName,
bool _needsStrip)
: localFileName(_localFileName),
remoteFileName(_remoteFileName),
localTimeStamp(_localTimeStamp),
remoteTimeStamp(0),
needsStrip(_needsStrip)
{}
QString localFileName;
QString remoteFileName;
unsigned int localTimeStamp;
unsigned int remoteTimeStamp;
bool needsStrip;
};
class AndroidDeployStep : public ProjectExplorer::BuildStep
{
Q_OBJECT
friend class AndroidDeployStepFactory;
public:
enum AndroidDeployAction
{
NoDeploy, // use ministro
DeployLocal,
InstallQASI, // unused old value
BundleLibraries
};
public:
AndroidDeployStep(ProjectExplorer::BuildStepList *bc);
virtual ~AndroidDeployStep();
QString deviceSerialNumber();
AndroidDeployAction deployAction();
bool fromMap(const QVariantMap &map);
QVariantMap toMap() const;
bool bundleQtOptionAvailable();
public slots:
void setDeployAction(AndroidDeployAction deploy);
signals:
void done();
void error();
void deployOptionsChanged();
private slots:
bool deployPackage();
void handleBuildOutput();
void handleBuildError();
void kitUpdated(ProjectExplorer::Kit *kit);
private:
AndroidDeployStep(ProjectExplorer::BuildStepList *bc,
AndroidDeployStep *other);
virtual bool init();
virtual void run(QFutureInterface<bool> &fi);
virtual ProjectExplorer::BuildStepConfigWidget *createConfigWidget();
virtual bool immutable() const { return true; }
void ctor();
void raiseError(const QString &error);
void writeOutput(const QString &text, OutputFormat = MessageOutput);
bool runCommand(QProcess *buildProc, const QString &program, const QStringList &arguments);
unsigned int remoteModificationTime(const QString &fullDestination,
QHash<QString, unsigned int> *cache);
void collectFiles(QList<DeployItem> *deployList, const QString &localPath,
const QString &remotePath, bool strip, const QStringList &filter = QStringList());
void filterModificationTimes(QList<DeployItem> *deployList);
void copyFilesToTemp(QList<DeployItem> *deployList, const QString &tempDirectory, const QString &sourcePrefix);
void fetchRemoteModificationTimes(QList<DeployItem> *deployList);
void stripFiles(const QList<DeployItem> &deployList, ProjectExplorer::Abi::Architecture architecture, const QString &ndkToolchainVersion);
void deployFiles(QProcess *process, const QList<DeployItem> &deployList);
bool checkForQt51Files();
private:
QString m_deviceSerialNumber;
int m_deviceAPILevel;
QString m_targetArch;
AndroidDeployAction m_deployAction;
// members to transfer data from init() to run
QString m_avdName;
QString m_packageName;
QString m_qtVersionSourcePath;
bool m_signPackage;
Utils::FileName m_androidDirPath;
QString m_apkPathDebug;
QString m_apkPathRelease;
QString m_buildDirectory;
AndroidDeployAction m_runDeployAction;
QString m_ndkToolChainVersion;
QString m_libgnustl;
bool m_bundleQtAvailable;
static const Core::Id Id;
};
} // namespace Internal
} // namespace Android
#endif // ANDROIDDEPLOYSTEP_H

View File

@@ -1,114 +0,0 @@
/**************************************************************************
**
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "androiddeploystepfactory.h"
#include "androiddeploystep.h"
#include "androidmanager.h"
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtsupportconstants.h>
#include <qtsupport/qtkitinformation.h>
#include <QCoreApplication>
using namespace ProjectExplorer;
namespace Android {
namespace Internal {
AndroidDeployStepFactory::AndroidDeployStepFactory(QObject *parent)
: IBuildStepFactory(parent)
{
}
QList<Core::Id> AndroidDeployStepFactory::availableCreationIds(BuildStepList *parent) const
{
if (parent->id() != ProjectExplorer::Constants::BUILDSTEPS_DEPLOY)
return QList<Core::Id>();
if (!AndroidManager::supportsAndroid(parent->target()))
return QList<Core::Id>();
if (parent->contains(AndroidDeployStep::Id))
return QList<Core::Id>();
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(parent->target()->kit());
if (qtVersion && qtVersion->qtVersion() >= QtSupport::QtVersionNumber(5, 2, 0))
return QList<Core::Id>();
return QList<Core::Id>() << AndroidDeployStep::Id;
}
QString AndroidDeployStepFactory::displayNameForId(Core::Id id) const
{
if (id == AndroidDeployStep::Id)
return tr("Deploy to Android device or emulator");
return QString();
}
bool AndroidDeployStepFactory::canCreate(BuildStepList *parent, Core::Id id) const
{
return availableCreationIds(parent).contains(id);
}
BuildStep *AndroidDeployStepFactory::create(BuildStepList *parent, Core::Id id)
{
Q_ASSERT(canCreate(parent, id));
Q_UNUSED(id);
return new AndroidDeployStep(parent);
}
bool AndroidDeployStepFactory::canRestore(BuildStepList *parent, const QVariantMap &map) const
{
return canCreate(parent, idFromMap(map));
}
BuildStep *AndroidDeployStepFactory::restore(BuildStepList *parent, const QVariantMap &map)
{
Q_ASSERT(canRestore(parent, map));
AndroidDeployStep * const step = new AndroidDeployStep(parent);
if (!step->fromMap(map)) {
delete step;
return 0;
}
return step;
}
bool AndroidDeployStepFactory::canClone(BuildStepList *parent, BuildStep *product) const
{
return canCreate(parent, product->id());
}
BuildStep *AndroidDeployStepFactory::clone(BuildStepList *parent, BuildStep *product)
{
Q_ASSERT(canClone(parent, product));
return new AndroidDeployStep(parent, static_cast<AndroidDeployStep *>(product));
}
} // namespace Internal
} // namespace Android

View File

@@ -1,62 +0,0 @@
/**************************************************************************
**
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef ANDROIDDEPLOYSTEPFACTORY_H
#define ANDROIDDEPLOYSTEPFACTORY_H
#include <projectexplorer/buildstep.h>
namespace Android {
namespace Internal {
class AndroidDeployStepFactory : public ProjectExplorer::IBuildStepFactory
{
Q_OBJECT
public:
explicit AndroidDeployStepFactory(QObject *parent = 0);
QList<Core::Id> availableCreationIds(ProjectExplorer::BuildStepList *parent) const;
QString displayNameForId(Core::Id id) const;
bool canCreate(ProjectExplorer::BuildStepList *parent, Core::Id id) const;
ProjectExplorer::BuildStep *create(ProjectExplorer::BuildStepList *parent, Core::Id id);
bool canRestore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map) const;
ProjectExplorer::BuildStep *restore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map);
bool canClone(ProjectExplorer::BuildStepList *parent,
ProjectExplorer::BuildStep *product) const;
ProjectExplorer::BuildStep *clone(ProjectExplorer::BuildStepList *parent,
ProjectExplorer::BuildStep *product);
};
} // namespace Internal
} // namespace Android
#endif // ANDROIDDEPLOYSTEPFACTORY_H

View File

@@ -1,136 +0,0 @@
/**************************************************************************
**
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "androiddeploystepwidget.h"
#include "ui_androiddeploystepwidget.h"
#include "androiddeploystep.h"
#include "androidmanager.h"
#include "androidrunconfiguration.h"
#include <coreplugin/icore.h>
#include <QFileDialog>
namespace Android {
namespace Internal {
AndroidDeployStepWidget::AndroidDeployStepWidget(AndroidDeployStep *step) :
ProjectExplorer::BuildStepConfigWidget(),
ui(new Ui::AndroidDeployStepWidget),
m_step(step)
{
ui->setupUi(this);
deployOptionsChanged();
connect(ui->ministroOption, SIGNAL(clicked()), SLOT(setMinistro()));
connect(ui->temporaryQtOption, SIGNAL(clicked()), SLOT(setDeployLocalQtLibs()));
connect(ui->bundleQtOption, SIGNAL(clicked()), SLOT(setBundleQtLibs()));
connect(ui->chooseButton, SIGNAL(clicked()), SLOT(setQASIPackagePath()));
connect(ui->cleanLibsPushButton, SIGNAL(clicked()), SLOT(cleanLibsOnDevice()));
connect(ui->resetDefaultDevices, SIGNAL(clicked()), SLOT(resetDefaultDevices()));
connect(m_step, SIGNAL(deployOptionsChanged()),
this, SLOT(deployOptionsChanged()));
}
void AndroidDeployStepWidget::deployOptionsChanged()
{
switch (m_step->deployAction()) {
case AndroidDeployStep::NoDeploy:
ui->ministroOption->setChecked(true);
break;
case AndroidDeployStep::DeployLocal:
ui->temporaryQtOption->setChecked(true);
break;
case AndroidDeployStep::BundleLibraries:
ui->bundleQtOption->setChecked(true);
break;
default:
ui->ministroOption->setChecked(true);
break;
}
ui->bundleQtOption->setVisible(m_step->bundleQtOptionAvailable());
}
AndroidDeployStepWidget::~AndroidDeployStepWidget()
{
delete ui;
}
QString AndroidDeployStepWidget::displayName() const
{
return tr("<b>Deploy configurations</b>");
}
QString AndroidDeployStepWidget::summaryText() const
{
return displayName();
}
void AndroidDeployStepWidget::setMinistro()
{
m_step->setDeployAction(AndroidDeployStep::NoDeploy);
}
void AndroidDeployStepWidget::setDeployLocalQtLibs()
{
m_step->setDeployAction(AndroidDeployStep::DeployLocal);
}
void AndroidDeployStepWidget::setBundleQtLibs()
{
m_step->setDeployAction(AndroidDeployStep::BundleLibraries);
}
void AndroidDeployStepWidget::setQASIPackagePath()
{
QString packagePath =
QFileDialog::getOpenFileName(this, tr("Qt Android Smart Installer"),
QDir::homePath(), tr("Android package (*.apk)"));
if (!packagePath.isEmpty())
AndroidManager::installQASIPackage(m_step->target(), packagePath);
}
void AndroidDeployStepWidget::cleanLibsOnDevice()
{
AndroidManager::cleanLibsOnDevice(m_step->target());
}
void AndroidDeployStepWidget::resetDefaultDevices()
{
AndroidConfigurations::clearDefaultDevices(m_step->project());
}
} // namespace Internal
} // namespace Android

View File

@@ -1,72 +0,0 @@
/**************************************************************************
**
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef ANDROIDDEPLOYSTEPWIDGET_H
#define ANDROIDDEPLOYSTEPWIDGET_H
#include <projectexplorer/buildstep.h>
QT_BEGIN_NAMESPACE
namespace Ui { class AndroidDeployStepWidget; }
QT_END_NAMESPACE
namespace Android {
namespace Internal {
class AndroidDeployStep;
class AndroidDeployStepWidget : public ProjectExplorer::BuildStepConfigWidget
{
Q_OBJECT
public:
AndroidDeployStepWidget(AndroidDeployStep *step);
~AndroidDeployStepWidget();
private slots:
void setMinistro();
void setDeployLocalQtLibs();
void setBundleQtLibs();
void setQASIPackagePath();
void cleanLibsOnDevice();
void resetDefaultDevices();
void deployOptionsChanged();
private:
virtual QString summaryText() const;
virtual QString displayName() const;
Ui::AndroidDeployStepWidget *ui;
AndroidDeployStep *m_step;
};
} // namespace Internal
} // namespace Android
#endif // ANDROIDDEPLOYSTEPWIDGET_H

View File

@@ -1,113 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AndroidDeployStepWidget</class>
<widget class="QWidget" name="AndroidDeployStepWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>682</width>
<height>183</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Qt Deployment</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QRadioButton" name="ministroOption">
<property name="toolTip">
<string>Uses the external Ministro application to download and maintain Qt libraries.</string>
</property>
<property name="text">
<string>Use Ministro service to install Qt</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="temporaryQtOption">
<property name="toolTip">
<string>Pushes local Qt libraries to device. You must have Qt libraries compiled for that platform.
The APK will not be usable on any other device.</string>
</property>
<property name="text">
<string>Deploy local Qt libraries to temporary directory</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="bundleQtOption">
<property name="toolTip">
<string>Creates a standalone APK.</string>
</property>
<property name="text">
<string>Bundle Qt libraries in APK</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Advanced Actions</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QPushButton" name="cleanLibsPushButton">
<property name="text">
<string>Clean Temporary Libraries Directory on Device</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="chooseButton">
<property name="text">
<string>Install Ministro from APK</string>
</property>
</widget>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="resetDefaultDevices">
<property name="text">
<string>Reset Default Devices</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -31,9 +31,7 @@
#include "androiddeployconfiguration.h"
#include "androidconfigurations.h"
#include "androidrunconfiguration.h"
#include "androiddeploystep.h"
#include "androidglobal.h"
#include "androidpackagecreationstep.h"
#include "androidtoolchain.h"
#include "androiddeployqtstep.h"
@@ -66,62 +64,6 @@ namespace {
const QLatin1String AndroidLibsFileName("/res/values/libs.xml");
const QLatin1String AndroidStringsFileName("/res/values/strings.xml");
const QLatin1String AndroidDefaultPropertiesName("project.properties");
const QLatin1String AndroidLibraryPrefix("--Managed_by_Qt_Creator--");
QString cleanPackageName(QString packageName)
{
QRegExp legalChars(QLatin1String("[a-zA-Z0-9_\\.]"));
for (int i = 0; i < packageName.length(); ++i)
if (!legalChars.exactMatch(packageName.mid(i, 1)))
packageName[i] = QLatin1Char('_');
static QStringList keywords;
if (keywords.isEmpty())
keywords << QLatin1String("abstract") << QLatin1String("continue") << QLatin1String("for")
<< QLatin1String("new") << QLatin1String("switch") << QLatin1String("assert")
<< QLatin1String("default") << QLatin1String("if") << QLatin1String("package")
<< QLatin1String("synchronized") << QLatin1String("boolean") << QLatin1String("do")
<< QLatin1String("goto") << QLatin1String("private") << QLatin1String("this")
<< QLatin1String("break") << QLatin1String("double") << QLatin1String("implements")
<< QLatin1String("protected") << QLatin1String("throw") << QLatin1String("byte")
<< QLatin1String("else") << QLatin1String("import") << QLatin1String("public")
<< QLatin1String("throws") << QLatin1String("case") << QLatin1String("enum")
<< QLatin1String("instanceof") << QLatin1String("return") << QLatin1String("transient")
<< QLatin1String("catch") << QLatin1String("extends") << QLatin1String("int")
<< QLatin1String("short") << QLatin1String("try") << QLatin1String("char")
<< QLatin1String("final") << QLatin1String("interface") << QLatin1String("static")
<< QLatin1String("void") << QLatin1String("class") << QLatin1String("finally")
<< QLatin1String("long") << QLatin1String("strictfp") << QLatin1String("volatile")
<< QLatin1String("const") << QLatin1String("float") << QLatin1String("native")
<< QLatin1String("super") << QLatin1String("while");
// No keywords
int index = -1;
while (index != packageName.length()) {
int next = packageName.indexOf(QLatin1Char('.'), index + 1);
if (next == -1)
next = packageName.length();
QString word = packageName.mid(index + 1, next - index - 1);
if (!word.isEmpty()) {
QChar c = word[0];
if (c >= QChar(QLatin1Char('0')) && c<= QChar(QLatin1Char('9'))) {
packageName.insert(index + 1, QLatin1Char('_'));
index = next + 1;
continue;
}
}
if (keywords.contains(word)) {
packageName.insert(next, QLatin1String("_"));
index = next + 1;
} else {
index = next;
}
}
return packageName;
}
} // anonymous namespace
namespace Android {
@@ -144,48 +86,6 @@ QString AndroidManager::packageName(ProjectExplorer::Target *target)
return manifestElem.attribute(QLatin1String("package"));
}
bool AndroidManager::setPackageName(ProjectExplorer::Target *target, const QString &name)
{
QDomDocument doc;
if (!openManifest(target, doc))
return false;
QDomElement manifestElem = doc.documentElement();
manifestElem.setAttribute(QLatin1String("package"), cleanPackageName(name));
return saveManifest(target, doc);
}
QString AndroidManager::applicationName(ProjectExplorer::Target *target)
{
QDomDocument doc;
if (!openXmlFile(doc, stringsPath(target)))
return QString();
QDomElement metadataElem = doc.documentElement().firstChildElement(QLatin1String("string"));
while (!metadataElem.isNull()) {
if (metadataElem.attribute(QLatin1String("name")) == QLatin1String("app_name"))
return metadataElem.text();
metadataElem = metadataElem.nextSiblingElement(QLatin1String("string"));
}
return QString();
}
bool AndroidManager::setApplicationName(ProjectExplorer::Target *target, const QString &name)
{
QDomDocument doc;
Utils::FileName path = stringsPath(target);
if (!openXmlFile(doc, path))
return false;
QDomElement metadataElem = doc.documentElement().firstChildElement(QLatin1String("string"));
while (!metadataElem.isNull()) {
if (metadataElem.attribute(QLatin1String("name")) == QLatin1String("app_name")) {
metadataElem.removeChild(metadataElem.firstChild());
metadataElem.appendChild(doc.createTextNode(name));
break;
}
metadataElem = metadataElem.nextSiblingElement(QLatin1String("string"));
}
return saveXmlFile(target, doc, path);
}
QString AndroidManager::intentName(ProjectExplorer::Target *target)
{
return packageName(target) + QLatin1Char('/') + activityName(target);
@@ -220,43 +120,12 @@ int AndroidManager::minimumSDK(ProjectExplorer::Target *target)
QString AndroidManager::buildTargetSDK(ProjectExplorer::Target *target)
{
QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target->kit());
if (qt && qt->qtVersion() >= QtSupport::QtVersionNumber(5, 2, 0)) {
if (!target->activeDeployConfiguration())
return QLatin1String("android-9");
AndroidDeployQtStep *step = AndroidGlobal::buildStep<AndroidDeployQtStep>(target->activeDeployConfiguration());
if (step)
return step->buildTargetSdk();
if (!target->activeDeployConfiguration())
return QLatin1String("android-9");
}
QVariant v = target->namedSettings(QLatin1String("AndroidManager.TargetSdk"));
if (v.isValid())
return v.toString();
QString fallback = QLatin1String("android-8");
if (qt && qt->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0))
fallback = QLatin1String("android-9");
if (!createAndroidTemplatesIfNecessary(target))
return fallback;
QFile file(defaultPropertiesPath(target).toString());
if (!file.open(QIODevice::ReadOnly))
return fallback;
while (!file.atEnd()) {
QByteArray line = file.readLine();
if (line.startsWith("target="))
return QString::fromLatin1(line.trimmed().mid(7));
}
return fallback;
}
bool AndroidManager::setBuildTargetSDK(ProjectExplorer::Target *target, const QString &sdk)
{
updateTarget(target, sdk, applicationName(target));
target->setNamedSettings(QLatin1String("AndroidManager.TargetSdk"), sdk);
return true;
AndroidDeployQtStep *step = AndroidGlobal::buildStep<AndroidDeployQtStep>(target->activeDeployConfiguration());
if (step)
return step->buildTargetSdk();
return QLatin1String("android-9");
}
QString AndroidManager::targetArch(ProjectExplorer::Target *target)
@@ -272,11 +141,7 @@ QString AndroidManager::targetArch(ProjectExplorer::Target *target)
Utils::FileName AndroidManager::dirPath(ProjectExplorer::Target *target)
{
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(target->kit());
if (qtVersion && qtVersion->qtVersion() >= QtSupport::QtVersionNumber(5, 2, 0))
return target->activeBuildConfiguration()->buildDirectory().appendPath(QLatin1String(Constants::ANDROID_BUILDDIRECTORY));
Utils::FileName dir = target->project()->projectDirectory();
return dir.appendPath(AndroidDirName);
return target->activeBuildConfiguration()->buildDirectory().appendPath(QLatin1String(Constants::ANDROID_BUILDDIRECTORY));
}
Utils::FileName AndroidManager::manifestPath(ProjectExplorer::Target *target)
@@ -289,21 +154,11 @@ Utils::FileName AndroidManager::libsPath(ProjectExplorer::Target *target)
return dirPath(target).appendPath(AndroidLibsFileName);
}
Utils::FileName AndroidManager::stringsPath(ProjectExplorer::Target *target)
{
return dirPath(target).appendString(AndroidStringsFileName);
}
Utils::FileName AndroidManager::defaultPropertiesPath(ProjectExplorer::Target *target)
{
return dirPath(target).appendPath(AndroidDefaultPropertiesName);
}
Utils::FileName AndroidManager::srcPath(ProjectExplorer::Target *target)
{
return dirPath(target).appendPath(QLatin1String("/src"));
}
Utils::FileName AndroidManager::apkPath(ProjectExplorer::Target *target, BuildType buildType)
{
QString packageName = QLatin1String("QtApp");
@@ -315,14 +170,6 @@ Utils::FileName AndroidManager::apkPath(ProjectExplorer::Target *target, BuildTy
else
buildTypeName = QLatin1String("release");
QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target->kit());
if (!qt || qt->qtVersion() < QtSupport::QtVersionNumber(5, 2, 0)) {
// Qt 5.1 and earlier:
packageName = applicationName(target);
if (buildType == ReleaseBuildSigned)
buildTypeName = QLatin1String("signed");
}
return dirPath(target)
.appendPath(QLatin1String("bin"))
.appendPath(QString::fromLatin1("%1-%2.apk")
@@ -349,30 +196,8 @@ QStringList AndroidManager::availableTargetApplications(ProjectExplorer::Target
return apps;
}
QString AndroidManager::targetApplication(ProjectExplorer::Target *target)
{
QDomDocument doc;
if (!openManifest(target, doc))
return QString();
QDomElement metadataElem = doc.documentElement().firstChildElement(QLatin1String("application")).firstChildElement(QLatin1String("activity")).firstChildElement(QLatin1String("meta-data"));
while (!metadataElem.isNull()) {
if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.lib_name"))
return metadataElem.attribute(QLatin1String("android:value"));
metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data"));
}
return QString();
}
// Note, this could be implemented via a base class and a couple of virtuals
// but I intend to remove the indirection once we drop support for qt 4.8
// and qt 5.1.
bool AndroidManager::bundleQt(ProjectExplorer::Target *target)
{
AndroidDeployStep *androidDeployStep
= AndroidGlobal::buildStep<AndroidDeployStep>(target->activeDeployConfiguration());
if (androidDeployStep)
return androidDeployStep->deployAction() == AndroidDeployStep::BundleLibraries;
AndroidDeployQtStep *androidDeployQtStep
= AndroidGlobal::buildStep<AndroidDeployQtStep>(target->activeDeployConfiguration());
if (androidDeployQtStep)
@@ -383,13 +208,6 @@ bool AndroidManager::bundleQt(ProjectExplorer::Target *target)
bool AndroidManager::useLocalLibs(ProjectExplorer::Target *target)
{
AndroidDeployStep *androidDeployStep
= AndroidGlobal::buildStep<AndroidDeployStep>(target->activeDeployConfiguration());
if (androidDeployStep) {
return androidDeployStep->deployAction() == AndroidDeployStep::DeployLocal
|| androidDeployStep->deployAction() == AndroidDeployStep::BundleLibraries;
}
AndroidDeployQtStep *androidDeployQtStep
= AndroidGlobal::buildStep<AndroidDeployQtStep>(target->activeDeployConfiguration());
if (androidDeployQtStep) {
@@ -402,11 +220,6 @@ bool AndroidManager::useLocalLibs(ProjectExplorer::Target *target)
QString AndroidManager::deviceSerialNumber(ProjectExplorer::Target *target)
{
AndroidDeployStep *androidDeployStep
= AndroidGlobal::buildStep<AndroidDeployStep>(target->activeDeployConfiguration());
if (androidDeployStep)
return androidDeployStep->deviceSerialNumber();
AndroidDeployQtStep *androidDeployQtStep
= AndroidGlobal::buildStep<AndroidDeployQtStep>(target->activeDeployConfiguration());
if (androidDeployQtStep)
@@ -414,307 +227,6 @@ QString AndroidManager::deviceSerialNumber(ProjectExplorer::Target *target)
return QString();
}
bool AndroidManager::updateDeploymentSettings(ProjectExplorer::Target *target)
{
// For Qt 4, the "use local libs" options is handled by passing command line arguments to the
// app, so no need to alter the AndroidManifest.xml
QtSupport::BaseQtVersion *baseQtVersion = QtSupport::QtKitInformation::qtVersion(target->kit());
if (baseQtVersion == 0 || baseQtVersion->qtVersion() < QtSupport::QtVersionNumber(5,0,0))
return true;
if (baseQtVersion->qtVersion() >= QtSupport::QtVersionNumber(5, 2, 0))
return true;
ProjectExplorer::RunConfiguration *runConfiguration = target->activeRunConfiguration();
AndroidRunConfiguration *androidRunConfiguration = qobject_cast<AndroidRunConfiguration *>(runConfiguration);
if (androidRunConfiguration == 0)
return false;
bool useLocalLibs = AndroidManager::useLocalLibs(target);
bool bundleQtLibs = AndroidManager::bundleQt(target);
QDomDocument doc;
if (!openManifest(target, doc))
return false;
QDomElement metadataElem = doc.documentElement().firstChildElement(QLatin1String("application")).firstChildElement(QLatin1String("activity")).firstChildElement(QLatin1String("meta-data"));
// ### Passes -1 for API level, which means it won't work with setups that require
// library selection based on API level. Use the old approach (command line argument)
// in these cases. Hence the Qt version > 4 condition at the beginning of this function.
QString localLibs;
QString localJars;
QString staticInitClasses;
if (useLocalLibs) {
localLibs = loadLocalLibs(target, -1);
localJars = loadLocalJars(target, -1);
staticInitClasses = loadLocalJarsInitClasses(target, -1);
}
bool changedManifest = false;
while (!metadataElem.isNull()) {
if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.use_local_qt_libs")) {
if (metadataElem.attribute(QLatin1String("android:value")).toInt() != int(useLocalLibs)) {
metadataElem.setAttribute(QLatin1String("android:value"), int(useLocalLibs));
changedManifest = true;
}
} else if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.load_local_libs")) {
if (metadataElem.attribute(QLatin1String("android:value")) != localLibs) {
metadataElem.setAttribute(QLatin1String("android:value"), localLibs);
changedManifest = true;
}
} else if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.load_local_jars")) {
if (metadataElem.attribute(QLatin1String("android:value")) != localJars) {
metadataElem.setAttribute(QLatin1String("android:value"), localJars);
changedManifest = true;
}
} else if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.static_init_classes")) {
if (metadataElem.attribute(QLatin1String("android:value")) != staticInitClasses) {
metadataElem.setAttribute(QLatin1String("android:value"), staticInitClasses);
changedManifest = true;
}
} else if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.bundle_local_qt_libs")) {
if (metadataElem.attribute(QLatin1String("android:value")).toInt() != int(bundleQtLibs)) {
metadataElem.setAttribute(QLatin1String("android:value"), int(bundleQtLibs));
changedManifest = true;
}
}
metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data"));
}
if (changedManifest)
return saveManifest(target, doc);
else
return true;
}
bool AndroidManager::setTargetApplication(ProjectExplorer::Target *target, const QString &name)
{
QDomDocument doc;
if (!openManifest(target, doc))
return false;
QDomElement metadataElem = doc.documentElement().firstChildElement(QLatin1String("application")).firstChildElement(QLatin1String("activity")).firstChildElement(QLatin1String("meta-data"));
while (!metadataElem.isNull()) {
if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")) {
metadataElem.setAttribute(QLatin1String("android:value"), name);
return saveManifest(target, doc);
}
metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data"));
}
return false;
}
QString AndroidManager::targetApplicationPath(ProjectExplorer::Target *target)
{
QString selectedApp = targetApplication(target);
if (selectedApp.isEmpty())
return QString();
QmakeProjectManager::QmakeProject *qmakeProject = qobject_cast<QmakeProjectManager::QmakeProject *>(target->project());
foreach (QmakeProjectManager::QmakeProFileNode *proFile, qmakeProject->applicationProFiles()) {
if (proFile->projectType() == QmakeProjectManager::ApplicationTemplate) {
if (proFile->targetInformation().target.startsWith(QLatin1String("lib"))
&& proFile->targetInformation().target.endsWith(QLatin1String(".so"))) {
if (proFile->targetInformation().target.mid(3, proFile->targetInformation().target.lastIndexOf(QLatin1Char('.')) - 3)
== selectedApp)
return proFile->targetInformation().buildDir + QLatin1Char('/') + proFile->targetInformation().target;
} else {
if (proFile->targetInformation().target == selectedApp)
return proFile->targetInformation().buildDir + QLatin1String("/lib") + proFile->targetInformation().target + QLatin1String(".so");
}
}
}
return QString();
}
bool AndroidManager::createAndroidTemplatesIfNecessary(ProjectExplorer::Target *target)
{
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit());
QmakeProjectManager::QmakeProject *qmakeProject = qobject_cast<QmakeProjectManager::QmakeProject*>(target->project());
if (!qmakeProject || !qmakeProject->rootProjectNode() || !version)
return false;
// TODO we should create the AndroidManifest.xml file for that version
if (version->qtVersion() >= QtSupport::QtVersionNumber(5, 2, 0))
return true;
Utils::FileName javaSrcPath
= Utils::FileName::fromString(version->qmakeProperty("QT_INSTALL_PREFIX"))
.appendPath(QLatin1String("src/android/java"));
QDir projectDir(qmakeProject->projectDirectory().toString());
Utils::FileName androidPath = dirPath(target);
QStringList m_ignoreFiles;
bool forceUpdate = false;
QDomDocument srcVersionDoc;
Utils::FileName srcVersionPath = javaSrcPath;
srcVersionPath.appendPath(QLatin1String("version.xml"));
if (openXmlFile(srcVersionDoc, srcVersionPath)) {
QDomDocument dstVersionDoc;
Utils::FileName dstVersionPath=androidPath;
dstVersionPath.appendPath(QLatin1String("version.xml"));
if (openXmlFile(dstVersionDoc, dstVersionPath))
forceUpdate = (srcVersionDoc.documentElement().attribute(QLatin1String("value")).toDouble()
> dstVersionDoc.documentElement().attribute(QLatin1String("value")).toDouble());
else
forceUpdate = true;
if (forceUpdate && androidPath.toFileInfo().exists()) {
QDomElement ignoreFile = srcVersionDoc.documentElement().firstChildElement(QLatin1String("ignore")).firstChildElement(QLatin1String("file"));
while (!ignoreFile.isNull()) {
m_ignoreFiles << ignoreFile.text();
ignoreFile = ignoreFile.nextSiblingElement();
}
}
}
Utils::FileName src = androidPath;
src.appendPath(QLatin1String("src"));
Utils::FileName res = androidPath;
res.appendPath(QLatin1String("res"));
if (!forceUpdate && androidPath.toFileInfo().exists()
&& manifestPath(target).toFileInfo().exists()
&& src.toFileInfo().exists()
&& res.toFileInfo().exists())
return true;
forceUpdate &= androidPath.toFileInfo().exists();
if (!dirPath(target).toFileInfo().exists() && !projectDir.mkdir(AndroidDirName)) {
raiseError(tr("Error creating Android directory \"%1\".").arg(AndroidDirName));
return false;
}
QStringList androidFiles;
QDirIterator it(javaSrcPath.toString(), QDirIterator::Subdirectories);
int pos = it.path().size();
while (it.hasNext()) {
it.next();
if (it.fileInfo().isDir()) {
projectDir.mkpath(AndroidDirName + it.filePath().mid(pos));
} else {
Utils::FileName dstFile = androidPath;
dstFile.appendPath(it.filePath().mid(pos));
if (m_ignoreFiles.contains(it.fileName())) {
continue;
} else {
if (dstFile.toFileInfo().exists())
QFile::remove(dstFile.toString());
else
androidFiles << dstFile.toString();
}
QFile::copy(it.filePath(), dstFile.toString());
}
}
if (!androidFiles.isEmpty())
qmakeProject->rootProjectNode()->addFiles(androidFiles);
int minApiLevel = 4;
if (QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target->kit()))
if (qt->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0))
minApiLevel = 9;
QStringList sdks = AndroidConfig::apiLevelNamesFor(AndroidConfigurations::currentConfig().sdkTargets(minApiLevel));
if (sdks.isEmpty()) {
raiseError(tr("No Qt for Android SDKs were found.\nPlease install at least one SDK."));
return false;
}
updateTarget(target, sdks.first());
QStringList apps = availableTargetApplications(target);
if (!apps.isEmpty())
setTargetApplication(target, apps.at(0));
QString applicationName = target->project()->displayName();
if (!applicationName.isEmpty()) {
setPackageName(target, packageName(target) + QLatin1Char('.') + applicationName);
applicationName[0] = applicationName[0].toUpper();
setApplicationName(target, applicationName);
}
if (forceUpdate)
QMessageBox::warning(Core::ICore::dialogParent(), tr("Warning"), tr("Android files have been updated automatically."));
return true;
}
void AndroidManager::updateTarget(ProjectExplorer::Target *target, const QString &targetSDK, const QString &name)
{
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(target->kit());
if (qtVersion && qtVersion->qtVersion() >= QtSupport::QtVersionNumber(5,2,0))
return;
QString androidDir = dirPath(target).toString();
Utils::Environment env = Utils::Environment::systemEnvironment();
QString javaHome = AndroidConfigurations::currentConfig().openJDKLocation().toString();
if (!javaHome.isEmpty())
env.set(QLatin1String("JAVA_HOME"), javaHome);
// clean previous build
QProcess androidProc;
androidProc.setWorkingDirectory(androidDir);
androidProc.setProcessEnvironment(env.toProcessEnvironment());
androidProc.start(AndroidConfigurations::currentConfig().antToolPath().toString(),
QStringList() << QLatin1String("clean"));
if (!androidProc.waitForFinished(-1))
androidProc.terminate();
// clean previous build
int targetSDKNumber = targetSDK.mid(targetSDK.lastIndexOf(QLatin1Char('-')) + 1).toInt();
bool commentLines = false;
QDirIterator it(androidDir, QStringList() << QLatin1String("*.java"), QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
it.next();
QFile file(it.filePath());
if (!file.open(QIODevice::ReadWrite))
continue;
QList<QByteArray> lines = file.readAll().trimmed().split('\n');
bool modified = false;
bool comment = false;
for (int i = 0; i < lines.size(); i++) {
QByteArray trimmed = lines[i].trimmed();
if (trimmed.contains("@ANDROID-")) {
commentLines = targetSDKNumber < trimmed.mid(trimmed.lastIndexOf('-') + 1).toInt();
comment = !comment;
continue;
}
if (!comment)
continue;
if (commentLines) {
if (!trimmed.startsWith("//QtCreator")) {
lines[i] = "//QtCreator " + lines[i];
modified = true;
}
} else { if (trimmed.startsWith("//QtCreator")) {
lines[i] = lines[i].mid(12);
modified = true;
}
}
}
if (modified) {
file.resize(0);
foreach (const QByteArray &line, lines) {
file.write(line);
file.write("\n");
}
}
file.close();
}
QStringList params;
params << QLatin1String("update") << QLatin1String("project") << QLatin1String("-p") << androidDir;
if (!targetSDK.isEmpty())
params << QLatin1String("-t") << targetSDK;
if (!name.isEmpty())
params << QLatin1String("-n") << name;
androidProc.setProcessEnvironment(AndroidConfigurations::currentConfig().androidToolEnvironment().toProcessEnvironment());
androidProc.start(AndroidConfigurations::currentConfig().androidToolPath().toString(), params);
if (!androidProc.waitForFinished(-1))
androidProc.terminate();
}
Utils::FileName AndroidManager::localLibsRulesFilePath(ProjectExplorer::Target *target)
{
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit());
@@ -728,11 +240,6 @@ QString AndroidManager::loadLocalLibs(ProjectExplorer::Target *target, int apiLe
return loadLocal(target, apiLevel, Lib);
}
QString AndroidManager::loadLocalBundledFiles(ProjectExplorer::Target *target, int apiLevel)
{
return loadLocal(target, apiLevel, BundledFile);
}
QString AndroidManager::loadLocalJars(ProjectExplorer::Target *target, int apiLevel)
{
ItemType type = bundleQt(target) ? BundledJar : Jar;
@@ -745,17 +252,9 @@ QString AndroidManager::loadLocalJarsInitClasses(ProjectExplorer::Target *target
return loadLocal(target, apiLevel, type, QLatin1String("initClass"));
}
QPair<int, int> AndroidManager::apiLevelRange(ProjectExplorer::Target *target)
QPair<int, int> AndroidManager::apiLevelRange()
{
// 4 is the minimum version on which qt is supported
// 19 and 20 are not yet released, but allow the user
// to set them
int minApiLevel = 4;
QtSupport::BaseQtVersion *qt;
if (target && (qt = QtSupport::QtKitInformation::qtVersion(target->kit())))
if (qt->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0))
minApiLevel = 9;
return qMakePair(minApiLevel, 20);
return qMakePair(9, 20);
}
QString AndroidManager::androidNameForApiLevel(int x)
@@ -800,139 +299,16 @@ QString AndroidManager::androidNameForApiLevel(int x)
}
}
QVector<AndroidManager::Library> AndroidManager::availableQtLibsWithDependencies(ProjectExplorer::Target *target)
{
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit());
if (!target->activeRunConfiguration())
return QVector<AndroidManager::Library>();
ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(target->kit());
if (tc->type() != QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE))
return QVector<AndroidManager::Library>();
QmakeProjectManager::QmakeProject *project = static_cast<QmakeProjectManager::QmakeProject *>(target->project());
QString arch = project->rootQmakeProjectNode()->singleVariableValue(QmakeProjectManager::AndroidArchVar);
AndroidToolChain *atc = static_cast<AndroidToolChain *>(tc);
QString libgnustl = libGnuStl(arch, atc->ndkToolChainVersion());
Utils::FileName readelfPath = AndroidConfigurations::currentConfig().readelfPath(target->activeRunConfiguration()->abi().architecture(),
atc->ndkToolChainVersion());
const QmakeProjectManager::QmakeProject *const qmakeProject
= qobject_cast<const QmakeProjectManager::QmakeProject *>(target->project());
if (!qmakeProject || !version)
return QVector<AndroidManager::Library>();
QString qtLibsPath = version->qmakeProperty("QT_INSTALL_LIBS");
if (!readelfPath.toFileInfo().exists())
return QVector<AndroidManager::Library>();
LibrariesMap mapLibs;
QDir libPath;
QDirIterator it(qtLibsPath, QStringList() << QLatin1String("*.so"), QDir::Files, QDirIterator::Subdirectories);
while (it.hasNext()) {
libPath = it.next();
const QString library = libPath.absolutePath().mid(libPath.absolutePath().lastIndexOf(QLatin1Char('/')) + 1);
mapLibs[library].dependencies = dependencies(readelfPath, libPath.absolutePath());
}
const QString library = libgnustl.mid(libgnustl.lastIndexOf(QLatin1Char('/')) + 1);
mapLibs[library] = Library();
// clean dependencies
const LibrariesMap::Iterator lend = mapLibs.end();
for (LibrariesMap::Iterator lit = mapLibs.begin(); lit != lend; ++lit) {
Library &library = lit.value();
int it = 0;
while (it < library.dependencies.size()) {
const QString &dependName = library.dependencies[it];
if (!mapLibs.contains(dependName) && dependName.startsWith(QLatin1String("lib")) && dependName.endsWith(QLatin1String(".so")))
library.dependencies.removeAt(it);
else
++it;
}
if (library.dependencies.isEmpty())
library.level = 0;
}
QVector<Library> qtLibraries;
// calculate the level for every library
for (LibrariesMap::Iterator lit = mapLibs.begin(); lit != lend; ++lit) {
Library &library = lit.value();
const QString &key = lit.key();
if (library.level < 0)
setLibraryLevel(key, mapLibs);
if (library.name.isEmpty() && key.startsWith(QLatin1String("lib")) && key.endsWith(QLatin1String(".so")))
library.name = key.mid(3, key.length() - 6);
for (int it = 0; it < library.dependencies.size(); it++) {
const QString &libName = library.dependencies[it];
if (libName.startsWith(QLatin1String("lib")) && libName.endsWith(QLatin1String(".so")))
library.dependencies[it] = libName.mid(3, libName.length() - 6);
}
qtLibraries.push_back(library);
}
Utils::sort(qtLibraries, [](const Library &a, const Library &b) -> bool {
if (a.level == b.level)
return a.name < b.name;
return a.level < b.level;
});
return qtLibraries;
}
QStringList AndroidManager::availableQtLibs(ProjectExplorer::Target *target)
{
QStringList libs;
QVector<Library> qtLibraries = availableQtLibsWithDependencies(target);
foreach (Library lib, qtLibraries)
libs.push_back(lib.name);
return libs;
}
QStringList AndroidManager::qtLibs(ProjectExplorer::Target *target)
{
return libsXml(target, QLatin1String("qt_libs"));
}
bool AndroidManager::setQtLibs(ProjectExplorer::Target *target, const QStringList &libs)
{
return setLibsXml(target, libs, QLatin1String("qt_libs"));
}
bool AndroidManager::setBundledInAssets(ProjectExplorer::Target *target, const QStringList &fileList)
{
return setLibsXml(target, fileList, QLatin1String("bundled_in_assets"));
}
bool AndroidManager::setBundledInLib(ProjectExplorer::Target *target, const QStringList &fileList)
{
return setLibsXml(target, fileList, QLatin1String("bundled_in_lib"));
}
QStringList AndroidManager::availablePrebundledLibs(ProjectExplorer::Target *target)
{
QStringList libs;
QmakeProjectManager::QmakeProject *qmakeProject = qobject_cast<QmakeProjectManager::QmakeProject *>(target->project());
if (!qmakeProject)
return libs;
foreach (QmakeProjectManager::QmakeProFileNode *node, qmakeProject->allProFiles())
if (node->projectType() == QmakeProjectManager::LibraryTemplate)
libs << node->targetInformation().target;
return libs;
}
QStringList AndroidManager::prebundledLibs(ProjectExplorer::Target *target)
{
return libsXml(target, QLatin1String("bundled_libs"));
}
bool AndroidManager::setPrebundledLibs(ProjectExplorer::Target *target, const QStringList &libs)
{
return setLibsXml(target, libs, QLatin1String("bundled_libs"));
}
bool AndroidManager::openLibsXml(ProjectExplorer::Target *target, QDomDocument &doc)
{
return openXmlFile(doc, libsPath(target));
@@ -940,7 +316,7 @@ bool AndroidManager::openLibsXml(ProjectExplorer::Target *target, QDomDocument &
bool AndroidManager::saveLibsXml(ProjectExplorer::Target *target, QDomDocument &doc)
{
return saveXmlFile(target, doc, libsPath(target));
return saveXmlFile(doc, libsPath(target));
}
void AndroidManager::raiseError(const QString &reason)
@@ -1060,11 +436,8 @@ bool AndroidManager::openXmlFile(QDomDocument &doc, const Utils::FileName &fileN
return true;
}
bool AndroidManager::saveXmlFile(ProjectExplorer::Target *target, QDomDocument &doc, const Utils::FileName &fileName)
bool AndroidManager::saveXmlFile(QDomDocument &doc, const Utils::FileName &fileName)
{
if (!createAndroidTemplatesIfNecessary(target))
return false;
QFile f(fileName.toString());
if (!f.open(QIODevice::WriteOnly)) {
raiseError(tr("Cannot open \"%1\".").arg(fileName.toUserOutput()));
@@ -1081,7 +454,7 @@ bool AndroidManager::openManifest(ProjectExplorer::Target *target, QDomDocument
bool AndroidManager::saveManifest(ProjectExplorer::Target *target, QDomDocument &doc)
{
Core::FileChangeBlocker blocker(manifestPath(target).toString());
return saveXmlFile(target, doc, manifestPath(target));
return saveXmlFile(doc, manifestPath(target));
}
QStringList AndroidManager::libsXml(ProjectExplorer::Target *target, const QString &tag)
@@ -1178,21 +551,6 @@ int AndroidManager::setLibraryLevel(const QString &library, LibrariesMap &mapLib
return maxlevel + 1;
}
QString AndroidManager::libGnuStl(const QString &arch, const QString &ndkToolChainVersion)
{
return AndroidConfigurations::currentConfig().ndkLocation().toString()
+ QLatin1String("/sources/cxx-stl/gnu-libstdc++/")
+ ndkToolChainVersion + QLatin1String("/libs/")
+ arch
+ QLatin1String("/libgnustl_shared.so");
}
QString AndroidManager::libraryPrefix()
{
return AndroidLibraryPrefix;
}
void AndroidManager::cleanLibsOnDevice(ProjectExplorer::Target *target)
{
const QString targetArch = AndroidManager::targetArch(target);

View File

@@ -57,26 +57,17 @@ public:
static bool supportsAndroid(ProjectExplorer::Target *target);
static QString packageName(ProjectExplorer::Target *target);
static bool setPackageName(ProjectExplorer::Target *target, const QString &name);
static QString applicationName(ProjectExplorer::Target *target);
static bool setApplicationName(ProjectExplorer::Target *target, const QString &name);
static QString intentName(ProjectExplorer::Target *target);
static QString activityName(ProjectExplorer::Target *target);
static QStringList availableTargetApplications(ProjectExplorer::Target *target);
static QString targetApplication(ProjectExplorer::Target *target);
static bool setTargetApplication(ProjectExplorer::Target *target, const QString &name);
static QString targetApplicationPath(ProjectExplorer::Target *target);
static bool updateDeploymentSettings(ProjectExplorer::Target *target);
static bool bundleQt(ProjectExplorer::Target *target);
static bool useLocalLibs(ProjectExplorer::Target *target);
static QString deviceSerialNumber(ProjectExplorer::Target *target);
static QString buildTargetSDK(ProjectExplorer::Target *target);
static bool setBuildTargetSDK(ProjectExplorer::Target *target, const QString &sdk);
static int minimumSDK(ProjectExplorer::Target *target);
static QString targetArch(ProjectExplorer::Target *target);
@@ -84,22 +75,15 @@ public:
static Utils::FileName dirPath(ProjectExplorer::Target *target);
static Utils::FileName manifestPath(ProjectExplorer::Target *target);
static Utils::FileName libsPath(ProjectExplorer::Target *target);
static Utils::FileName stringsPath(ProjectExplorer::Target *target);
static Utils::FileName defaultPropertiesPath(ProjectExplorer::Target *target);
static Utils::FileName srcPath(ProjectExplorer::Target *target);
static Utils::FileName apkPath(ProjectExplorer::Target *target, BuildType buildType);
static bool createAndroidTemplatesIfNecessary(ProjectExplorer::Target *target);
static void updateTarget(ProjectExplorer::Target *target, const QString &buildTargetSDK,
const QString &name = QString());
static Utils::FileName localLibsRulesFilePath(ProjectExplorer::Target *target);
static QString loadLocalLibs(ProjectExplorer::Target *target, int apiLevel = -1);
static QString loadLocalJars(ProjectExplorer::Target *target, int apiLevel = -1);
static QString loadLocalBundledFiles(ProjectExplorer::Target *target, int apiLevel = -1);
static QString loadLocalJarsInitClasses(ProjectExplorer::Target *target, int apiLevel = -1);
static QPair<int, int> apiLevelRange(ProjectExplorer::Target *target);
static QPair<int, int> apiLevelRange();
static QString androidNameForApiLevel(int x);
class Library
@@ -113,22 +97,8 @@ public:
};
typedef QMap<QString, Library> LibrariesMap;
static QVector<AndroidManager::Library> availableQtLibsWithDependencies(ProjectExplorer::Target *target);
static QStringList availableQtLibs(ProjectExplorer::Target *target);
static QStringList qtLibs(ProjectExplorer::Target *target);
static bool setQtLibs(ProjectExplorer::Target *target, const QStringList &libs);
static bool setBundledInLib(ProjectExplorer::Target *target,
const QStringList &fileList);
static bool setBundledInAssets(ProjectExplorer::Target *target,
const QStringList &fileList);
static QStringList availablePrebundledLibs(ProjectExplorer::Target *target);
static QStringList prebundledLibs(ProjectExplorer::Target *target);
static bool setPrebundledLibs(ProjectExplorer::Target *target, const QStringList &libs);
static QString libGnuStl(const QString &arch, const QString &ndkToolChainVersion);
static QString libraryPrefix();
static void cleanLibsOnDevice(ProjectExplorer::Target *target);
static void installQASIPackage(ProjectExplorer::Target *target, const QString &packagePath);
@@ -139,7 +109,7 @@ public:
private:
static void raiseError(const QString &reason);
static bool openXmlFile(QDomDocument &doc, const Utils::FileName &fileName);
static bool saveXmlFile(ProjectExplorer::Target *target, QDomDocument &doc, const Utils::FileName &fileName);
static bool saveXmlFile(QDomDocument &doc, const Utils::FileName &fileName);
static bool openManifest(ProjectExplorer::Target *target, QDomDocument &doc);
static bool saveManifest(ProjectExplorer::Target *target, QDomDocument &doc);
static bool openLibsXml(ProjectExplorer::Target *target, QDomDocument &doc);

View File

@@ -690,8 +690,7 @@ void AndroidManifestEditorWidget::updateInfoBar()
void AndroidManifestEditorWidget::updateSdkVersions()
{
const QString docPath(m_textEditorWidget->baseTextDocument()->filePath());
Project *project = androidProject(docPath);
QPair<int, int> apiLevels = AndroidManager::apiLevelRange(project ? project->activeTarget() : 0);
QPair<int, int> apiLevels = AndroidManager::apiLevelRange();
for (int i = apiLevels.first; i < apiLevels.second + 1; ++i)
m_androidMinSdkVersion->addItem(tr("API %1: %2")
.arg(i)

View File

@@ -1,112 +0,0 @@
/**************************************************************************
**
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "androidpackagecreationfactory.h"
#include "androidpackagecreationstep.h"
#include "androidmanager.h"
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtkitinformation.h>
using namespace ProjectExplorer;
namespace Android {
namespace Internal {
AndroidPackageCreationFactory::AndroidPackageCreationFactory(QObject *parent)
: IBuildStepFactory(parent)
{
}
QList<Core::Id> AndroidPackageCreationFactory::availableCreationIds(BuildStepList *parent) const
{
if (parent->id() != Constants::BUILDSTEPS_DEPLOY)
return QList<Core::Id>();
if (!AndroidManager::supportsAndroid(parent->target()))
return QList<Core::Id>();
if (parent->contains(AndroidPackageCreationStep::CreatePackageId))
return QList<Core::Id>();
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(parent->target()->kit());
if (qtVersion && qtVersion->qtVersion() >= QtSupport::QtVersionNumber(5, 2, 0))
return QList<Core::Id>();
return QList<Core::Id>() << AndroidPackageCreationStep::CreatePackageId;
}
QString AndroidPackageCreationFactory::displayNameForId(Core::Id id) const
{
if (id == AndroidPackageCreationStep::CreatePackageId)
return tr("Create Android (.apk) Package");
return QString();
}
bool AndroidPackageCreationFactory::canCreate(BuildStepList *parent, Core::Id id) const
{
return availableCreationIds(parent).contains(id);
}
BuildStep *AndroidPackageCreationFactory::create(BuildStepList *parent, Core::Id id)
{
Q_ASSERT(canCreate(parent, id));
Q_UNUSED(id);
return new AndroidPackageCreationStep(parent);
}
bool AndroidPackageCreationFactory::canRestore(BuildStepList *parent, const QVariantMap &map) const
{
return canCreate(parent, idFromMap(map));
}
BuildStep *AndroidPackageCreationFactory::restore(BuildStepList *parent, const QVariantMap &map)
{
Q_ASSERT(canRestore(parent, map));
AndroidPackageCreationStep *const step = new AndroidPackageCreationStep(parent);
if (!step->fromMap(map)) {
delete step;
return 0;
}
return step;
}
bool AndroidPackageCreationFactory::canClone(BuildStepList *parent, BuildStep *product) const
{
return canCreate(parent, product->id());
}
BuildStep *AndroidPackageCreationFactory::clone(BuildStepList *parent, BuildStep *product)
{
Q_ASSERT(canClone(parent, product));
return new AndroidPackageCreationStep(parent, static_cast<AndroidPackageCreationStep *>(product));
}
} // namespace Internal
} // namespace Android

View File

@@ -1,63 +0,0 @@
/**************************************************************************
**
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef ANDROIDPACKAGECREATIONFACTORY_H
#define ANDROIDPACKAGECREATIONFACTORY_H
#include <projectexplorer/buildstep.h>
namespace Android {
namespace Internal {
class AndroidPackageCreationFactory : public ProjectExplorer::IBuildStepFactory
{
Q_OBJECT
public:
explicit AndroidPackageCreationFactory(QObject *parent = 0);
QList<Core::Id> availableCreationIds(ProjectExplorer::BuildStepList *parent) const;
QString displayNameForId(Core::Id id) const;
bool canCreate(ProjectExplorer::BuildStepList *parent, Core::Id id) const;
ProjectExplorer::BuildStep *create(ProjectExplorer::BuildStepList *parent, Core::Id id);
bool canRestore(ProjectExplorer::BuildStepList *parent,
const QVariantMap &map) const;
ProjectExplorer::BuildStep *restore(ProjectExplorer::BuildStepList *parent, const QVariantMap &map);
bool canClone(ProjectExplorer::BuildStepList *parent,
ProjectExplorer::BuildStep *product) const;
ProjectExplorer::BuildStep *clone(ProjectExplorer::BuildStepList *parent,
ProjectExplorer::BuildStep *product);
};
} // namespace Internal
} // namespace Android
#endif // ANDROIDPACKAGECREATIONFACTORY_H

View File

@@ -1,883 +0,0 @@
/**************************************************************************
**
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "androidpackagecreationstep.h"
#include "androidconstants.h"
#include "androiddeploystep.h"
#include "androidglobal.h"
#include "androidpackagecreationwidget.h"
#include "androidmanager.h"
#include "androidgdbserverkitinformation.h"
#include "androidtoolchain.h"
#include "certificatesmodel.h"
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/target.h>
#include <qmakeprojectmanager/qmakebuildconfiguration.h>
#include <qmakeprojectmanager/qmakeproject.h>
#include <qmakeprojectmanager/qmakenodes.h>
#include <qtsupport/qtkitinformation.h>
#include <coreplugin/icore.h>
#include <coreplugin/fileutils.h>
#include <QAbstractListModel>
#include <QProcess>
#include <QVector>
#include <QPair>
#include <QWidget>
#include <QMessageBox>
#include <QInputDialog>
#include <QMainWindow>
using namespace ProjectExplorer;
using namespace ProjectExplorer::Constants;
namespace Android {
namespace Internal {
namespace {
const QLatin1String KeystoreLocationKey("KeystoreLocation");
const QLatin1String SignPackageKey("SignPackage");
const QLatin1String AliasString("Alias name:");
const QLatin1String CertificateSeparator("*******************************************");
}
using namespace QmakeProjectManager;
AndroidPackageCreationStep::AndroidPackageCreationStep(BuildStepList *bsl)
: BuildStep(bsl, CreatePackageId)
{
ctor();
}
AndroidPackageCreationStep::AndroidPackageCreationStep(BuildStepList *bsl,
AndroidPackageCreationStep *other)
: BuildStep(bsl, other)
{
ctor();
}
void AndroidPackageCreationStep::ctor()
{
setDefaultDisplayName(tr("Packaging for Android"));
m_openPackageLocation = true;
m_bundleQt = false;
m_signPackage = false;
connect(&m_outputParser, SIGNAL(addTask(ProjectExplorer::Task)), this, SIGNAL(addTask(ProjectExplorer::Task)));
}
bool AndroidPackageCreationStep::init()
{
const QmakeBuildConfiguration *bc = qobject_cast<QmakeBuildConfiguration *>(target()->activeBuildConfiguration());
if (!bc) {
raiseError(tr("Cannot create Android package: current build configuration is not Qt 4."));
return false;
}
QmakeProject *project = static_cast<QmakeProject *>(target()->project());
m_outputParser.setProjectFileList(project->files(Project::AllFiles));
// Copying
m_androidDir = AndroidManager::dirPath(target());
Utils::FileName path = m_androidDir;
QString androidTargetArch = project->rootQmakeProjectNode()->singleVariableValue(QmakeProjectManager::AndroidArchVar);
if (androidTargetArch.isEmpty()) {
raiseError(tr("Cannot create Android package: No ANDROID_TARGET_ARCH set in make spec."));
return false;
}
Utils::FileName androidLibPath = path.appendPath(QLatin1String("libs/") + androidTargetArch);
m_gdbServerDestination = androidLibPath.appendPath(QLatin1String("gdbserver"));
m_gdbServerSource = AndroidGdbServerKitInformation::gdbServer(target()->kit());
if (!AndroidManager::createAndroidTemplatesIfNecessary(target()))
return false;
AndroidManager::updateTarget(target(), AndroidManager::buildTargetSDK(target()), AndroidManager::applicationName(target()));
m_antToolPath = AndroidConfigurations::currentConfig().antToolPath();
m_apkPathUnsigned = AndroidManager::apkPath(target(), AndroidManager::ReleaseBuildUnsigned);
m_apkPathSigned = AndroidManager::apkPath(target(), AndroidManager::ReleaseBuildSigned);
m_signPackageForRun = m_signPackage;
m_keystorePathForRun = m_keystorePath;
m_certificatePasswdForRun = m_certificatePasswd;
m_jarSigner = AndroidConfigurations::currentConfig().jarsignerPath();
m_zipAligner = AndroidConfigurations::currentConfig().zipalignPath();
m_environment = bc->environment();
ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(target()->kit());
if (tc->type() != QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE))
return false;
initCheckRequiredLibrariesForRun();
if (m_signPackage && (bc->qmakeBuildConfiguration() & QtSupport::BaseQtVersion::DebugBuild))
emit addOutput(tr("Warning: Signing a debug package."), BuildStep::ErrorMessageOutput);
return true;
}
void AndroidPackageCreationStep::run(QFutureInterface<bool> &fi)
{
fi.reportResult(createPackage());
}
BuildStepConfigWidget *AndroidPackageCreationStep::createConfigWidget()
{
return new AndroidPackageCreationWidget(this);
}
static inline QString msgCannotFindElfInformation()
{
return AndroidPackageCreationStep::tr("Cannot find ELF information");
}
static inline QString msgCannotFindExecutable(const QString &appPath)
{
return AndroidPackageCreationStep::tr("Cannot find \"%1\".\n"
"Please make sure your application is "
"built successfully and is selected in Application tab ('Run option').").arg(appPath);
}
static void parseSharedLibs(const QByteArray &buffer, QStringList *libs)
{
#if defined(_WIN32)
QList<QByteArray> lines = buffer.trimmed().split('\r');
#else
QList<QByteArray> lines = buffer.trimmed().split('\n');
#endif
foreach (const QByteArray &line, lines) {
if (line.contains("(NEEDED)") && line.contains("Shared library:") ) {
const int pos = line.lastIndexOf('[') + 1;
(*libs) << QString::fromLatin1(line.mid(pos, line.length() - pos - 1));
}
}
}
void markNeeded(const QString &library,
const QVector<AndroidManager::Library> &dependencies,
QMap<QString, bool> *neededMap)
{
if (!neededMap->contains(library))
return;
if (neededMap->value(library))
return;
neededMap->insert(library, true);
for (int i = 0; i < dependencies.size(); ++i) {
if (dependencies.at(i).name == library) {
foreach (const QString &dependency, dependencies.at(i).dependencies)
markNeeded(dependency, dependencies, neededMap);
break;
}
}
}
QStringList requiredLibraries(QVector<AndroidManager::Library> availableLibraries,
const QStringList &checkedLibs, const QStringList &dependencies)
{
QMap<QString, bool> neededLibraries;
QVector<AndroidManager::Library>::const_iterator it, end;
it = availableLibraries.constBegin();
end = availableLibraries.constEnd();
for (; it != end; ++it)
neededLibraries[(*it).name] = false;
// Checked items are always needed
foreach (const QString &lib, checkedLibs)
markNeeded(lib, availableLibraries, &neededLibraries);
foreach (const QString &lib, dependencies) {
if (lib.startsWith(QLatin1String("lib"))
&& lib.endsWith(QLatin1String(".so")))
markNeeded(lib.mid(3, lib.size() - 6), availableLibraries, &neededLibraries);
}
for (int i = availableLibraries.size() - 1; i>= 0; --i)
if (!neededLibraries.value(availableLibraries.at(i).name))
availableLibraries.remove(i);
QStringList requiredLibraries;
foreach (const AndroidManager::Library &lib, availableLibraries) {
if (neededLibraries.value(lib.name))
requiredLibraries << lib.name;
}
return requiredLibraries;
}
void AndroidPackageCreationStep::checkRequiredLibraries()
{
QProcess readelfProc;
QString appPath = AndroidManager::targetApplicationPath(target());
if (!QFile::exists(appPath)) {
raiseError(msgCannotFindElfInformation(), msgCannotFindExecutable(appPath));
return;
}
ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(target()->kit());
if (tc->type() != QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE))
return;
AndroidToolChain *atc = static_cast<AndroidToolChain *>(tc);
readelfProc.start(AndroidConfigurations::currentConfig().readelfPath(target()->activeRunConfiguration()->abi().architecture(), atc->ndkToolChainVersion()).toString(),
QStringList() << QLatin1String("-d") << QLatin1String("-W") << appPath);
if (!readelfProc.waitForFinished(-1)) {
readelfProc.kill();
return;
}
QStringList libs;
parseSharedLibs(readelfProc.readAll(), &libs);
AndroidManager::setQtLibs(target(), requiredLibraries(AndroidManager::availableQtLibsWithDependencies(target()),
AndroidManager::qtLibs(target()), libs));
emit updateRequiredLibrariesModels();
}
void AndroidPackageCreationStep::initCheckRequiredLibrariesForRun()
{
ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(target()->kit());
if (tc->type() != QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE))
return;
AndroidToolChain *atc = static_cast<AndroidToolChain *>(tc);
m_appPath = Utils::FileName::fromString(AndroidManager::targetApplicationPath(target()));
m_readElf = AndroidConfigurations::currentConfig().readelfPath(target()->activeRunConfiguration()->abi().architecture(),
atc->ndkToolChainVersion());
m_qtLibs = AndroidManager::qtLibs(target());
m_availableQtLibs = AndroidManager::availableQtLibsWithDependencies(target());
m_prebundledLibs = AndroidManager::prebundledLibs(target());
}
void AndroidPackageCreationStep::getBundleInformation()
{
m_bundleQt = AndroidManager::bundleQt(target());
if (m_bundleQt) {
m_bundledJars = AndroidManager::loadLocalJars(target()).split(QLatin1Char(':'),
QString::SkipEmptyParts);
m_otherBundledFiles = AndroidManager::loadLocalBundledFiles(target()).split(QLatin1Char(':'),
QString::SkipEmptyParts);
}
}
void AndroidPackageCreationStep::checkRequiredLibrariesForRun()
{
QProcess readelfProc;
if (!m_appPath.toFileInfo().exists()) {
raiseError(msgCannotFindElfInformation(), msgCannotFindExecutable(m_appPath.toUserOutput()));
return;
}
readelfProc.start(m_readElf.toString(), QStringList() << QLatin1String("-d") << QLatin1String("-W") << m_appPath.toUserOutput());
if (!readelfProc.waitForFinished(-1)) {
readelfProc.kill();
return;
}
QStringList libs;
parseSharedLibs(readelfProc.readAll(), &libs);
m_qtLibsWithDependencies = requiredLibraries(m_availableQtLibs, m_qtLibs, libs);
QMetaObject::invokeMethod(this, "setQtLibs",Qt::BlockingQueuedConnection,
Q_ARG(QStringList, m_qtLibsWithDependencies));
QMetaObject::invokeMethod(this, "getBundleInformation", Qt::BlockingQueuedConnection);
emit updateRequiredLibrariesModels();
}
void AndroidPackageCreationStep::setQtLibs(const QStringList &qtLibs)
{
AndroidManager::setQtLibs(target(), qtLibs);
}
void AndroidPackageCreationStep::setPrebundledLibs(const QStringList &prebundledLibs)
{
AndroidManager::setPrebundledLibs(target(), prebundledLibs);
}
Utils::FileName AndroidPackageCreationStep::keystorePath()
{
return m_keystorePath;
}
void AndroidPackageCreationStep::setKeystorePath(const Utils::FileName &path)
{
m_keystorePath = path;
m_certificatePasswd.clear();
m_keystorePasswd.clear();
}
void AndroidPackageCreationStep::setKeystorePassword(const QString &pwd)
{
m_keystorePasswd = pwd;
}
void AndroidPackageCreationStep::setCertificateAlias(const QString &alias)
{
m_certificateAlias = alias;
}
void AndroidPackageCreationStep::setCertificatePassword(const QString &pwd)
{
m_certificatePasswd = pwd;
}
void AndroidPackageCreationStep::setOpenPackageLocation(bool open)
{
m_openPackageLocation = open;
}
QAbstractItemModel *AndroidPackageCreationStep::keystoreCertificates()
{
QString rawCerts;
QProcess keytoolProc;
while (!rawCerts.length() || !m_keystorePasswd.length()) {
QStringList params;
params << QLatin1String("-list") << QLatin1String("-v") << QLatin1String("-keystore") << m_keystorePath.toUserOutput() << QLatin1String("-storepass");
if (!m_keystorePasswd.length())
keystorePassword();
if (!m_keystorePasswd.length())
return 0;
params << m_keystorePasswd;
params << QLatin1String("-J-Duser.language=en");
keytoolProc.start(AndroidConfigurations::currentConfig().keytoolPath().toString(), params);
if (!keytoolProc.waitForStarted() || !keytoolProc.waitForFinished()) {
QMessageBox::critical(0, tr("Error"),
tr("Failed to run keytool"));
return 0;
}
if (keytoolProc.exitCode()) {
QMessageBox::critical(0, tr("Error"),
tr("Invalid password"));
m_keystorePasswd.clear();
}
rawCerts = QString::fromLatin1(keytoolProc.readAllStandardOutput());
}
return new CertificatesModel(rawCerts, this);
}
bool AndroidPackageCreationStep::signPackage() const
{
return m_signPackage;
}
void AndroidPackageCreationStep::setSignPackage(bool b)
{
m_signPackage = b;
}
bool AndroidPackageCreationStep::fromMap(const QVariantMap &map)
{
if (!BuildStep::fromMap(map))
return false;
m_keystorePath = Utils::FileName::fromString(map.value(KeystoreLocationKey).toString());
m_signPackage = map.value(SignPackageKey).toBool();
return true;
}
QVariantMap AndroidPackageCreationStep::toMap() const
{
QVariantMap map(BuildStep::toMap());
map.insert(KeystoreLocationKey, m_keystorePath.toString());
map.insert(SignPackageKey, m_signPackage);
return map;
}
QStringList AndroidPackageCreationStep::collectRelativeFilePaths(const QString &parentPath)
{
QStringList relativeFilePaths;
QDirIterator libsIt(parentPath, QDir::NoFilter, QDirIterator::Subdirectories);
int pos = parentPath.size();
while (libsIt.hasNext()) {
libsIt.next();
if (!libsIt.fileInfo().isDir())
relativeFilePaths.append(libsIt.filePath().mid(pos));
}
return relativeFilePaths;
}
void AndroidPackageCreationStep::collectFiles(QList<DeployItem> *deployList,
QList<DeployItem> *pluginsAndImportsList)
{
Q_ASSERT(deployList != 0);
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit());
if (!version)
return;
QmakeProject *project = static_cast<QmakeProject *>(target()->project());
QString androidTargetArch = project->rootQmakeProjectNode()->singleVariableValue(QmakeProjectManager::AndroidArchVar);
QString androidAssetsPath = m_androidDir.toString() + QLatin1String("/assets/");
QString androidJarPath = m_androidDir.toString() + QLatin1String("/libs/");
QString androidLibPath = m_androidDir.toString() + QLatin1String("/libs/") + androidTargetArch;
QString qtVersionSourcePath = version->sourcePath().toString();
foreach (QString qtLib, m_qtLibsWithDependencies) {
QString fullPath = qtVersionSourcePath
+ QLatin1String("/lib/lib")
+ qtLib
+ QLatin1String(".so");
QString destinationPath = androidLibPath
+ QLatin1String("/lib")
+ qtLib
+ QLatin1String(".so");
// If the Qt lib/ folder contains libgnustl_shared.so, don't deploy it from there, since
// it will be deployed directly from the NDK instead.
if (qtLib != QLatin1String("gnustl_shared")) {
DeployItem deployItem(fullPath, 0, destinationPath, true);
deployList->append(deployItem);
}
}
if (!androidTargetArch.isEmpty()) {
ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(target()->kit());
if (tc->type() != QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE))
return;
AndroidToolChain *atc = static_cast<AndroidToolChain *>(tc);
QString libgnustl = AndroidManager::libGnuStl(androidTargetArch, atc->ndkToolChainVersion());
DeployItem deployItem(libgnustl, 0, androidLibPath + QLatin1String("/libgnustl_shared.so"), false);
deployList->append(deployItem);
}
foreach (QString jar, m_bundledJars) {
QString fullPath = qtVersionSourcePath + QLatin1Char('/') + jar;
QFileInfo fileInfo(fullPath);
if (fileInfo.exists()) {
QString destinationPath = androidJarPath
+ AndroidManager::libraryPrefix()
+ fileInfo.fileName();
deployList->append(DeployItem(fullPath, 0, destinationPath, true));
}
}
QSet<QString> alreadyListed;
foreach (QString bundledFile, m_otherBundledFiles) {
QStringList allFiles;
if (QFileInfo(qtVersionSourcePath + QLatin1Char('/') + bundledFile).isDir()) {
if (!bundledFile.endsWith(QLatin1Char('/')))
bundledFile.append(QLatin1Char('/'));
allFiles = collectRelativeFilePaths(qtVersionSourcePath + QLatin1Char('/') + bundledFile);
} else {
// If we need to bundle a specific file, we just add an empty string and the file
// names and data will be prepared correctly in the loop below.
allFiles = QStringList(QString());
}
foreach (QString file, allFiles) {
QString fullPath = qtVersionSourcePath + QLatin1Char('/') + bundledFile + file;
if (alreadyListed.contains(fullPath))
continue;
alreadyListed.insert(fullPath);
QString garbledFileName;
QString destinationPath;
bool shouldStrip = false;
QString fullFileName = bundledFile + file;
if (fullFileName.endsWith(QLatin1String(".so"))) {
if (fullFileName.startsWith(QLatin1String("lib/"))) {
// Special case when the destination folder is lib/
// Since this is also the source folder, there is no need to garble the file
// name and copy it. We also won't have write access to this folder, so we
// couldn't if we wanted to.
garbledFileName = fullFileName.mid(sizeof("lib/") - 1);
} else {
garbledFileName = QLatin1String("lib")
+ AndroidManager::libraryPrefix()
+ QString(fullFileName).replace(QLatin1Char('/'), QLatin1Char('_'));
}
destinationPath = androidLibPath + QLatin1Char('/') + garbledFileName;
shouldStrip = true;
} else {
garbledFileName = AndroidManager::libraryPrefix() + QLatin1Char('/') + fullFileName;
destinationPath = androidAssetsPath + garbledFileName;
}
deployList->append(DeployItem(fullPath, 0, destinationPath, shouldStrip));
pluginsAndImportsList->append(DeployItem(garbledFileName,
0,
fullFileName,
shouldStrip));
}
}
}
void AndroidPackageCreationStep::removeManagedFilesFromPackage(const Utils::FileName &qtLibraryDir)
{
// Clean up all files managed by Qt Creator
{
QString androidLibPath = m_androidDir.toString() + QLatin1String("/libs/");
QDirIterator dirIt(m_androidDir.toString(), QDirIterator::Subdirectories);
while (dirIt.hasNext()) {
dirIt.next();
if (!dirIt.fileInfo().isDir()) {
bool isQtLibrary = dirIt.fileInfo().path().startsWith(androidLibPath)
&& dirIt.fileName().startsWith(QLatin1String("libQt5"))
&& dirIt.fileName().endsWith(QLatin1String(".so"));
if (isQtLibrary) {
Utils::FileName qtLibraryFile = qtLibraryDir;
qtLibraryFile.appendPath(dirIt.fileName());
isQtLibrary = qtLibraryFile.toFileInfo().exists();
}
if (dirIt.filePath().contains(AndroidManager::libraryPrefix()) || isQtLibrary)
QFile::remove(dirIt.filePath());
}
}
}
removeDirectory(m_androidDir.toString() + QLatin1String("/assets/") + AndroidManager::libraryPrefix());
}
void AndroidPackageCreationStep::copyFilesIntoPackage(const QList<DeployItem> &deployList)
{
foreach (DeployItem item, deployList) {
QFileInfo info(item.remoteFileName);
if (info.exists())
QFile::remove(item.remoteFileName);
else
QDir().mkpath(info.absolutePath());
QFile::copy(item.localFileName, item.remoteFileName);
}
}
void AndroidPackageCreationStep::stripFiles(const QList<DeployItem> &deployList)
{
QStringList fileList;
foreach (DeployItem item, deployList)
if (item.needsStrip)
fileList.append(item.remoteFileName);
ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(target()->kit());
if (tc->type() != QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE))
return;
AndroidToolChain *atc = static_cast<AndroidToolChain *>(tc);
stripAndroidLibs(fileList,
target()->activeRunConfiguration()->abi().architecture(),
atc->ndkToolChainVersion());
}
void AndroidPackageCreationStep::updateXmlForFiles(const QStringList &inLibList,
const QStringList &inAssetsList)
{
AndroidManager::setBundledInLib(target(), inLibList);
AndroidManager::setBundledInAssets(target(), inAssetsList);
}
bool AndroidPackageCreationStep::createPackage()
{
checkRequiredLibrariesForRun();
emit addOutput(tr("Copy Qt app & libs to Android package ..."), MessageOutput);
QStringList build;
// build << QLatin1String("-silent"); //TODO depends on ant 1.9.0, enabled, not *now*
build << QLatin1String("clean");
QFile::remove(m_gdbServerDestination.toString());
if (m_signPackageForRun) {
build << QLatin1String("release");
} else {
build << QLatin1String("debug");
QDir dir;
dir.mkpath(m_gdbServerDestination.toFileInfo().absolutePath());
if (!QFile::copy(m_gdbServerSource.toString(), m_gdbServerDestination.toString())) {
raiseError(tr("Can't copy gdbserver from \"%1\" to \"%2\"").arg(m_gdbServerSource.toUserOutput())
.arg(m_gdbServerDestination.toUserOutput()));
return false;
}
}
QList<DeployItem> deployFiles;
QList<DeployItem> importsAndPlugins;
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit());
// Qt 5 supports bundling libraries inside the apk. We guard the code for Qt 5 to be sure we
// do not disrupt existing projects.
if (version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0)) {
bool bundleQt = AndroidManager::bundleQt(target());
// Collect the files to bundle in the package
if (bundleQt)
collectFiles(&deployFiles, &importsAndPlugins);
// Remove files from package if they are not needed
removeManagedFilesFromPackage(version->libraryPath());
// Deploy files to package
if (bundleQt) {
copyFilesIntoPackage(deployFiles);
stripFiles(deployFiles);
QStringList inLibList;
QStringList inAssetsList;
foreach (DeployItem deployItem, importsAndPlugins) {
QString conversionInfo = deployItem.localFileName
+ QLatin1Char(':')
+ deployItem.remoteFileName;
if (deployItem.localFileName.endsWith(QLatin1String(".so")))
inLibList.append(conversionInfo);
else
inAssetsList.append(conversionInfo);
}
QMetaObject::invokeMethod(this,
"updateXmlForFiles",
Qt::BlockingQueuedConnection,
Q_ARG(QStringList, inLibList),
Q_ARG(QStringList, inAssetsList));
}
}
emit addOutput(tr("Creating package file ..."), MessageOutput);
QProcess *const buildProc = new QProcess;
buildProc->setProcessEnvironment(m_environment.toProcessEnvironment());
connect(buildProc, SIGNAL(readyReadStandardOutput()), this,
SLOT(handleBuildStdOutOutput()), Qt::DirectConnection);
connect(buildProc, SIGNAL(readyReadStandardError()), this,
SLOT(handleBuildStdErrOutput()), Qt::DirectConnection);
buildProc->setWorkingDirectory(m_androidDir.toString());
if (!runCommand(buildProc, m_antToolPath.toString(), build)) {
disconnect(buildProc, 0, this, 0);
buildProc->deleteLater();
return false;
}
if (m_signPackageForRun) {
emit addOutput(tr("Signing package ..."), MessageOutput);
while (true) {
if (m_certificatePasswdForRun.isEmpty())
QMetaObject::invokeMethod(this, "certificatePassword", Qt::BlockingQueuedConnection);
if (m_certificatePasswdForRun.isEmpty()) {
disconnect(buildProc, 0, this, 0);
buildProc->deleteLater();
return false;
}
QByteArray keyPass = m_certificatePasswdForRun.toUtf8();
build.clear();
build << QLatin1String("-verbose") << QLatin1String("-digestalg") << QLatin1String("SHA1")
<< QLatin1String("-sigalg") << QLatin1String("MD5withRSA")
<< QLatin1String("-keystore") << m_keystorePathForRun.toUserOutput()
<< QLatin1String("-storepass") << m_keystorePasswd
<< m_apkPathUnsigned.toUserOutput()
<< m_certificateAlias;
buildProc->start(m_jarSigner.toString(), build);
if (!buildProc->waitForStarted()) {
disconnect(buildProc, 0, this, 0);
buildProc->deleteLater();
return false;
}
keyPass += '\n';
buildProc->write(keyPass);
buildProc->waitForBytesWritten();
buildProc->waitForFinished();
if (!buildProc->exitCode())
break;
emit addOutput(tr("Failed, try again"), ErrorMessageOutput);
m_certificatePasswdForRun.clear();
}
build.clear();
build << QLatin1String("-f") << QLatin1String("-v") << QLatin1String("4") << m_apkPathUnsigned.toString() << m_apkPathSigned.toString();
buildProc->start(m_zipAligner.toString(), build);
buildProc->waitForFinished();
if (!buildProc->exitCode()) {
QFile::remove(m_apkPathUnsigned.toString());
emit addOutput(tr("Release signed package created to %1")
.arg(m_apkPathSigned.toUserOutput())
, MessageOutput);
if (m_openPackageLocation)
QMetaObject::invokeMethod(this, "showInGraphicalShell", Qt::QueuedConnection);
}
}
emit addOutput(tr("Package created."), BuildStep::MessageOutput);
disconnect(buildProc, 0, this, 0);
buildProc->deleteLater();
return true;
}
void AndroidPackageCreationStep::stripAndroidLibs(const QStringList & files, Abi::Architecture architecture, const QString &ndkToolchainVersion)
{
QProcess stripProcess;
foreach (const QString &file, files) {
stripProcess.start(AndroidConfigurations::currentConfig().stripPath(architecture, ndkToolchainVersion).toString(),
QStringList()<<QLatin1String("--strip-unneeded") << file);
stripProcess.waitForStarted();
if (!stripProcess.waitForFinished())
stripProcess.kill();
}
}
bool AndroidPackageCreationStep::removeDirectory(const QString &dirPath)
{
QDir dir(dirPath);
if (!dir.exists())
return true;
const QStringList &files
= dir.entryList(QDir::Files | QDir::Hidden | QDir::System);
foreach (const QString &fileName, files) {
if (!dir.remove(fileName))
return false;
}
const QStringList &subDirs
= dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
foreach (const QString &subDirName, subDirs) {
if (!removeDirectory(dirPath + QLatin1Char('/') + subDirName))
return false;
}
return dir.rmdir(dirPath);
}
bool AndroidPackageCreationStep::runCommand(QProcess *buildProc
, const QString &program, const QStringList &arguments)
{
emit addOutput(tr("Package deploy: Running command '%1 %2'.").arg(program).arg(arguments.join(QLatin1String(" "))), BuildStep::MessageOutput);
buildProc->start(program, arguments);
if (!buildProc->waitForStarted()) {
raiseError(tr("Packaging failed."),
tr("Packaging error: Could not start command '%1 %2'. Reason: %3")
.arg(program).arg(arguments.join(QLatin1String(" "))).arg(buildProc->errorString()));
return false;
}
buildProc->waitForFinished(-1);
handleProcessOutput(buildProc, false);
handleProcessOutput(buildProc, true);
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 += QLatin1Char(' ') + tr("Reason: %1").arg(buildProc->errorString());
else
mainMessage += tr("Exit code: %1").arg(buildProc->exitCode());
raiseError(mainMessage);
return false;
}
return true;
}
void AndroidPackageCreationStep::handleBuildStdOutOutput()
{
QProcess *const process = qobject_cast<QProcess *>(sender());
if (!process)
return;
handleProcessOutput(process, false);
}
void AndroidPackageCreationStep::handleBuildStdErrOutput()
{
QProcess *const process = qobject_cast<QProcess *>(sender());
if (!process)
return;
handleProcessOutput(process, true);
}
void AndroidPackageCreationStep::handleProcessOutput(QProcess *process, bool stdErr)
{
process->setReadChannel(stdErr ? QProcess::StandardError : QProcess::StandardOutput);
while (process->canReadLine()) {
QString line = QString::fromLocal8Bit(process->readLine());
if (stdErr)
m_outputParser.stdError(line);
else
m_outputParser.stdOutput(line);
emit addOutput(line, stdErr ? BuildStep::ErrorOutput
: BuildStep::NormalOutput,
BuildStep::DontAppendNewline);
}
}
void AndroidPackageCreationStep::keystorePassword()
{
m_keystorePasswd.clear();
bool ok;
QString text = QInputDialog::getText(0, tr("Keystore"),
tr("Keystore password:"), QLineEdit::Password,
QString(), &ok);
if (ok && !text.isEmpty())
m_keystorePasswd = text;
}
void AndroidPackageCreationStep::certificatePassword()
{
m_certificatePasswdForRun.clear();
bool ok;
QString text = QInputDialog::getText(0, tr("Certificate"),
tr("Certificate password (%1):").arg(m_certificateAlias), QLineEdit::Password,
QString(), &ok);
if (ok && !text.isEmpty())
m_certificatePasswdForRun = text;
}
void AndroidPackageCreationStep::showInGraphicalShell()
{
Core::FileUtils::showInGraphicalShell(Core::ICore::mainWindow(), m_apkPathSigned.toString());
}
void AndroidPackageCreationStep::raiseError(const QString &shortMsg,
const QString &detailedMsg)
{
emit addOutput(detailedMsg.isNull() ? shortMsg : detailedMsg, BuildStep::ErrorOutput);
emit addTask(Task(Task::Error, shortMsg, Utils::FileName::fromString(QString()), -1,
TASK_CATEGORY_DEPLOYMENT));
}
const Core::Id AndroidPackageCreationStep::CreatePackageId("Qt4ProjectManager.AndroidPackageCreationStep");
} // namespace Internal
} // namespace Android

View File

@@ -1,156 +0,0 @@
/**************************************************************************
**
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef ANDROIDPACKAGECREATIONSTEP_H
#define ANDROIDPACKAGECREATIONSTEP_H
#include "javaparser.h"
#include "androidmanager.h"
#include <projectexplorer/abi.h>
#include <projectexplorer/buildstep.h>
#include <utils/environment.h>
#include <QAbstractItemModel>
QT_BEGIN_NAMESPACE
class QProcess;
QT_END_NAMESPACE
namespace Android {
namespace Internal {
class DeployItem;
class AndroidPackageCreationStep : public ProjectExplorer::BuildStep
{
Q_OBJECT
friend class AndroidPackageCreationFactory;
public:
AndroidPackageCreationStep(ProjectExplorer::BuildStepList *bsl);
static bool removeDirectory(const QString &dirPath);
static void stripAndroidLibs(const QStringList &files, ProjectExplorer::Abi::Architecture architecture, const QString &ndkToolchainVersion);
static const QLatin1String DefaultVersionNumber;
void checkRequiredLibraries();
void initCheckRequiredLibrariesForRun();
void checkRequiredLibrariesForRun();
Utils::FileName keystorePath();
void setKeystorePath(const Utils::FileName &path);
void setKeystorePassword(const QString &pwd);
void setCertificateAlias(const QString &alias);
void setCertificatePassword(const QString &pwd);
void setOpenPackageLocation(bool open);
QAbstractItemModel *keystoreCertificates();
bool signPackage() const;
void setSignPackage(bool b);
protected:
bool fromMap(const QVariantMap &map);
QVariantMap toMap() const;
private slots:
void handleBuildStdOutOutput();
void handleBuildStdErrOutput();
void keystorePassword();
void certificatePassword();
void showInGraphicalShell();
void setQtLibs(const QStringList &qtLibs);
void setPrebundledLibs(const QStringList &prebundledLibs);
void updateXmlForFiles(const QStringList &inLibList, const QStringList &inAssetsList);
void getBundleInformation();
signals:
void updateRequiredLibrariesModels();
private:
AndroidPackageCreationStep(ProjectExplorer::BuildStepList *buildConfig,
AndroidPackageCreationStep *other);
void ctor();
virtual bool init();
virtual void run(QFutureInterface<bool> &fi);
virtual ProjectExplorer::BuildStepConfigWidget *createConfigWidget();
virtual bool immutable() const { return true; }
bool createPackage();
bool runCommand(QProcess *buildProc, const QString &program, const QStringList &arguments);
void raiseError(const QString &shortMsg,
const QString &detailedMsg = QString());
QStringList collectRelativeFilePaths(const QString &parentPath);
void collectFiles(QList<DeployItem> *deployList, QList<DeployItem> *pluginsAndImports);
void removeManagedFilesFromPackage(const Utils::FileName &qtLibraryDir);
void copyFilesIntoPackage(const QList<DeployItem> &deployList);
void stripFiles(const QList<DeployItem> &deployList);
static const Core::Id CreatePackageId;
private:
void handleProcessOutput(QProcess *process, bool stdErr);
bool m_signPackage;
Utils::FileName m_keystorePath;
QString m_keystorePasswd;
QString m_certificateAlias;
QString m_certificatePasswd;
bool m_openPackageLocation;
JavaParser m_outputParser;
// members to pass data from init() to run()
Utils::FileName m_androidDir;
Utils::FileName m_gdbServerSource;
Utils::FileName m_gdbServerDestination;
Utils::FileName m_antToolPath;
Utils::FileName m_apkPathUnsigned;
Utils::FileName m_apkPathSigned;
bool m_signPackageForRun;
Utils::FileName m_keystorePathForRun;
QString m_certificatePasswdForRun;
Utils::FileName m_jarSigner;
Utils::FileName m_zipAligner;
// more for checkLibraries
Utils::FileName m_appPath;
Utils::FileName m_readElf;
QStringList m_qtLibs;
QStringList m_qtLibsWithDependencies;
QVector<AndroidManager::Library> m_availableQtLibs;
QStringList m_prebundledLibs;
QStringList m_bundledJars;
QStringList m_otherBundledFiles;
bool m_bundleQt;
Utils::Environment m_environment;
};
} // namespace Internal
} // namespace Android
#endif // ANDROIDPACKAGECREATIONSTEP_H

View File

@@ -1,394 +0,0 @@
/**************************************************************************
**
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "androidpackagecreationwidget.h"
#include "androidpackagecreationstep.h"
#include "androidconfigurations.h"
#include "androidcreatekeystorecertificate.h"
#include "androidmanager.h"
#include "androiddeploystep.h"
#include "androidglobal.h"
#include "ui_androidpackagecreationwidget.h"
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <qmakeprojectmanager/qmakebuildconfiguration.h>
#include <qmakeprojectmanager/qmakestep.h>
#include <utils/pathchooser.h>
#include <QTimer>
#include <QFileDialog>
#include <QFileSystemWatcher>
#include <QMessageBox>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
namespace Android {
namespace Internal {
using namespace ProjectExplorer;
using namespace QmakeProjectManager;
///////////////////////////// CheckModel /////////////////////////////
CheckModel::CheckModel(QObject *parent)
: QAbstractListModel(parent)
{
}
void CheckModel::setAvailableItems(const QStringList &items)
{
beginResetModel();
m_availableItems = items;
endResetModel();
}
void CheckModel::setCheckedItems(const QStringList &items)
{
m_checkedItems = items;
if (rowCount())
emit dataChanged(index(0), index(rowCount()-1));
}
const QStringList &CheckModel::checkedItems()
{
return m_checkedItems;
}
QVariant CheckModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
switch (role) {
case Qt::CheckStateRole:
return m_checkedItems.contains(m_availableItems.at(index.row())) ? Qt::Checked : Qt::Unchecked;
case Qt::DisplayRole:
return m_availableItems.at(index.row());
}
return QVariant();
}
void CheckModel::moveUp(int index)
{
beginMoveRows(QModelIndex(), index, index, QModelIndex(), index - 1);
const QString &item1 = m_availableItems[index];
const QString &item2 = m_availableItems[index - 1];
m_availableItems.swap(index, index - 1);
index = m_checkedItems.indexOf(item1);
int index2 = m_checkedItems.indexOf(item2);
if (index > -1 && index2 > -1)
m_checkedItems.swap(index, index2);
endMoveRows();
}
bool CheckModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role != Qt::CheckStateRole || !index.isValid())
return false;
if (value.toInt() == Qt::Checked)
m_checkedItems.append(m_availableItems.at(index.row()));
else
m_checkedItems.removeAll(m_availableItems.at(index.row()));
emit dataChanged(index, index);
return true;
}
int CheckModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return m_availableItems.count();
}
Qt::ItemFlags CheckModel::flags(const QModelIndex &/*index*/) const
{
return Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled;
}
///////////////////////////// AndroidPackageCreationWidget /////////////////////////////
AndroidPackageCreationWidget::AndroidPackageCreationWidget(AndroidPackageCreationStep *step)
: ProjectExplorer::BuildStepConfigWidget(),
m_step(step),
m_ui(new Ui::AndroidPackageCreationWidget),
m_fileSystemWatcher(new QFileSystemWatcher(this)),
m_currentBuildConfiguration(0)
{
m_qtLibsModel = new CheckModel(this);
m_prebundledLibs = new CheckModel(this);
m_ui->setupUi(this);
m_ui->KeystoreLocationPushButton->setText(Utils::PathChooser::browseButtonLabel());
m_ui->signingDebugWarningIcon->hide();
m_ui->signingDebugWarningLabel->hide();
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QTimer::singleShot(50, this, SLOT(initGui()));
connect(m_step, SIGNAL(updateRequiredLibrariesModels()), SLOT(updateRequiredLibrariesModels()));
}
void AndroidPackageCreationWidget::initGui()
{
updateAndroidProjectInfo();
ProjectExplorer::Target *target = m_step->target();
m_fileSystemWatcher->addPath(AndroidManager::dirPath(target).toString());
m_fileSystemWatcher->addPath(AndroidManager::manifestPath(target).toString());
m_fileSystemWatcher->addPath(AndroidManager::srcPath(target).toString());
connect(m_fileSystemWatcher, SIGNAL(directoryChanged(QString)),
this, SLOT(updateAndroidProjectInfo()));
connect(m_fileSystemWatcher, SIGNAL(fileChanged(QString)), this,
SLOT(updateAndroidProjectInfo()));
connect(m_ui->targetSDKComboBox, SIGNAL(activated(QString)), SLOT(setTargetSDK(QString)));
connect(m_qtLibsModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(setQtLibs(QModelIndex,QModelIndex)));
connect(m_prebundledLibs, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(setPrebundledLibs(QModelIndex,QModelIndex)));
connect(m_ui->prebundledLibsListView, SIGNAL(activated(QModelIndex)), SLOT(prebundledLibSelected(QModelIndex)));
connect(m_ui->prebundledLibsListView, SIGNAL(clicked(QModelIndex)), SLOT(prebundledLibSelected(QModelIndex)));
connect(m_ui->upPushButton, SIGNAL(clicked()), SLOT(prebundledLibMoveUp()));
connect(m_ui->downPushButton, SIGNAL(clicked()), SLOT(prebundledLibMoveDown()));
connect(m_ui->readInfoPushButton, SIGNAL(clicked()), SLOT(readElfInfo()));
m_ui->qtLibsListView->setModel(m_qtLibsModel);
m_ui->prebundledLibsListView->setModel(m_prebundledLibs);
m_ui->KeystoreLocationLineEdit->setText(m_step->keystorePath().toUserOutput());
// Make the buildconfiguration emit a evironmentChanged() signal
// TODO find a better way
QmakeBuildConfiguration *bc = qobject_cast<QmakeBuildConfiguration *>(m_step->target()->activeBuildConfiguration());
if (!bc)
return;
bool use = bc->useSystemEnvironment();
bc->setUseSystemEnvironment(!use);
bc->setUseSystemEnvironment(use);
activeBuildConfigurationChanged();
connect(m_step->target(), SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)),
this, SLOT(activeBuildConfigurationChanged()));
}
void AndroidPackageCreationWidget::updateSigningWarning()
{
QmakeBuildConfiguration *bc = qobject_cast<QmakeBuildConfiguration *>(m_step->target()->activeBuildConfiguration());
bool debug = bc && (bc->qmakeBuildConfiguration() & QtSupport::BaseQtVersion::DebugBuild);
if (m_step->signPackage() && debug) {
m_ui->signingDebugWarningIcon->setVisible(true);
m_ui->signingDebugWarningLabel->setVisible(true);
} else {
m_ui->signingDebugWarningIcon->setVisible(false);
m_ui->signingDebugWarningLabel->setVisible(false);
}
}
void AndroidPackageCreationWidget::activeBuildConfigurationChanged()
{
if (m_currentBuildConfiguration)
disconnect(m_currentBuildConfiguration, SIGNAL(qmakeBuildConfigurationChanged()),
this, SLOT(updateSigningWarning()));
updateSigningWarning();
QmakeBuildConfiguration *bc = qobject_cast<QmakeBuildConfiguration *>(m_step->target()->activeBuildConfiguration());
m_currentBuildConfiguration = bc;
if (bc)
connect(bc, SIGNAL(qmakeBuildConfigurationChanged()), this, SLOT(updateSigningWarning()));
m_currentBuildConfiguration = bc;
}
void AndroidPackageCreationWidget::updateAndroidProjectInfo()
{
ProjectExplorer::Target *target = m_step->target();
m_ui->targetSDKComboBox->clear();
int minApiLevel = 4;
if (QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target->kit()))
if (qt->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0))
minApiLevel = 9;
QStringList targets = AndroidConfig::apiLevelNamesFor(AndroidConfigurations::currentConfig().sdkTargets(minApiLevel));
m_ui->targetSDKComboBox->addItems(targets);
m_ui->targetSDKComboBox->setCurrentIndex(targets.indexOf(AndroidManager::buildTargetSDK(target)));
m_qtLibsModel->setAvailableItems(AndroidManager::availableQtLibs(target));
m_qtLibsModel->setCheckedItems(AndroidManager::qtLibs(target));
m_prebundledLibs->setAvailableItems(AndroidManager::availablePrebundledLibs(target));
m_prebundledLibs->setCheckedItems(AndroidManager::prebundledLibs(target));
}
void AndroidPackageCreationWidget::setTargetSDK(const QString &sdk)
{
AndroidManager::setBuildTargetSDK(m_step->target(), sdk);
QmakeBuildConfiguration *bc = qobject_cast<QmakeBuildConfiguration *>(m_step->target()->activeBuildConfiguration());
if (!bc)
return;
QMakeStep *qs = bc->qmakeStep();
if (!qs)
return;
qs->setForced(true);
BuildManager::buildList(bc->stepList(ProjectExplorer::Constants::BUILDSTEPS_CLEAN),
ProjectExplorerPlugin::displayNameForStepId(ProjectExplorer::Constants::BUILDSTEPS_CLEAN));
BuildManager::appendStep(qs, ProjectExplorerPlugin::displayNameForStepId(ProjectExplorer::Constants::BUILDSTEPS_CLEAN));
bc->setSubNodeBuild(0);
// Make the buildconfiguration emit a evironmentChanged() signal
// TODO find a better way
bool use = bc->useSystemEnvironment();
bc->setUseSystemEnvironment(!use);
bc->setUseSystemEnvironment(use);
}
void AndroidPackageCreationWidget::setQtLibs(QModelIndex, QModelIndex)
{
AndroidManager::setQtLibs(m_step->target(), m_qtLibsModel->checkedItems());
AndroidDeployStep * const deployStep = AndroidGlobal::buildStep<AndroidDeployStep>(m_step->target()->activeDeployConfiguration());
if (deployStep->deployAction() == AndroidDeployStep::DeployLocal
|| deployStep->deployAction() == AndroidDeployStep::BundleLibraries)
AndroidManager::updateDeploymentSettings(m_step->target());
}
void AndroidPackageCreationWidget::setPrebundledLibs(QModelIndex, QModelIndex)
{
AndroidManager::setPrebundledLibs(m_step->target(), m_prebundledLibs->checkedItems());
AndroidDeployStep * const deployStep = AndroidGlobal::buildStep<AndroidDeployStep>(m_step->target()->activeDeployConfiguration());
if (deployStep->deployAction() == AndroidDeployStep::DeployLocal
|| deployStep->deployAction() == AndroidDeployStep::BundleLibraries)
AndroidManager::updateDeploymentSettings(m_step->target());
}
void AndroidPackageCreationWidget::prebundledLibSelected(const QModelIndex &index)
{
m_ui->upPushButton->setEnabled(false);
m_ui->downPushButton->setEnabled(false);
if (!index.isValid())
return;
if (index.row() > 0)
m_ui->upPushButton->setEnabled(true);
if (index.row() < m_prebundledLibs->rowCount(QModelIndex()) - 1)
m_ui->downPushButton->setEnabled(true);
}
void AndroidPackageCreationWidget::prebundledLibMoveUp()
{
const QModelIndex &index = m_ui->prebundledLibsListView->currentIndex();
if (index.isValid())
m_prebundledLibs->moveUp(index.row());
}
void AndroidPackageCreationWidget::prebundledLibMoveDown()
{
const QModelIndex &index = m_ui->prebundledLibsListView->currentIndex();
if (index.isValid())
m_prebundledLibs->moveUp(index.row() + 1);
}
void AndroidPackageCreationWidget::updateRequiredLibrariesModels()
{
m_qtLibsModel->setCheckedItems(AndroidManager::qtLibs(m_step->target()));
m_prebundledLibs->setCheckedItems(AndroidManager::prebundledLibs(m_step->target()));
}
void AndroidPackageCreationWidget::readElfInfo()
{
m_step->checkRequiredLibraries();
}
QString AndroidPackageCreationWidget::summaryText() const
{
return tr("<b>Package configurations</b>");
}
QString AndroidPackageCreationWidget::displayName() const
{
return m_step->displayName();
}
void AndroidPackageCreationWidget::setCertificates()
{
QAbstractItemModel *certificates = m_step->keystoreCertificates();
m_ui->signPackageCheckBox->setChecked(certificates);
m_ui->certificatesAliasComboBox->setModel(certificates);
}
void AndroidPackageCreationWidget::on_signPackageCheckBox_toggled(bool checked)
{
m_step->setSignPackage(checked);
updateSigningWarning();
if (!checked)
return;
if (!m_step->keystorePath().isEmpty())
setCertificates();
}
void AndroidPackageCreationWidget::on_KeystoreCreatePushButton_clicked()
{
AndroidCreateKeystoreCertificate d;
if (d.exec() != QDialog::Accepted)
return;
m_ui->KeystoreLocationLineEdit->setText(d.keystoreFilePath().toUserOutput());
m_step->setKeystorePath(d.keystoreFilePath());
m_step->setKeystorePassword(d.keystorePassword());
m_step->setCertificateAlias(d.certificateAlias());
m_step->setCertificatePassword(d.certificatePassword());
setCertificates();
}
void AndroidPackageCreationWidget::on_KeystoreLocationPushButton_clicked()
{
Utils::FileName keystorePath = m_step->keystorePath();
if (keystorePath.isEmpty())
keystorePath = Utils::FileName::fromString(QDir::homePath());
Utils::FileName file = Utils::FileName::fromString(QFileDialog::getOpenFileName(this, tr("Select keystore file"), keystorePath.toString(), tr("Keystore files (*.keystore *.jks)")));
if (file.isEmpty())
return;
m_ui->KeystoreLocationLineEdit->setText(file.toUserOutput());
m_step->setKeystorePath(file);
m_ui->signPackageCheckBox->setChecked(false);
}
void AndroidPackageCreationWidget::on_certificatesAliasComboBox_activated(const QString &alias)
{
if (alias.length())
m_step->setCertificateAlias(alias);
}
void AndroidPackageCreationWidget::on_certificatesAliasComboBox_currentIndexChanged(const QString &alias)
{
if (alias.length())
m_step->setCertificateAlias(alias);
}
void AndroidPackageCreationWidget::on_openPackageLocationCheckBox_toggled(bool checked)
{
m_step->setOpenPackageLocation(checked);
}
} // namespace Internal
} // namespace Android

View File

@@ -1,121 +0,0 @@
/**************************************************************************
**
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, 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, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef ANDROIDPACKAGECREATIONWIDGET_H
#define ANDROIDPACKAGECREATIONWIDGET_H
#include <projectexplorer/buildstep.h>
#include <QAbstractListModel>
#include <QStringList>
QT_BEGIN_NAMESPACE
class QFileSystemWatcher;
namespace Ui { class AndroidPackageCreationWidget; }
QT_END_NAMESPACE
namespace QmakeProjectManager { class QmakeBuildConfiguration; }
namespace Android {
namespace Internal {
class AndroidPackageCreationStep;
class CheckModel: public QAbstractListModel
{
Q_OBJECT
public:
CheckModel(QObject *parent = 0);
void setAvailableItems(const QStringList &items);
void setCheckedItems(const QStringList &items);
const QStringList &checkedItems();
QVariant data(const QModelIndex &index, int role) const;
void moveUp(int index);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
protected:
bool setData(const QModelIndex &index, const QVariant &value, int role);
Qt::ItemFlags flags(const QModelIndex &index) const;
private:
QStringList m_availableItems;
QStringList m_checkedItems;
};
class AndroidPackageCreationWidget : public ProjectExplorer::BuildStepConfigWidget
{
Q_OBJECT
public:
AndroidPackageCreationWidget(AndroidPackageCreationStep *step);
virtual QString summaryText() const;
virtual QString displayName() const;
public slots:
void readElfInfo();
private:
void setEnabledSaveDiscardButtons(bool enabled);
void setCertificates();
private slots:
void initGui();
void updateAndroidProjectInfo();
void setTargetSDK(const QString &sdk);
void setQtLibs(QModelIndex, QModelIndex);
void setPrebundledLibs(QModelIndex, QModelIndex);
void prebundledLibSelected(const QModelIndex &index);
void prebundledLibMoveUp();
void prebundledLibMoveDown();
void updateRequiredLibrariesModels();
void on_signPackageCheckBox_toggled(bool checked);
void on_KeystoreCreatePushButton_clicked();
void on_KeystoreLocationPushButton_clicked();
void on_certificatesAliasComboBox_activated(const QString &alias);
void on_certificatesAliasComboBox_currentIndexChanged(const QString &alias);
void on_openPackageLocationCheckBox_toggled(bool checked);
void updateSigningWarning();
void activeBuildConfigurationChanged();
private:
AndroidPackageCreationStep *const m_step;
Ui::AndroidPackageCreationWidget *const m_ui;
CheckModel *m_qtLibsModel;
CheckModel *m_prebundledLibs;
QFileSystemWatcher *m_fileSystemWatcher;
QmakeProjectManager::QmakeBuildConfiguration *m_currentBuildConfiguration;
};
} // namespace Internal
} // namespace Android
#endif // ANDROIDPACKAGECREATIONWIDGET_H

View File

@@ -1,323 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AndroidPackageCreationWidget</class>
<widget class="QWidget" name="AndroidPackageCreationWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>688</width>
<height>553</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Application</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="editDebianFileLabel_4">
<property name="text">
<string>&lt;b&gt;Android target SDK:&lt;/b&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="targetSDKComboBox"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="librariesGroupBox">
<property name="title">
<string>Libraries</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" colspan="2">
<widget class="QPushButton" name="readInfoPushButton">
<property name="toolTip">
<string>Automatically check required Qt libraries from compiled application.</string>
</property>
<property name="text">
<string>Read information from application (must be compiled)</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Required Qt libraries</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="qtLibsListView"/>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>&lt;center&gt;Prebundled libraries&lt;/center&gt;
&lt;p align=&quot;justify&quot;&gt;Please be aware that the order is very important: If library &lt;i&gt;A&lt;/i&gt; depends on library &lt;i&gt;B&lt;/i&gt;, &lt;i&gt;B&lt;/i&gt; &lt;b&gt;must&lt;/b&gt; go before &lt;i&gt;A&lt;/i&gt;.&lt;/p&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QListView" name="prebundledLibsListView"/>
</item>
<item row="1" column="1">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="upPushButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Up</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="downPushButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Down</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Sign package</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="KeystoreLocationLabel">
<property name="text">
<string>Keystore:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="KeystoreLocationLineEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="KeystoreCreatePushButton">
<property name="text">
<string>Create</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="KeystoreLocationPushButton">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="signPackageCheckBox">
<property name="text">
<string>Sign package</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="openPackageLocationCheckBox">
<property name="text">
<string>Open package location after is complete</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="signingDebugWarningIcon">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../coreplugin/core.qrc">:/core/images/warning.png</pixmap>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="signingDebugWarningLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Signing a debug package</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="KeystoreLocationLabel_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Certificate alias:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="certificatesAliasComboBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../projectexplorer/projectexplorer.qrc"/>
</resources>
<connections>
<connection>
<sender>signPackageCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>certificatesAliasComboBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>138</x>
<y>93</y>
</hint>
<hint type="destinationlabel">
<x>184</x>
<y>139</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>addFile()</slot>
<slot>removeFile()</slot>
<slot>handleSkipButtonToggled(bool)</slot>
<slot>versionInfoChanged()</slot>
<slot>editDebianFile()</slot>
<slot>setPackageManagerIcon()</slot>
</slots>
</ui>

View File

@@ -31,12 +31,10 @@
#include "androidconstants.h"
#include "androidconfigurations.h"
#include "androiddeploystepfactory.h"
#include "androiddeployqtstep.h"
#include "androiddevice.h"
#include "androiddevicefactory.h"
#include "androidmanager.h"
#include "androidpackagecreationfactory.h"
#include "androidpackageinstallationfactory.h"
#include "androidrunfactories.h"
#include "androidsettingspage.h"
@@ -77,8 +75,6 @@ bool AndroidPlugin::initialize(const QStringList &arguments, QString *errorMessa
addAutoReleasedObject(new Internal::AndroidRunControlFactory);
addAutoReleasedObject(new Internal::AndroidRunConfigurationFactory);
addAutoReleasedObject(new Internal::AndroidPackageInstallationFactory);
addAutoReleasedObject(new Internal::AndroidPackageCreationFactory);
addAutoReleasedObject(new Internal::AndroidDeployStepFactory);
addAutoReleasedObject(new Internal::AndroidDeployQtStepFactory);
addAutoReleasedObject(new Internal::AndroidSettingsPage);
addAutoReleasedObject(new Internal::AndroidQtVersionFactory);

View File

@@ -28,7 +28,6 @@
****************************************************************************/
#include "androidrunconfiguration.h"
#include "androiddeploystep.h"
#include "androidglobal.h"
#include "androidtoolchain.h"
#include "androidmanager.h"

View File

@@ -29,7 +29,6 @@
#include "androidruncontrol.h"
#include "androiddeploystep.h"
#include "androidglobal.h"
#include "androidrunconfiguration.h"
#include "androidrunner.h"

View File

@@ -29,7 +29,6 @@
#include "androidrunner.h"
#include "androiddeploystep.h"
#include "androiddeployqtstep.h"
#include "androidconfigurations.h"
#include "androidglobal.h"