aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/android
diff options
context:
space:
mode:
authorAssam Boudjelthia <assam.boudjelthia@qt.io>2021-09-23 17:11:19 +0300
committerAssam Boudjelthia <assam.boudjelthia@qt.io>2021-09-30 09:06:23 +0000
commitb7c15d4d8dfdbc40c89fc6ba3c6e9e7d142cdab4 (patch)
tree9390dd6a7207b8dbc5f1be79d1f0a88743d7bee4 /src/plugins/android
parentb1d5abd8eb6f1b7ee7a56854c2dd841b89efa37c (diff)
Android: Make fixes to androidqmlpreview
This amends 261a39cbbd2fa53d35bd4d4de8642dc341f9f6ad with fixes to issues noticed after merging the initial patch. Change-Id: I5f859374cbba3a2e020e6ca0789cc2b387d2739a Reviewed-by: Christian Kandeler <christian.kandeler@qt.io> Reviewed-by: Alessandro Portale <alessandro.portale@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'src/plugins/android')
-rw-r--r--src/plugins/android/androidqmlpreviewworker.cpp354
-rw-r--r--src/plugins/android/androidqmlpreviewworker.h32
2 files changed, 180 insertions, 206 deletions
diff --git a/src/plugins/android/androidqmlpreviewworker.cpp b/src/plugins/android/androidqmlpreviewworker.cpp
index 645cabbb48a..37de94a6f94 100644
--- a/src/plugins/android/androidqmlpreviewworker.cpp
+++ b/src/plugins/android/androidqmlpreviewworker.cpp
@@ -23,12 +23,13 @@
**
****************************************************************************/
+#include "androidqmlpreviewworker.h"
+
#include "androidavdmanager.h"
#include "androiddevice.h"
#include "androiddeviceinfo.h"
#include "androidglobal.h"
#include "androidmanager.h"
-#include "androidqmlpreviewworker.h"
#include <coreplugin/icore.h>
@@ -44,10 +45,10 @@
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
+#include <utils/runextensions.h>
+
+#include <QDateTime>
#include <QThread>
-#include <QTemporaryDir>
-#include <QImageReader>
-#include <QtConcurrent>
namespace Android {
namespace Internal {
@@ -80,173 +81,143 @@ ApkInfo::ApkInfo() :
Q_GLOBAL_STATIC(ApkInfo, apkInfo)
-const char packageSuffix[] = ".qmlrc";
+static const char packageSuffix[] = ".qmlrc";
-static inline bool isMainThread()
+FilePath AndroidQmlPreviewWorker::designViewerApkPath(const QString &abi) const
{
- return QCoreApplication::instance()->thread() == QThread::currentThread();
-}
-
-static FilePath viewerApkPath(const QString &avdAbi)
-{
- if (avdAbi.isEmpty())
+ if (abi.isEmpty())
return {};
- if (apkInfo()->abis.contains(avdAbi))
- return Core::ICore::resourcePath(QString("android/qtdesignviewer/designviewer_%1.apk").
- arg(avdAbi));
+ if (apkInfo()->abis.contains(abi)) {
+ return Core::ICore::resourcePath(QString("android/qtdesignviewer/designviewer_%1.apk")
+ .arg(abi));
+ }
return {};
}
-static SdkToolResult runAdbCommandAsyncAndWait(const QString &dev, const QStringList &arguments)
+SdkToolResult AndroidQmlPreviewWorker::runAdbCommand(const QStringList &arguments) const
{
QStringList args;
- if (!dev.isEmpty())
- args << AndroidDeviceInfo::adbSelector(dev);
+ if (!m_serialNumber.isEmpty())
+ args << AndroidDeviceInfo::adbSelector(m_serialNumber);
args << arguments;
- QFuture<SdkToolResult> asyncResult = QtConcurrent::run([args] {
- return AndroidManager::runAdbCommand(args);});
+ return AndroidManager::runAdbCommand(args);
+}
- while (asyncResult.isRunning()) {
- QCoreApplication::instance()->processEvents(QEventLoop::AllEvents, 100);
- }
- return asyncResult.result();
+SdkToolResult AndroidQmlPreviewWorker::runAdbShellCommand(const QStringList &arguments) const
+{
+ return runAdbCommand(QStringList() << "shell" << arguments);
}
-static SdkToolResult runAdbCommand(const QString &dev, const QStringList &arguments)
+int AndroidQmlPreviewWorker::pidofPreview() const
{
- if (isMainThread())
- return runAdbCommandAsyncAndWait(dev, arguments);
- QStringList args;
- if (!dev.isEmpty())
- args << AndroidDeviceInfo::adbSelector(dev);
- args << arguments;
- return AndroidManager::runAdbCommand(args);
+ const QStringList command{"pidof", apkInfo()->appId};
+ const SdkToolResult res = runAdbShellCommand(command);
+ return res.success() ? res.stdOut().toInt() : -1;
}
-static SdkToolResult runAdbShellCommand(const QString &dev, const QStringList &arguments)
+bool AndroidQmlPreviewWorker::isPreviewRunning(int lastKnownPid) const
{
- const QStringList shellCmd{"shell"};
- return runAdbCommand(dev, shellCmd + arguments);
+ const int pid = pidofPreview();
+ return (lastKnownPid > 1) ? lastKnownPid == pid : pid > 1;
}
-static QString startAvd(const AndroidAvdManager &avd, const QString &name)
+void AndroidQmlPreviewWorker::startPidWatcher()
{
- QFuture<QString> asyncRes = QtConcurrent::run([avd, name] {
- return avd.startAvd(name);
- });
- while (asyncRes.isRunning())
- QCoreApplication::instance()->processEvents(QEventLoop::AllEvents, 100);
- return asyncRes.result();
+ m_pidFutureWatcher.setFuture(Utils::runAsync([this]() {
+ // wait for started
+ const int sleepTimeMs = 2000;
+ QDeadlineTimer deadline(20000);
+ while (!m_pidFutureWatcher.isCanceled() && !deadline.hasExpired()) {
+ if (m_viewerPid == -1) {
+ m_viewerPid = pidofPreview();
+ if (m_viewerPid > 0) {
+ emit previewPidChanged();
+ break;
+ }
+ }
+ QThread::msleep(sleepTimeMs);
+ }
+
+ while (!m_pidFutureWatcher.isCanceled()) {
+ if (!isPreviewRunning(m_viewerPid)) {
+ stop();
+ break;
+ }
+ QThread::msleep(sleepTimeMs);
+ }
+ }));
}
-static int pidofPreview(const QString &dev)
+void AndroidQmlPreviewWorker::startLogcat()
{
- const QStringList command{"pidof", apkInfo()->appId};
- const SdkToolResult res = runAdbShellCommand(dev, command);
- return res.success() ? res.stdOut().toInt() : -1;
+ QString args = QString("logcat --pid=%1").arg(m_viewerPid);
+ if (!m_logcatStartTimeStamp.isEmpty())
+ args += QString(" -T '%1'").arg(m_logcatStartTimeStamp);
+ Utils::CommandLine cmd(AndroidConfigurations::currentConfig().adbToolPath());
+ cmd.setArguments(args);
+ m_logcatProcess.setCommand(cmd);
+ m_logcatProcess.setUseCtrlCStub(true);
+ m_logcatProcess.start();
}
-static bool isPreviewRunning(const QString &dev, int lastKnownPid = -1)
+void AndroidQmlPreviewWorker::filterLogcatAndAppendMessage(const QString &stdOut)
{
- const int pid = pidofPreview(dev);
- return (lastKnownPid > 1) ? lastKnownPid == pid : pid > 1;
+ for (const QString &line : stdOut.split('\n')) {
+ QStringList splittedLine = line.split(QLatin1String("%1: ").arg(apkInfo()->name));
+ if (splittedLine.count() == 1)
+ continue;
+
+ const QString outLine = splittedLine.last();
+ const QString firstPart = splittedLine.first();
+ if (firstPart.contains(" I ") || firstPart.contains(" D "))
+ appendMessage(outLine, NormalMessageFormat);
+ else
+ appendMessage(outLine, ErrorMessageFormat);
+ }
}
AndroidQmlPreviewWorker::AndroidQmlPreviewWorker(ProjectExplorer::RunControl *runControl)
- : ProjectExplorer::RunWorker(runControl)
- , m_rc(runControl)
- , m_config(AndroidConfigurations::currentConfig())
+ : ProjectExplorer::RunWorker(runControl),
+ m_rc(runControl),
+ m_androidConfig(AndroidConfigurations::currentConfig())
{
+ connect(this, &RunWorker::started, this, &AndroidQmlPreviewWorker::startPidWatcher);
+ connect(this, &RunWorker::stopped, &m_pidFutureWatcher, &QFutureWatcher<void>::cancel);
+ connect(this, &AndroidQmlPreviewWorker::previewPidChanged,
+ this, &AndroidQmlPreviewWorker::startLogcat);
+
+ connect(this, &RunWorker::stopped, &m_logcatProcess, &Utils::QtcProcess::stopProcess);
+ m_logcatProcess.setStdOutCallback([this](const QString &stdOut) {
+ filterLogcatAndAppendMessage(stdOut);
+ });
}
-QStringList filterAppLog(const QStringList& oldList, const QStringList& newList)
+AndroidQmlPreviewWorker::~AndroidQmlPreviewWorker()
{
- QStringList list = Utils::filtered(newList,
- [](const auto & arg){return arg.contains(apkInfo()->name);});
- for (const auto &oldEntry : oldList) {
- list.removeAll(oldEntry);
- }
- return list;
+ m_pidFutureWatcher.cancel();
+ m_pidFutureWatcher.waitForFinished();
}
void AndroidQmlPreviewWorker::start()
{
- UploadInfo transfer;
- const bool res = ensureAvdIsRunning()
- && checkAndInstallPreviewApp()
- && prepareUpload(transfer)
- && uploadFiles(transfer)
- && runPreviewApp(transfer);
-
- if (!res) {
- reportFailure();
- return;
+ const SdkToolResult dateResult = runAdbCommand({"shell", "date", "+%s"});
+ if (dateResult.success()) {
+ m_logcatStartTimeStamp = QDateTime::fromSecsSinceEpoch(dateResult.stdOut().toInt())
+ .toString("MM-dd hh:mm:ss.mmm");
}
- reportStarted();
- //Thread to monitor preview life
- QtConcurrent::run([this]() {
- QElapsedTimer timer;
- timer.start();
- while (runControl() && runControl()->isRunning()) {
- if (m_viewerPid == -1) {
- m_viewerPid = pidofPreview(m_devInfo.serialNumber);
- if (m_viewerPid > 0)
- QMetaObject::invokeMethod(this, &AndroidQmlPreviewWorker::startLogcat);
- } else if (timer.elapsed() > 2000) {
- //Get the application output
- if (!isPreviewRunning(m_devInfo.serialNumber, m_viewerPid))
- QMetaObject::invokeMethod(this, &AndroidQmlPreviewWorker::stop);
-
- timer.restart();
- }
- QThread::msleep(100);
- }
- });
-}
+ const bool previewStarted = ensureAvdIsRunning()
+ && checkAndInstallPreviewApp()
+ && uploadPreviewArtefacts()
+ && preparePreviewArtefacts()
+ && startPreviewApp();
-void AndroidQmlPreviewWorker::startLogcat()
-{
- QtConcurrent::run([this]() {
- QElapsedTimer timer;
- timer.start();
- int initialPid = m_viewerPid; // to check if our initial process is still alive
- QStringList logLines;
- auto appendLogLinesCall = [&logLines, this](){ appendLogLines(logLines); };
- auto runCondition = [this, initialPid](){ return (runControl() && runControl()->isRunning())
- && initialPid == m_viewerPid;};
- QString timeFilter;
- while (runCondition()) {
- if (timer.elapsed() > 2000) {
- //Get the application output
- QStringList logcatCmd = {"logcat", QString("--pid=%1").arg(initialPid), "-t"};
- if (!timeFilter.isEmpty())
- logcatCmd.append(QString("%1").arg(timeFilter));
- else
- logcatCmd.append(QString("1000")); //show last 1000 lines (but for the 1st time)
-
- const SdkToolResult logcatResult = runAdbCommand(m_devInfo.serialNumber, logcatCmd);
- if (runCondition()) {
- const QStringList output = logcatResult.stdOut().split('\n');
- const QStringList filtered = filterAppLog(logLines, output);
-
- if (!filtered.isEmpty()){
- const QString lastLine = filtered.last();
- timeFilter = lastLine.left(lastLine.indexOf(" ", lastLine.indexOf(" ") + 1));
- QMetaObject::invokeMethod(this, appendLogLinesCall);
- logLines = filtered;
- }
- }
- timer.restart();
- }
- QThread::msleep(100);
- }
- });
+ previewStarted ? reportStarted() : reportStopped();
}
void AndroidQmlPreviewWorker::stop()
{
- if (!isPreviewRunning(m_devInfo.serialNumber, m_viewerPid) || stopPreviewApp())
+ if (!isPreviewRunning(m_viewerPid) || stopPreviewApp())
appendMessage(tr("%1 has been stopped.").arg(apkInfo()->name), NormalMessageFormat);
m_viewerPid = -1;
reportStopped();
@@ -254,28 +225,35 @@ void AndroidQmlPreviewWorker::stop()
bool AndroidQmlPreviewWorker::ensureAvdIsRunning()
{
- AndroidAvdManager avdMan(m_config);
+ AndroidAvdManager avdMananager(m_androidConfig);
QString devSN = AndroidManager::deviceSerialNumber(m_rc->target());
if (devSN.isEmpty())
- devSN = m_devInfo.serialNumber;
+ devSN = m_serialNumber;
- if (!avdMan.isAvdBooted(devSN)) {
- m_devInfo = {};
+ if (!avdMananager.isAvdBooted(devSN)) {
using namespace ProjectExplorer;
const IDevice *dev = DeviceKitAspect::device(m_rc->target()->kit()).data();
+ if (!dev) {
+ appendMessage(tr("Selected device is invalid."), ErrorMessageFormat);
+ return false;
+ }
+ if (dev->deviceState() == IDevice::DeviceDisconnected) {
+ appendMessage(tr("Selected device is disconnected."), ErrorMessageFormat);
+ return false;
+ }
AndroidDeviceInfo devInfoLocal = AndroidDevice::androidDeviceInfoFromIDevice(dev);
if (devInfoLocal.isValid()) {
- if (devInfoLocal.type == AndroidDeviceInfo::Emulator) {
+ if (dev->machineType() == IDevice::Emulator) {
appendMessage(tr("Launching AVD."), NormalMessageFormat);
- devInfoLocal.serialNumber = startAvd(avdMan, devInfoLocal.avdname);
+ devInfoLocal.serialNumber = avdMananager.startAvd(devInfoLocal.avdname);
}
if (devInfoLocal.serialNumber.isEmpty()) {
- appendMessage(tr("Could not run AVD."), ErrorMessageFormat);
+ appendMessage(tr("Could not start AVD."), ErrorMessageFormat);
} else {
- m_devInfo = devInfoLocal;
- m_avdAbis = m_config.getAbis(m_config.adbToolPath(), m_devInfo.serialNumber);
+ m_serialNumber = devInfoLocal.serialNumber;
+ m_avdAbis = m_androidConfig.getAbis(m_androidConfig.adbToolPath(), m_serialNumber);
}
return !devInfoLocal.serialNumber.isEmpty();
} else {
@@ -283,7 +261,7 @@ bool AndroidQmlPreviewWorker::ensureAvdIsRunning()
}
return false;
}
- m_avdAbis = m_config.getAbis(m_config.adbToolPath(), m_devInfo.serialNumber);
+ m_avdAbis = m_androidConfig.getAbis(m_androidConfig.adbToolPath(), m_serialNumber);
return true;
}
@@ -291,7 +269,7 @@ bool AndroidQmlPreviewWorker::checkAndInstallPreviewApp()
{
const QStringList command {"pm", "list", "packages", apkInfo()->appId};
appendMessage(tr("Checking if %1 app is installed.").arg(apkInfo()->name), NormalMessageFormat);
- const SdkToolResult res = runAdbShellCommand(m_devInfo.serialNumber, command);
+ const SdkToolResult res = runAdbShellCommand(command);
if (!res.success()) {
appendMessage(res.stdErr(), ErrorMessageFormat);
return false;
@@ -303,7 +281,7 @@ bool AndroidQmlPreviewWorker::checkAndInstallPreviewApp()
ErrorMessageFormat);
return false;
}
- const FilePath apkPath = viewerApkPath(m_avdAbis.first());
+ const FilePath apkPath = designViewerApkPath(m_avdAbis.first());
if (!apkPath.exists()) {
appendMessage(tr("Cannot install %1 app for %2 architecture. "
"The appropriate APK was not found in resources folders.").
@@ -313,32 +291,29 @@ bool AndroidQmlPreviewWorker::checkAndInstallPreviewApp()
appendMessage(tr("Installing %1 APK.").arg(apkInfo()->name), NormalMessageFormat);
-
- const SdkToolResult res = runAdbCommand(m_devInfo.serialNumber, {"install",
- apkPath.toString()});
- if (!res.success()) {
+ const SdkToolResult res = runAdbCommand({"install", apkPath.toString()});
+ if (!res.success())
appendMessage(res.stdErr(), StdErrFormat);
-
- return false;
- }
}
- return true;
+
+ return res.success();
}
-bool AndroidQmlPreviewWorker::prepareUpload(UploadInfo &transfer)
+bool AndroidQmlPreviewWorker::preparePreviewArtefacts()
{
if (m_rc->project()->id() == QmlProjectManager::Constants::QML_PROJECT_ID) {
const auto bs = m_rc->target()->buildSystem();
if (bs) {
- transfer.uploadPackage = FilePath::fromString(
+ m_uploadInfo.uploadPackage = FilePath::fromString(
bs->additionalData(QmlProjectManager::Constants::mainFilePath).toString());
- transfer.projectFolder = bs->projectDirectory();
+ m_uploadInfo.projectFolder = bs->projectDirectory();
return true;
}
} else {
const FilePaths allFiles = m_rc->project()->files(m_rc->project()->SourceFiles);
const FilePaths filesToExport = Utils::filtered(allFiles,[](const FilePath &path) {
- return path.suffix() == "qmlproject";});
+ return path.suffix() == "qmlproject";
+ });
if (filesToExport.size() > 1) {
appendMessage(tr("Too many .qmlproject files in your project. Open directly the "
@@ -348,10 +323,9 @@ bool AndroidQmlPreviewWorker::prepareUpload(UploadInfo &transfer)
appendMessage(tr("No .qmlproject file found among project files."), ErrorMessageFormat);
} else {
const FilePath qmlprojectFile = filesToExport.first();
- transfer.uploadPackage = transfer.
- projectFolder.
- resolvePath(qmlprojectFile.fileName());
- transfer.projectFolder = qmlprojectFile.parentDir();
+ m_uploadInfo.uploadPackage = m_uploadInfo.projectFolder.resolvePath(
+ qmlprojectFile.fileName());
+ m_uploadInfo.projectFolder = qmlprojectFile.parentDir();
return true;
}
}
@@ -366,16 +340,15 @@ FilePath AndroidQmlPreviewWorker::createQmlrcFile(const FilePath &workFolder,
const FilePath rccBinary = qtVersion->rccFilePath();
QtcProcess rccProcess;
FilePath qrcPath = FilePath::fromString(basename) + ".qrc4viewer";
- const FilePath qmlrcPath = FilePath::fromString(QDir::tempPath() + "/" + basename +
- packageSuffix);
+ const FilePath qmlrcPath = FilePath::fromString(QDir::tempPath()) / basename + packageSuffix;
rccProcess.setWorkingDirectory(workFolder);
const QStringList arguments[2] = {{"--project", "--output", qrcPath.fileName()},
{"--binary", "--output", qmlrcPath.path(),
qrcPath.fileName()}};
- for (const auto &arguments : arguments) {
- rccProcess.setCommand({rccBinary, arguments});
+ for (const QStringList &args : arguments) {
+ rccProcess.setCommand({rccBinary, args});
rccProcess.start();
if (!rccProcess.waitForStarted()) {
appendMessage(tr("Could not create file for %1 \"%2\"").
@@ -420,71 +393,54 @@ FilePath AndroidQmlPreviewWorker::createQmlrcFile(const FilePath &workFolder,
return qmlrcPath;
}
-bool AndroidQmlPreviewWorker::uploadFiles(const UploadInfo &transfer)
+bool AndroidQmlPreviewWorker::uploadPreviewArtefacts()
{
appendMessage(tr("Uploading files."), NormalMessageFormat);
-
- const FilePath qresPath = createQmlrcFile(FilePath::fromString(transfer.projectFolder.path()),
- transfer.uploadPackage.baseName());
+ const FilePath qresPath = createQmlrcFile(m_uploadInfo.projectFolder,
+ m_uploadInfo.uploadPackage.baseName());
if (!qresPath.exists())
return false;
- runAdbShellCommand(m_devInfo.serialNumber, {"mkdir", "-p", apkInfo()->uploadDir});
-
- const SdkToolResult res = runAdbCommand(m_devInfo.serialNumber,
- {"push", qresPath.resolvePath(QString()).toString(),
- apkInfo()->uploadDir});
+ runAdbShellCommand({"mkdir", "-p", apkInfo()->uploadDir});
+ const SdkToolResult res = runAdbCommand({"push", qresPath.resolvePath(QString()).toString(),
+ apkInfo()->uploadDir});
if (!res.success()) {
appendMessage(res.stdOut(), ErrorMessageFormat);
- if (res.stdOut().contains("Permission denied"))
+ if (res.stdOut().contains("Permission denied")) {
appendMessage("'Permission denied' error detected. Try restarting your device "
"and then running the preview.", NormalMessageFormat);
+ }
}
qresPath.removeFile();
return res.success();
}
-bool AndroidQmlPreviewWorker::runPreviewApp(const UploadInfo &transfer)
+bool AndroidQmlPreviewWorker::startPreviewApp()
{
stopPreviewApp();
appendMessage(tr("Starting %1.").arg(apkInfo()->name), NormalMessageFormat);
const QDir destDir(apkInfo()->uploadDir);
+ const QString qmlrcPath = destDir.filePath(m_uploadInfo.uploadPackage.baseName()
+ + packageSuffix);
const QStringList command{"am", "start",
"-n", apkInfo()->activityId,
- "-e", "extraappparams",
- QString::fromLatin1(
- destDir.filePath(transfer.uploadPackage.baseName() + packageSuffix).
- toUtf8().
- toBase64())};
- const SdkToolResult res = runAdbShellCommand(m_devInfo.serialNumber, command);
- if (!res.success()) {
- appendMessage(res.stdErr(), ErrorMessageFormat);
- return res.success();
- }
- appendMessage(tr("%1 is running.").arg(apkInfo()->name), NormalMessageFormat);
- m_viewerPid = pidofPreview(m_devInfo.serialNumber);
- return true;
+ "-e", "extraappparams", QLatin1String(qmlrcPath.toUtf8().toBase64())};
+ const SdkToolResult result = runAdbShellCommand(command);
+ if (result.success())
+ appendMessage(tr("%1 is running.").arg(apkInfo()->name), NormalMessageFormat);
+ else
+ appendMessage(result.stdErr(), ErrorMessageFormat);
+
+ return result.success();
}
bool AndroidQmlPreviewWorker::stopPreviewApp()
{
const QStringList command{"am", "force-stop", apkInfo()->appId};
- const SdkToolResult res = runAdbShellCommand(m_devInfo.serialNumber, command);
- if (!res.success()) {
+ const SdkToolResult res = runAdbShellCommand(command);
+ if (!res.success())
appendMessage(res.stdErr(), ErrorMessageFormat);
- return res.success();
- }
- return true;
-}
-
-void AndroidQmlPreviewWorker::appendLogLines(const QStringList & lines)
-{
- for (const QString& line : lines) {
- const int charsToSkip = apkInfo()->name.length() + 2; // strlen(": ") == 2
- const QString formatted = line.mid(line.indexOf(apkInfo()->name) + charsToSkip);
- // TODO: See AndroidRunnerWorker::logcatProcess() - filtering for logs to decide format.
- appendMessage(formatted, StdOutFormat);
- }
+ return res.success();
}
} // namespace Internal
diff --git a/src/plugins/android/androidqmlpreviewworker.h b/src/plugins/android/androidqmlpreviewworker.h
index e014107df54..c837570e01f 100644
--- a/src/plugins/android/androidqmlpreviewworker.h
+++ b/src/plugins/android/androidqmlpreviewworker.h
@@ -25,9 +25,12 @@
#pragma once
#include "androidconfigurations.h"
+
#include <projectexplorer/runcontrol.h>
#include <utils/environment.h>
+#include <QFutureWatcher>
+
namespace Android {
class SdkToolResult;
@@ -45,6 +48,10 @@ class AndroidQmlPreviewWorker : public ProjectExplorer::RunWorker
Q_OBJECT
public:
AndroidQmlPreviewWorker(ProjectExplorer::RunControl *runControl);
+ ~AndroidQmlPreviewWorker();
+
+signals:
+ void previewPidChanged();
private:
void start() override;
@@ -52,22 +59,33 @@ private:
bool ensureAvdIsRunning();
bool checkAndInstallPreviewApp();
- bool prepareUpload(UploadInfo &transfer);
- bool uploadFiles(const UploadInfo &transfer);
+ bool preparePreviewArtefacts();
+ bool uploadPreviewArtefacts();
- bool runPreviewApp(const UploadInfo &transfer);
- bool stopPreviewApp();
+ SdkToolResult runAdbCommand(const QStringList &arguments) const;
+ SdkToolResult runAdbShellCommand(const QStringList &arguments) const;
+ int pidofPreview() const;
+ bool isPreviewRunning(int lastKnownPid = -1) const;
+ void startPidWatcher();
void startLogcat();
- void appendLogLines(const QStringList &lines);
+ void filterLogcatAndAppendMessage(const QString &stdOut);
+
+ bool startPreviewApp();
+ bool stopPreviewApp();
+ Utils::FilePath designViewerApkPath(const QString &abi) const;
Utils::FilePath createQmlrcFile(const Utils::FilePath &workFolder, const QString &basename);
ProjectExplorer::RunControl *m_rc = nullptr;
- AndroidConfig m_config;
- AndroidDeviceInfo m_devInfo;
+ AndroidConfig m_androidConfig;
+ QString m_serialNumber;
QStringList m_avdAbis;
int m_viewerPid = -1;
+ QFutureWatcher<void> m_pidFutureWatcher;
+ Utils::QtcProcess m_logcatProcess;
+ QString m_logcatStartTimeStamp;
+ UploadInfo m_uploadInfo;
};
} // namespace Internal