From 6b31ff29604cc805049ba41cb124a1b124d89eb8 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 11 Jul 2024 13:41:45 +0200 Subject: [PATCH] Android: Make installQASIPackage() asynchronous Reuse existing avd recipes and run a task tree instead. Change-Id: Ieaeb84eee299d7f75101a3076027d4185533b897 Reviewed-by: Alessandro Portale --- src/plugins/android/androiddeployqtstep.cpp | 66 ++++++++++++++++++++- src/plugins/android/androidmanager.cpp | 30 ---------- src/plugins/android/androidmanager.h | 2 - 3 files changed, 64 insertions(+), 34 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 492191222e1..8c7a84909fb 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -579,8 +579,70 @@ QWidget *AndroidDeployQtStep::createConfigWidget() Tr::tr("Qt Android Installer"), FileUtils::homePath(), Tr::tr("Android package (*.apk)")); - if (!packagePath.isEmpty()) - AndroidManager::installQASIPackage(target(), packagePath); + if (packagePath.isEmpty()) + return; + + // TODO: Write error messages on all the early returns below. + Target *currentTarget = target(); + if (currentTarget == nullptr) + return; + + const QStringList appAbis = AndroidManager::applicationAbis(currentTarget); + if (appAbis.isEmpty()) + return; + + const IDevice::ConstPtr device = DeviceKitAspect::device(currentTarget->kit()); + const AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromIDevice(device.get()); + if (!info.isValid()) // aborted + return; + + const Storage serialNumberStorage; + + const auto onSetup = [serialNumberStorage, info] { + if (info.type == IDevice::Emulator) + return SetupResult::Continue; + if (info.serialNumber.isEmpty()) + return SetupResult::StopWithError; + *serialNumberStorage = info.serialNumber; + return SetupResult::StopWithSuccess; + }; + const auto onDone = [serialNumberStorage, info](DoneWith result) { + if (info.type == IDevice::Emulator && serialNumberStorage->isEmpty()) { + Core::MessageManager::writeDisrupting(Tr::tr("Starting Android virtual device failed.")); + return false; + } + return result == DoneWith::Success; + }; + + const auto onAdbSetup = [serialNumberStorage, packagePath](Process &process) { + const CommandLine cmd{AndroidConfig::adbToolPath(), + {AndroidDeviceInfo::adbSelector(*serialNumberStorage), + "install", "-r", packagePath.path()}}; + process.setCommand(cmd); + }; + const auto onAdbDone = [](const Process &process, DoneWith result) { + if (result == DoneWith::Success) { + Core::MessageManager::writeSilently( + Tr::tr("Android package installation finished with success.")); + } else { + Core::MessageManager::writeDisrupting(Tr::tr("Android package installation failed.") + + '\n' + process.cleanedStdErr()); + } + }; + + const Group recipe { + serialNumberStorage, + Group { + onGroupSetup(onSetup), + AndroidAvdManager::startAvdRecipe(info.avdName, serialNumberStorage), + onGroupDone(onDone) + }, + ProcessTask(onAdbSetup, onAdbDone) + }; + + TaskTreeRunner *runner = new TaskTreeRunner; + runner->setParent(currentTarget); + runner->start(recipe); }); using namespace Layouting; diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index dac4eb3c8e4..e15e3b5a81a 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -583,36 +583,6 @@ QString androidNameForApiLevel(int x) } } -void installQASIPackage(Target *target, const FilePath &packagePath) -{ - const QStringList appAbis = AndroidManager::applicationAbis(target); - if (appAbis.isEmpty()) - return; - const IDevice::ConstPtr device = DeviceKitAspect::device(target->kit()); - AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromIDevice(device.get()); - if (!info.isValid()) // aborted - return; - - QString deviceSerialNumber = info.serialNumber; - if (info.type == IDevice::Emulator) { - deviceSerialNumber = AndroidAvdManager::startAvd(info.avdName); - if (deviceSerialNumber.isEmpty()) - MessageManager::writeDisrupting(Tr::tr("Starting Android virtual device failed.")); - } - - QStringList arguments = AndroidDeviceInfo::adbSelector(deviceSerialNumber); - arguments << "install" << "-r " << packagePath.path(); - QString error; - Process *process = startAdbProcess(arguments, &error); - if (process) { - // TODO: Potential leak when the process is still running on Creator shutdown. - QObject::connect(process, &Process::done, process, &QObject::deleteLater); - } else { - MessageManager::writeDisrupting( - Tr::tr("Android package installation failed.\n%1").arg(error)); - } -} - bool checkKeystorePassword(const FilePath &keystorePath, const QString &keystorePasswd) { if (keystorePasswd.isEmpty()) diff --git a/src/plugins/android/androidmanager.h b/src/plugins/android/androidmanager.h index 382768e898c..2557a3675f8 100644 --- a/src/plugins/android/androidmanager.h +++ b/src/plugins/android/androidmanager.h @@ -72,8 +72,6 @@ bool skipInstallationAndPackageSteps(const ProjectExplorer::Target *target); QString androidNameForApiLevel(int x); -void installQASIPackage(ProjectExplorer::Target *target, const Utils::FilePath &packagePath); - bool checkKeystorePassword(const Utils::FilePath &keystorePath, const QString &keystorePasswd); bool checkCertificatePassword(const Utils::FilePath &keystorePath,