forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.7'
Conflicts: qbs/modules/qtc/qtc.qbs qtcreator.pri src/plugins/android/androiddebugsupport.cpp Change-Id: I01c4880850ad25432a65bb32849365d2aeb0756f
This commit is contained in:
@@ -416,6 +416,17 @@ FileName AndroidConfig::avdManagerToolPath() const
|
||||
return avdManagerPath;
|
||||
}
|
||||
|
||||
FileName AndroidConfig::aaptToolPath() const
|
||||
{
|
||||
Utils::FileName aaptToolPath = m_sdkLocation;
|
||||
aaptToolPath.appendPath("build-tools");
|
||||
QString toolPath = QString("%1/aapt").arg(buildToolsVersion().toString());
|
||||
if (HostOsInfo::isWindowsHost())
|
||||
toolPath += ANDROID_BAT_SUFFIX;
|
||||
aaptToolPath.appendPath(toolPath);
|
||||
return aaptToolPath;
|
||||
}
|
||||
|
||||
FileName AndroidConfig::gccPath(const Abi &abi, Core::Id lang,
|
||||
const QString &ndkToolChainVersion) const
|
||||
{
|
||||
|
||||
@@ -132,6 +132,7 @@ public:
|
||||
Utils::FileName emulatorToolPath() const;
|
||||
Utils::FileName sdkManagerToolPath() const;
|
||||
Utils::FileName avdManagerToolPath() const;
|
||||
Utils::FileName aaptToolPath() const;
|
||||
|
||||
Utils::FileName gccPath(const ProjectExplorer::Abi &abi, Core::Id lang,
|
||||
const QString &ndkToolChainVersion) const;
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
|
||||
#include <QDirIterator>
|
||||
#include <QLoggingCategory>
|
||||
#include <QHostAddress>
|
||||
|
||||
namespace {
|
||||
Q_LOGGING_CATEGORY(androidDebugSupportLog, "qtc.android.run.androiddebugsupport")
|
||||
@@ -142,7 +143,10 @@ void AndroidDebugSupport::start()
|
||||
+ "/app_process");
|
||||
setSkipExecutableValidation(true);
|
||||
setUseExtendedRemote(true);
|
||||
setRemoteChannel(":" + m_runner->gdbServerPort().toString());
|
||||
QUrl gdbServer;
|
||||
gdbServer.setHost(QHostAddress(QHostAddress::LocalHost).toString());
|
||||
gdbServer.setPort(m_runner->gdbServerPort().number());
|
||||
setRemoteChannel(gdbServer);
|
||||
|
||||
QString sysRoot = AndroidConfigurations::currentConfig().ndkLocation().appendPath("platforms")
|
||||
.appendPath(QString("android-%1").arg(AndroidManager::minimumSDK(target)))
|
||||
|
||||
@@ -61,17 +61,43 @@
|
||||
#include <QApplication>
|
||||
#include <QDomDocument>
|
||||
#include <QVersionNumber>
|
||||
|
||||
namespace {
|
||||
Q_LOGGING_CATEGORY(androidManagerLog, "qtc.android.androidManager")
|
||||
}
|
||||
#include <QRegularExpression>
|
||||
|
||||
namespace {
|
||||
const QLatin1String AndroidManifestName("AndroidManifest.xml");
|
||||
const QLatin1String AndroidDefaultPropertiesName("project.properties");
|
||||
const QLatin1String AndroidDeviceSn("AndroidDeviceSerialNumber");
|
||||
const QLatin1String ApiLevelKey("AndroidVersion.ApiLevel");
|
||||
const QString packageNameRegEx("(package: name=)\\'(([a-z]{1}[a-z\\d_]*\\."
|
||||
")*[a-z][a-z\\d_]*)\\'");
|
||||
const QString activityRegEx("(launchable-activity: name=)\\'"
|
||||
"(([a-z]{1}[a-z\\d_]*\\.)*[a-z][a-z\\d_]*)\\'");
|
||||
const QString apkVersionRegEx("package: name=([\\=a-z\\d_\\.\\'\\s]*)"
|
||||
"\\sversionName='([\\d\\.]*)'");
|
||||
|
||||
Q_LOGGING_CATEGORY(androidManagerLog, "qtc.android.androidManager")
|
||||
|
||||
bool runCommand(const QString &executable, const QStringList &args,
|
||||
QString *output = nullptr, int timeoutS = 30)
|
||||
{
|
||||
Utils::SynchronousProcess cmdProc;
|
||||
cmdProc.setTimeoutS(timeoutS);
|
||||
qCDebug(androidManagerLog) << executable << args.join(' ');
|
||||
Utils::SynchronousProcessResponse response = cmdProc.runBlocking(executable, args);
|
||||
if (output)
|
||||
*output = response.allOutput();
|
||||
return response.result == Utils::SynchronousProcessResponse::Finished;
|
||||
}
|
||||
|
||||
QString parseAaptOutput(const QString &output, const QString ®Ex) {
|
||||
const QRegularExpression regRx(regEx,
|
||||
QRegularExpression::CaseInsensitiveOption |
|
||||
QRegularExpression::MultilineOption);
|
||||
QRegularExpressionMatch match = regRx.match(output);
|
||||
if (match.hasMatch())
|
||||
return match.captured(2);
|
||||
return QString();
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
@@ -127,6 +153,53 @@ QString AndroidManager::packageName(const Utils::FileName &manifestFile)
|
||||
return manifestElem.attribute(QLatin1String("package"));
|
||||
}
|
||||
|
||||
bool AndroidManager::packageInstalled(const QString &deviceSerial,
|
||||
const QString &packageName)
|
||||
{
|
||||
if (deviceSerial.isEmpty() || packageName.isEmpty())
|
||||
return false;
|
||||
QStringList args = AndroidDeviceInfo::adbSelector(deviceSerial);
|
||||
args << "shell" << "pm" << "list" << "packages";
|
||||
QString output;
|
||||
runAdbCommand(args, &output);
|
||||
QStringList lines = output.split(QRegularExpression("[\\n\\r]"),
|
||||
QString::SkipEmptyParts);
|
||||
for (const QString &line : lines) {
|
||||
// Don't want to confuse com.abc.xyz with com.abc.xyz.def so check with
|
||||
// endsWith
|
||||
if (line.endsWith(packageName))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AndroidManager::apkInfo(const Utils::FileName &apkPath,
|
||||
QString *packageName,
|
||||
QVersionNumber *version,
|
||||
QString *activityPath)
|
||||
{
|
||||
QString output;
|
||||
runAaptCommand({"dump", "badging", apkPath.toString()}, &output);
|
||||
|
||||
QString packageStr;
|
||||
if (activityPath) {
|
||||
packageStr = parseAaptOutput(output, packageNameRegEx);
|
||||
QString path = parseAaptOutput(output, activityRegEx);
|
||||
if (!packageStr.isEmpty() && !path.isEmpty())
|
||||
*activityPath = packageStr + '/' + path;
|
||||
}
|
||||
|
||||
if (packageName) {
|
||||
*packageName = activityPath ? packageStr :
|
||||
parseAaptOutput(output, packageNameRegEx);
|
||||
}
|
||||
|
||||
if (version) {
|
||||
QString versionStr = parseAaptOutput(output, apkVersionRegEx);
|
||||
*version = QVersionNumber::fromString(versionStr);
|
||||
}
|
||||
}
|
||||
|
||||
QString AndroidManager::intentName(ProjectExplorer::Target *target)
|
||||
{
|
||||
return packageName(target) + QLatin1Char('/') + activityName(target);
|
||||
@@ -381,16 +454,9 @@ void AndroidManager::cleanLibsOnDevice(ProjectExplorer::Target *target)
|
||||
Core::MessageManager::write(tr("Starting Android virtual device failed."));
|
||||
}
|
||||
|
||||
QProcess *process = new QProcess();
|
||||
QStringList arguments = AndroidDeviceInfo::adbSelector(deviceSerialNumber);
|
||||
arguments << QLatin1String("shell") << QLatin1String("rm") << QLatin1String("-r") << QLatin1String("/data/local/tmp/qt");
|
||||
QObject::connect(process, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
|
||||
process, &QObject::deleteLater);
|
||||
const QString adb = AndroidConfigurations::currentConfig().adbToolPath().toString();
|
||||
Core::MessageManager::write(adb + QLatin1Char(' ') + arguments.join(QLatin1Char(' ')));
|
||||
process->start(adb, arguments);
|
||||
if (!process->waitForStarted(500))
|
||||
delete process;
|
||||
runAdbCommandDetached(arguments);
|
||||
}
|
||||
|
||||
void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const QString &packagePath)
|
||||
@@ -410,17 +476,9 @@ void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const Q
|
||||
Core::MessageManager::write(tr("Starting Android virtual device failed."));
|
||||
}
|
||||
|
||||
QProcess *process = new QProcess();
|
||||
QStringList arguments = AndroidDeviceInfo::adbSelector(deviceSerialNumber);
|
||||
arguments << QLatin1String("install") << QLatin1String("-r ") << packagePath;
|
||||
|
||||
connect(process, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
|
||||
process, &QObject::deleteLater);
|
||||
const QString adb = AndroidConfigurations::currentConfig().adbToolPath().toString();
|
||||
Core::MessageManager::write(adb + QLatin1Char(' ') + arguments.join(QLatin1Char(' ')));
|
||||
process->start(adb, arguments);
|
||||
if (!process->waitForStarted(500) && process->state() != QProcess::Running)
|
||||
delete process;
|
||||
runAdbCommandDetached(arguments);
|
||||
}
|
||||
|
||||
bool AndroidManager::checkKeystorePassword(const QString &keystorePath, const QString &keystorePasswd)
|
||||
@@ -603,4 +661,27 @@ int AndroidManager::findApiLevel(const Utils::FileName &platformPath)
|
||||
return apiLevel;
|
||||
}
|
||||
|
||||
void AndroidManager::runAdbCommandDetached(const QStringList &args)
|
||||
{
|
||||
QProcess *process = new QProcess();
|
||||
connect(process, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
|
||||
process, &QObject::deleteLater);
|
||||
const QString adb = AndroidConfigurations::currentConfig().adbToolPath().toString();
|
||||
qCDebug(androidManagerLog) << adb << args.join(' ');
|
||||
process->start(adb, args);
|
||||
if (!process->waitForStarted(500) && process->state() != QProcess::Running)
|
||||
delete process;
|
||||
}
|
||||
|
||||
bool AndroidManager::runAdbCommand(const QStringList &args, QString *output)
|
||||
{
|
||||
return runCommand(AndroidConfigurations::currentConfig().adbToolPath().toString(),
|
||||
args, output);
|
||||
}
|
||||
|
||||
bool AndroidManager::runAaptCommand(const QStringList &args, QString *output)
|
||||
{
|
||||
return runCommand(AndroidConfigurations::currentConfig().aaptToolPath().toString(),
|
||||
args, output);
|
||||
}
|
||||
} // namespace Android
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <QPair>
|
||||
#include <QObject>
|
||||
#include <QVersionNumber>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class Kit;
|
||||
@@ -48,7 +49,12 @@ class ANDROID_EXPORT AndroidManager : public QObject
|
||||
public:
|
||||
static QString packageName(ProjectExplorer::Target *target);
|
||||
static QString packageName(const Utils::FileName &manifestFile);
|
||||
|
||||
static bool packageInstalled(const QString &deviceSerial,
|
||||
const QString &packageName);
|
||||
static void apkInfo(const Utils::FileName &apkPath,
|
||||
QString *packageName = nullptr,
|
||||
QVersionNumber *version = nullptr,
|
||||
QString *activityPath = nullptr);
|
||||
static QString intentName(ProjectExplorer::Target *target);
|
||||
static QString activityName(ProjectExplorer::Target *target);
|
||||
|
||||
@@ -86,6 +92,10 @@ public:
|
||||
static AndroidQtSupport *androidQtSupport(ProjectExplorer::Target *target);
|
||||
static bool updateGradleProperties(ProjectExplorer::Target *target);
|
||||
static int findApiLevel(const Utils::FileName &platformPath);
|
||||
|
||||
static void runAdbCommandDetached(const QStringList &args);
|
||||
static bool runAdbCommand(const QStringList &args, QString *output = nullptr);
|
||||
static bool runAaptCommand(const QStringList &args, QString *output = nullptr);
|
||||
};
|
||||
|
||||
} // namespace Android
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "androidavdmanager.h"
|
||||
#include "androidrunnerworker.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/projectexplorersettings.h>
|
||||
@@ -206,6 +207,7 @@ void AndroidRunner::qmlServerPortReady(Port port)
|
||||
// device side. It only happens to work since we redirect
|
||||
// host port n to target port n via adb.
|
||||
QUrl serverUrl;
|
||||
serverUrl.setHost(QHostAddress(QHostAddress::LocalHost).toString());
|
||||
serverUrl.setPort(port.number());
|
||||
serverUrl.setScheme(urlTcpScheme());
|
||||
emit qmlServerReady(serverUrl);
|
||||
|
||||
@@ -176,8 +176,7 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
|
||||
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) {
|
||||
qCDebug(androidRunWorkerLog) << "QML debugging enabled";
|
||||
QTcpServer server;
|
||||
QTC_ASSERT(server.listen(QHostAddress::LocalHost)
|
||||
|| server.listen(QHostAddress::LocalHostIPv6),
|
||||
QTC_ASSERT(server.listen(QHostAddress::LocalHost),
|
||||
qDebug() << tr("No free ports available on host for QML debugging."));
|
||||
m_qmlServer.setScheme(Utils::urlTcpScheme());
|
||||
m_qmlServer.setHost(server.serverAddress().toString());
|
||||
|
||||
Reference in New Issue
Block a user