2016-01-15 14:57:40 +01:00
|
|
|
/****************************************************************************
|
2012-07-03 16:57:44 +03:00
|
|
|
**
|
2021-10-29 18:19:54 +03:00
|
|
|
** Copyright (C) 2022 The Qt Company Ltd.
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2012-07-03 16:57:44 +03:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2012-07-03 16:57:44 +03:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** 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
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2012-07-03 16:57:44 +03:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2012-07-03 16:57:44 +03:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2012-07-03 16:57:44 +03:00
|
|
|
|
|
|
|
#include "androiddevice.h"
|
2021-08-22 01:51:57 +03:00
|
|
|
|
|
|
|
#include "androidavdmanager.h"
|
|
|
|
#include "androidconfigurations.h"
|
2012-07-03 16:57:44 +03:00
|
|
|
#include "androidconstants.h"
|
2021-09-19 14:54:35 +03:00
|
|
|
#include "androidmanager.h"
|
2013-09-30 13:20:02 +02:00
|
|
|
#include "androidsignaloperation.h"
|
2021-09-11 18:38:13 +03:00
|
|
|
#include "avddialog.h"
|
|
|
|
|
|
|
|
#include <coreplugin/icore.h>
|
2012-07-03 16:57:44 +03:00
|
|
|
|
2021-08-22 01:51:57 +03:00
|
|
|
#include <projectexplorer/devicesupport/devicemanager.h>
|
2021-09-19 14:54:35 +03:00
|
|
|
#include <projectexplorer/devicesupport/idevicewidget.h>
|
2021-11-10 22:38:59 +01:00
|
|
|
#include <projectexplorer/kitinformation.h>
|
2016-06-03 19:11:29 +02:00
|
|
|
#include <projectexplorer/runconfiguration.h>
|
2021-11-10 22:38:59 +01:00
|
|
|
#include <projectexplorer/session.h>
|
|
|
|
#include <projectexplorer/target.h>
|
2016-06-03 19:11:29 +02:00
|
|
|
|
2021-09-11 18:38:13 +03:00
|
|
|
#include <utils/qtcprocess.h>
|
2021-08-22 01:51:57 +03:00
|
|
|
#include <utils/runextensions.h>
|
2021-09-19 14:54:35 +03:00
|
|
|
#include <utils/url.h>
|
2017-10-25 16:18:58 +02:00
|
|
|
|
2021-09-11 18:38:13 +03:00
|
|
|
#include <QEventLoop>
|
2021-09-19 14:54:35 +03:00
|
|
|
#include <QFormLayout>
|
2021-09-11 18:38:13 +03:00
|
|
|
#include <QInputDialog>
|
2018-07-17 13:58:50 +02:00
|
|
|
#include <QLoggingCategory>
|
2021-09-11 18:38:13 +03:00
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QPushButton>
|
2021-10-29 18:19:54 +03:00
|
|
|
#include <QTimer>
|
2022-02-22 21:31:12 +02:00
|
|
|
#include <QRegularExpression>
|
2021-10-29 18:19:54 +03:00
|
|
|
|
|
|
|
#include <utils/qtcprocess.h>
|
2012-07-03 16:57:44 +03:00
|
|
|
|
2012-07-26 17:41:52 +02:00
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
2021-08-22 01:51:57 +03:00
|
|
|
namespace {
|
|
|
|
static Q_LOGGING_CATEGORY(androidDeviceLog, "qtc.android.androiddevice", QtWarningMsg)
|
|
|
|
}
|
|
|
|
|
2012-07-03 16:57:44 +03:00
|
|
|
namespace Android {
|
|
|
|
namespace Internal {
|
|
|
|
|
2021-09-19 14:54:35 +03:00
|
|
|
class AndroidDeviceWidget : public IDeviceWidget
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AndroidDeviceWidget(const ProjectExplorer::IDevice::Ptr &device);
|
|
|
|
|
|
|
|
void updateDeviceFromUi() final {}
|
2021-09-11 18:38:13 +03:00
|
|
|
static QString dialogTitle();
|
2021-09-20 21:19:00 +03:00
|
|
|
static bool criticalDialog(const QString &error, QWidget *parent = nullptr);
|
|
|
|
static bool questionDialog(const QString &question, QWidget *parent = nullptr);
|
2021-09-19 14:54:35 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device)
|
|
|
|
: IDeviceWidget(device)
|
|
|
|
{
|
|
|
|
const auto dev = qSharedPointerCast<AndroidDevice>(device);
|
|
|
|
const auto formLayout = new QFormLayout(this);
|
|
|
|
formLayout->setFormAlignment(Qt::AlignLeft);
|
|
|
|
formLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
setLayout(formLayout);
|
|
|
|
formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
|
|
|
|
|
|
|
|
if (!dev->isValid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
formLayout->addRow(AndroidDevice::tr("Device name:"), new QLabel(dev->displayName()));
|
|
|
|
formLayout->addRow(AndroidDevice::tr("Device type:"), new QLabel(dev->deviceTypeName()));
|
|
|
|
|
|
|
|
const QString serialNumber = dev->serialNumber();
|
2021-10-28 10:03:28 +02:00
|
|
|
const QString printableSerialNumber = serialNumber.isEmpty() ? AndroidDevice::tr("Unknown")
|
|
|
|
: serialNumber;
|
2021-09-19 14:54:35 +03:00
|
|
|
formLayout->addRow(AndroidDevice::tr("Serial number:"), new QLabel(printableSerialNumber));
|
|
|
|
|
|
|
|
const QString abis = dev->supportedAbis().join(", ");
|
|
|
|
formLayout->addRow(AndroidDevice::tr("CPU architecture:"), new QLabel(abis));
|
|
|
|
|
|
|
|
const auto osString = QString("%1 (SDK %2)").arg(dev->androidVersion()).arg(dev->sdkLevel());
|
|
|
|
formLayout->addRow(AndroidDevice::tr("OS version:"), new QLabel(osString));
|
|
|
|
|
2021-10-07 11:10:47 +03:00
|
|
|
if (dev->machineType() == IDevice::Hardware) {
|
2021-10-28 10:03:28 +02:00
|
|
|
const QString authorizedStr = dev->deviceState() == IDevice::DeviceReadyToUse
|
|
|
|
? AndroidDevice::tr("Yes")
|
|
|
|
: AndroidDevice::tr("No");
|
2021-10-07 11:10:47 +03:00
|
|
|
formLayout->addRow(AndroidDevice::tr("Authorized:"), new QLabel(authorizedStr));
|
|
|
|
}
|
|
|
|
|
2021-09-19 14:54:35 +03:00
|
|
|
if (dev->machineType() == IDevice::Emulator) {
|
|
|
|
const QString targetName = dev->androidTargetName();
|
|
|
|
formLayout->addRow(AndroidDevice::tr("Android target flavor:"), new QLabel(targetName));
|
|
|
|
formLayout->addRow(AndroidDevice::tr("SD card size:"), new QLabel(dev->sdcardSize()));
|
|
|
|
formLayout->addRow(AndroidDevice::tr("Skin type:"), new QLabel(dev->skinName()));
|
|
|
|
const QString openGlStatus = dev->openGlStatusString();
|
|
|
|
formLayout->addRow(AndroidDevice::tr("OpenGL status:"), new QLabel(openGlStatus));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-11 18:38:13 +03:00
|
|
|
QString AndroidDeviceWidget::dialogTitle()
|
|
|
|
{
|
2021-10-28 10:03:28 +02:00
|
|
|
return AndroidDevice::tr("Android Device Manager");
|
2021-09-11 18:38:13 +03:00
|
|
|
}
|
|
|
|
|
2021-09-20 21:19:00 +03:00
|
|
|
bool AndroidDeviceWidget::criticalDialog(const QString &error, QWidget *parent)
|
2021-09-11 18:38:13 +03:00
|
|
|
{
|
|
|
|
qCDebug(androidDeviceLog) << error;
|
2021-09-20 21:19:00 +03:00
|
|
|
QMessageBox box(parent ? parent : Core::ICore::dialogParent());
|
2021-09-11 18:38:13 +03:00
|
|
|
box.QDialog::setWindowTitle(dialogTitle());
|
|
|
|
box.setText(error);
|
|
|
|
box.setIcon(QMessageBox::Critical);
|
|
|
|
box.setWindowFlag(Qt::WindowTitleHint);
|
|
|
|
return box.exec();
|
|
|
|
}
|
|
|
|
|
2021-09-20 21:19:00 +03:00
|
|
|
bool AndroidDeviceWidget::questionDialog(const QString &question, QWidget *parent)
|
2021-09-11 18:38:13 +03:00
|
|
|
{
|
2021-09-20 21:19:00 +03:00
|
|
|
QMessageBox box(parent ? parent : Core::ICore::dialogParent());
|
2021-09-11 18:38:13 +03:00
|
|
|
box.QDialog::setWindowTitle(dialogTitle());
|
|
|
|
box.setText(question);
|
|
|
|
box.setIcon(QMessageBox::Question);
|
|
|
|
QPushButton *YesButton = box.addButton(QMessageBox::Yes);
|
|
|
|
box.addButton(QMessageBox::No);
|
|
|
|
box.setWindowFlag(Qt::WindowTitleHint);
|
|
|
|
box.exec();
|
|
|
|
|
|
|
|
if (box.clickedButton() == YesButton)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-07-26 17:41:52 +02:00
|
|
|
AndroidDevice::AndroidDevice()
|
2012-07-03 16:57:44 +03:00
|
|
|
{
|
2019-01-14 16:57:51 +01:00
|
|
|
setupId(IDevice::AutoDetected, Constants::ANDROID_DEVICE_ID);
|
2019-01-14 16:11:27 +01:00
|
|
|
setType(Constants::ANDROID_DEVICE_TYPE);
|
2020-01-21 16:17:59 +01:00
|
|
|
setDefaultDisplayName(tr("Run on Android"));
|
|
|
|
setDisplayType(tr("Android"));
|
2019-01-14 15:27:52 +01:00
|
|
|
setMachineType(IDevice::Hardware);
|
2019-08-16 10:17:45 +02:00
|
|
|
setOsType(Utils::OsTypeOtherUnix);
|
2021-08-22 01:51:57 +03:00
|
|
|
setDeviceState(DeviceConnected);
|
|
|
|
|
2021-09-26 23:06:00 +03:00
|
|
|
addDeviceAction({tr("Refresh"), [](const IDevice::Ptr &device, QWidget *parent) {
|
|
|
|
Q_UNUSED(parent)
|
|
|
|
AndroidDeviceManager::instance()->updateDeviceState(device);
|
2021-08-22 01:51:57 +03:00
|
|
|
}});
|
2021-09-11 18:38:13 +03:00
|
|
|
|
2021-09-20 21:19:00 +03:00
|
|
|
addEmulatorActionsIfNotFound();
|
|
|
|
}
|
2021-09-11 18:38:13 +03:00
|
|
|
|
2021-09-20 21:19:00 +03:00
|
|
|
void AndroidDevice::addEmulatorActionsIfNotFound()
|
|
|
|
{
|
|
|
|
static const QString startAvdAction = tr("Start AVD");
|
|
|
|
static const QString eraseAvdAction = tr("Erase AVD");
|
|
|
|
static const QString avdArgumentsAction = tr("AVD Arguments");
|
2021-09-11 18:38:13 +03:00
|
|
|
|
2021-09-20 21:19:00 +03:00
|
|
|
bool hasStartAction = false;
|
|
|
|
bool hasEraseAction = false;
|
|
|
|
bool hasAvdArgumentsAction = false;
|
|
|
|
|
|
|
|
for (const DeviceAction &item : deviceActions()) {
|
|
|
|
if (item.display == startAvdAction)
|
|
|
|
hasStartAction = true;
|
|
|
|
else if (item.display == eraseAvdAction)
|
|
|
|
hasEraseAction = true;
|
|
|
|
else if (item.display == avdArgumentsAction)
|
|
|
|
hasAvdArgumentsAction = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (machineType() == Emulator) {
|
|
|
|
if (!hasStartAction) {
|
|
|
|
addDeviceAction({startAvdAction, [](const IDevice::Ptr &device, QWidget *parent) {
|
|
|
|
AndroidDeviceManager::instance()->startAvd(device, parent);
|
|
|
|
}});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hasEraseAction) {
|
|
|
|
addDeviceAction({eraseAvdAction, [](const IDevice::Ptr &device, QWidget *parent) {
|
|
|
|
AndroidDeviceManager::instance()->eraseAvd(device, parent);
|
|
|
|
}});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hasAvdArgumentsAction) {
|
|
|
|
addDeviceAction({avdArgumentsAction, [](const IDevice::Ptr &device, QWidget *parent) {
|
|
|
|
Q_UNUSED(device)
|
|
|
|
AndroidDeviceManager::instance()->setEmulatorArguments(parent);
|
|
|
|
}});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidDevice::fromMap(const QVariantMap &map)
|
|
|
|
{
|
|
|
|
IDevice::fromMap(map);
|
|
|
|
// Add Actions for Emulator is not added already.
|
|
|
|
// This is needed because actions for Emulators and physical devices are not the same.
|
|
|
|
addEmulatorActionsIfNotFound();
|
2021-08-22 01:51:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
IDevice::Ptr AndroidDevice::create()
|
|
|
|
{
|
|
|
|
return IDevice::Ptr(new AndroidDevice);
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidDeviceInfo AndroidDevice::androidDeviceInfoFromIDevice(const IDevice *dev)
|
|
|
|
{
|
|
|
|
AndroidDeviceInfo info;
|
2021-10-06 22:35:12 +03:00
|
|
|
info.state = dev->deviceState();
|
2021-08-22 01:51:57 +03:00
|
|
|
info.avdname = dev->extraData(Constants::AndroidAvdName).toString();
|
|
|
|
info.serialNumber = dev->extraData(Constants::AndroidSerialNumber).toString();
|
|
|
|
info.cpuAbi = dev->extraData(Constants::AndroidCpuAbi).toStringList();
|
|
|
|
info.avdTarget = dev->extraData(Constants::AndroidAvdTarget).toString();
|
|
|
|
info.avdDevice = dev->extraData(Constants::AndroidAvdDevice).toString();
|
|
|
|
info.avdSkin = dev->extraData(Constants::AndroidAvdSkin).toString();
|
|
|
|
info.avdSdcardSize = dev->extraData(Constants::AndroidAvdSdcard).toString();
|
|
|
|
info.sdk = dev->extraData(Constants::AndroidSdk).toInt();
|
2021-10-06 22:35:12 +03:00
|
|
|
info.type = dev->machineType();
|
2021-08-22 01:51:57 +03:00
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidDevice::setAndroidDeviceInfoExtras(IDevice *dev, const AndroidDeviceInfo &info)
|
|
|
|
{
|
|
|
|
dev->setExtraData(Constants::AndroidAvdName, info.avdname);
|
|
|
|
dev->setExtraData(Constants::AndroidSerialNumber, info.serialNumber);
|
|
|
|
dev->setExtraData(Constants::AndroidCpuAbi, info.cpuAbi);
|
|
|
|
dev->setExtraData(Constants::AndroidAvdTarget, info.avdTarget);
|
|
|
|
dev->setExtraData(Constants::AndroidAvdDevice, info.avdDevice);
|
|
|
|
dev->setExtraData(Constants::AndroidAvdSkin, info.avdSkin);
|
|
|
|
dev->setExtraData(Constants::AndroidAvdSdcard, info.avdSdcardSize);
|
|
|
|
dev->setExtraData(Constants::AndroidSdk, info.sdk);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidDevice::displayNameFromInfo(const AndroidDeviceInfo &info)
|
|
|
|
{
|
2021-10-06 22:35:12 +03:00
|
|
|
return info.type == IDevice::Hardware
|
2021-08-22 01:51:57 +03:00
|
|
|
? AndroidConfigurations::currentConfig().getProductModel(info.serialNumber)
|
|
|
|
: info.avdname;
|
|
|
|
}
|
|
|
|
|
|
|
|
Utils::Id AndroidDevice::idFromDeviceInfo(const AndroidDeviceInfo &info)
|
|
|
|
{
|
2021-10-06 22:35:12 +03:00
|
|
|
const QString id = (info.type == IDevice::Hardware ? info.serialNumber : info.avdname);
|
2021-08-22 01:51:57 +03:00
|
|
|
return Utils::Id(Constants::ANDROID_DEVICE_ID).withSuffix(':' + id);
|
|
|
|
}
|
|
|
|
|
|
|
|
Utils::Id AndroidDevice::idFromAvdInfo(const CreateAvdInfo &info)
|
|
|
|
{
|
|
|
|
return Utils::Id(Constants::ANDROID_DEVICE_ID).withSuffix(':' + info.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList AndroidDevice::supportedAbis() const
|
|
|
|
{
|
|
|
|
return extraData(Constants::AndroidCpuAbi).toStringList();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AndroidDevice::canSupportAbis(const QStringList &abis) const
|
|
|
|
{
|
|
|
|
// If the list is empty, no valid decision can be made, this means something is wrong
|
|
|
|
// somewhere, but let's not stop deployment.
|
|
|
|
QTC_ASSERT(!abis.isEmpty(), return true);
|
|
|
|
|
|
|
|
const QStringList ourAbis = supportedAbis();
|
|
|
|
QTC_ASSERT(!ourAbis.isEmpty(), return false);
|
|
|
|
|
|
|
|
for (const QString &abi : abis)
|
|
|
|
if (ourAbis.contains(abi))
|
|
|
|
return true; // it's enough if only one abi match is found
|
|
|
|
|
|
|
|
// If no exact match is found, let's take ABI backward compatibility into account
|
|
|
|
// https://developer.android.com/ndk/guides/abis#android-platform-abi-support
|
|
|
|
// arm64 usually can run {arm, armv7}, x86 can support {arm, armv7}, and 64-bit devices
|
|
|
|
// can support their 32-bit variants.
|
|
|
|
using namespace ProjectExplorer::Constants;
|
2022-01-14 16:42:21 +01:00
|
|
|
const bool isTheirsArm = abis.contains(ANDROID_ABI_ARMEABI)
|
2021-08-22 01:51:57 +03:00
|
|
|
|| abis.contains(ANDROID_ABI_ARMEABI_V7A);
|
|
|
|
// The primary ABI at the first index
|
|
|
|
const bool oursSupportsArm = ourAbis.first() == ANDROID_ABI_ARM64_V8A
|
|
|
|
|| ourAbis.first() == ANDROID_ABI_X86;
|
|
|
|
// arm64 and x86 can run armv7 and arm
|
|
|
|
if (isTheirsArm && oursSupportsArm)
|
|
|
|
return true;
|
|
|
|
// x64 can run x86
|
|
|
|
if (ourAbis.first() == ANDROID_ABI_X86_64 && abis.contains(ANDROID_ABI_X86))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2019-08-16 10:17:45 +02:00
|
|
|
|
2021-08-22 01:51:57 +03:00
|
|
|
bool AndroidDevice::canHandleDeployments() const
|
|
|
|
{
|
|
|
|
// If hardware and disconned, it wouldn't be possilbe to start it, unlike an emulator
|
|
|
|
if (machineType() == Hardware && deviceState() == DeviceDisconnected)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AndroidDevice::isValid() const
|
|
|
|
{
|
|
|
|
return !serialNumber().isEmpty() || !avdName().isEmpty();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidDevice::serialNumber() const
|
|
|
|
{
|
2021-09-21 21:40:27 +03:00
|
|
|
const QString serialNumber = extraData(Constants::AndroidSerialNumber).toString();
|
|
|
|
if (machineType() == Hardware)
|
|
|
|
return serialNumber;
|
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
return AndroidDeviceManager::instance()->getRunningAvdsSerialNumber(avdName());
|
2021-08-22 01:51:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidDevice::avdName() const
|
|
|
|
{
|
|
|
|
return extraData(Constants::AndroidAvdName).toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
int AndroidDevice::sdkLevel() const
|
|
|
|
{
|
|
|
|
return extraData(Constants::AndroidSdk).toInt();
|
2012-07-03 16:57:44 +03:00
|
|
|
}
|
|
|
|
|
2021-09-19 14:54:35 +03:00
|
|
|
QString AndroidDevice::androidVersion() const
|
|
|
|
{
|
|
|
|
return AndroidManager::androidNameForApiLevel(sdkLevel());
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidDevice::deviceTypeName() const
|
|
|
|
{
|
|
|
|
if (machineType() == Emulator)
|
|
|
|
return tr("Emulator for ") + extraData(Constants::AndroidAvdDevice).toString();
|
|
|
|
return tr("Physical device");
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidDevice::skinName() const
|
|
|
|
{
|
|
|
|
const QString skin = extraData(Constants::AndroidAvdSkin).toString();
|
|
|
|
return skin.isEmpty() ? tr("None") : skin;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidDevice::androidTargetName() const
|
|
|
|
{
|
|
|
|
const QString target = extraData(Constants::AndroidAvdTarget).toString();
|
|
|
|
return target.isEmpty() ? tr("Unknown") : target;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidDevice::sdcardSize() const
|
|
|
|
{
|
|
|
|
const QString size = extraData(Constants::AndroidAvdSdcard).toString();
|
|
|
|
return size.isEmpty() ? tr("Unknown") : size;
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidConfig::OpenGl AndroidDevice::openGlStatus() const
|
|
|
|
{
|
|
|
|
return AndroidConfigurations::currentConfig().getOpenGLEnabled(displayName());
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidDevice::openGlStatusString() const
|
|
|
|
{
|
|
|
|
const AndroidConfig::OpenGl glStatus = AndroidConfigurations::currentConfig()
|
|
|
|
.getOpenGLEnabled(displayName());
|
|
|
|
switch (glStatus) {
|
|
|
|
case (AndroidConfig::OpenGl::Enabled):
|
|
|
|
return tr("Enabled");
|
|
|
|
case (AndroidConfig::OpenGl::Disabled):
|
|
|
|
return tr("Disabled");
|
|
|
|
case (AndroidConfig::OpenGl::Unknown):
|
|
|
|
return tr("Unknown");
|
|
|
|
}
|
|
|
|
return tr("Unknown");
|
|
|
|
}
|
|
|
|
|
2012-07-26 17:41:52 +02:00
|
|
|
IDevice::DeviceInfo AndroidDevice::deviceInformation() const
|
2012-07-03 16:57:44 +03:00
|
|
|
{
|
2012-07-26 17:41:52 +02:00
|
|
|
return IDevice::DeviceInfo();
|
2012-07-03 16:57:44 +03:00
|
|
|
}
|
|
|
|
|
2012-07-26 17:41:52 +02:00
|
|
|
IDeviceWidget *AndroidDevice::createWidget()
|
2012-07-03 16:57:44 +03:00
|
|
|
{
|
2021-09-19 14:54:35 +03:00
|
|
|
return new AndroidDeviceWidget(sharedFromThis());
|
2012-07-03 16:57:44 +03:00
|
|
|
}
|
|
|
|
|
2013-04-18 10:01:05 +02:00
|
|
|
bool AndroidDevice::canAutoDetectPorts() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-16 15:30:30 +02:00
|
|
|
DeviceProcessSignalOperation::Ptr AndroidDevice::signalOperation() const
|
|
|
|
{
|
2013-09-30 13:20:02 +02:00
|
|
|
return DeviceProcessSignalOperation::Ptr(new AndroidSignalOperation());
|
2013-09-16 15:30:30 +02:00
|
|
|
}
|
|
|
|
|
2017-06-29 18:32:01 +02:00
|
|
|
QUrl AndroidDevice::toolControlChannel(const ControlChannelHint &) const
|
2013-10-11 12:58:24 +02:00
|
|
|
{
|
2017-06-29 18:32:01 +02:00
|
|
|
QUrl url;
|
2017-10-25 16:18:58 +02:00
|
|
|
url.setScheme(Utils::urlTcpScheme());
|
2017-06-29 18:32:01 +02:00
|
|
|
url.setHost("localhost");
|
|
|
|
return url;
|
2013-10-11 12:58:24 +02:00
|
|
|
}
|
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
void AndroidDeviceManager::updateAvdsList()
|
2021-08-22 01:51:57 +03:00
|
|
|
{
|
2021-10-29 18:19:54 +03:00
|
|
|
if (!m_avdsFutureWatcher.isRunning() && m_androidConfig.adbToolPath().exists())
|
|
|
|
m_avdsFutureWatcher.setFuture(m_avdManager.avdList());
|
2021-08-22 01:51:57 +03:00
|
|
|
}
|
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
IDevice::DeviceState AndroidDeviceManager::getDeviceState(const QString &serial,
|
|
|
|
IDevice::MachineType type) const
|
2021-08-22 01:51:57 +03:00
|
|
|
{
|
2021-10-29 18:19:54 +03:00
|
|
|
const QStringList args = AndroidDeviceInfo::adbSelector(serial) << "shell" << "echo 1";
|
|
|
|
const SdkToolResult result = AndroidManager::runAdbCommand(args);
|
|
|
|
if (result.success())
|
|
|
|
return IDevice::DeviceReadyToUse;
|
|
|
|
else if (type == IDevice::Emulator || result.stdErr().contains("unauthorized"))
|
|
|
|
return IDevice::DeviceConnected;
|
|
|
|
|
|
|
|
return IDevice::DeviceDisconnected;
|
2021-08-22 01:51:57 +03:00
|
|
|
}
|
2019-02-20 19:13:28 +01:00
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
void AndroidDeviceManager::updateDeviceState(const ProjectExplorer::IDevice::ConstPtr &device)
|
2021-09-26 23:06:00 +03:00
|
|
|
{
|
2021-10-29 18:19:54 +03:00
|
|
|
const AndroidDevice *dev = static_cast<const AndroidDevice *>(device.data());
|
2021-09-26 23:06:00 +03:00
|
|
|
const QString serial = dev->serialNumber();
|
|
|
|
DeviceManager *const devMgr = DeviceManager::instance();
|
|
|
|
const Utils::Id id = dev->id();
|
|
|
|
if (serial.isEmpty() && dev->machineType() == IDevice::Emulator) {
|
|
|
|
devMgr->setDeviceState(id, IDevice::DeviceConnected);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
devMgr->setDeviceState(id, getDeviceState(serial, dev->machineType()));
|
2021-09-26 23:06:00 +03:00
|
|
|
}
|
|
|
|
|
2021-09-20 21:19:00 +03:00
|
|
|
void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent)
|
2021-09-11 18:38:13 +03:00
|
|
|
{
|
2021-09-20 21:19:00 +03:00
|
|
|
Q_UNUSED(parent)
|
2021-09-11 18:38:13 +03:00
|
|
|
const AndroidDevice *androidDev = static_cast<const AndroidDevice *>(device.data());
|
|
|
|
const QString name = androidDev->avdName();
|
|
|
|
qCDebug(androidDeviceLog, "Starting Android AVD id \"%s\".", qPrintable(name));
|
|
|
|
Utils::runAsync([this, name, device]() {
|
|
|
|
const QString serialNumber = m_avdManager.startAvd(name);
|
|
|
|
// Mark the AVD as ReadyToUse once we know it's started
|
|
|
|
if (!serialNumber.isEmpty()) {
|
|
|
|
DeviceManager *const devMgr = DeviceManager::instance();
|
|
|
|
devMgr->setDeviceState(device->id(), IDevice::DeviceReadyToUse);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-09-20 21:19:00 +03:00
|
|
|
void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device, QWidget *parent)
|
2021-09-11 18:38:13 +03:00
|
|
|
{
|
|
|
|
if (device.isNull())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (device->machineType() == IDevice::Hardware)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const QString name = static_cast<const AndroidDevice *>(device.data())->avdName();
|
2021-10-28 10:03:28 +02:00
|
|
|
const QString question
|
|
|
|
= AndroidDevice::tr("Erase the Android AVD \"%1\"?\nThis cannot be undone.").arg(name);
|
2021-09-20 21:19:00 +03:00
|
|
|
if (!AndroidDeviceWidget::questionDialog(question, parent))
|
2021-09-11 18:38:13 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
qCDebug(androidDeviceLog) << QString("Erasing Android AVD \"%1\" from the system.").arg(name);
|
|
|
|
m_removeAvdFutureWatcher.setFuture(Utils::runAsync([this, name, device]() {
|
|
|
|
QPair<IDevice::ConstPtr, bool> pair;
|
|
|
|
pair.first = device;
|
|
|
|
pair.second = false;
|
|
|
|
if (m_avdManager.removeAvd(name))
|
|
|
|
pair.second = true;
|
|
|
|
return pair;
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidDeviceManager::handleAvdRemoved()
|
|
|
|
{
|
|
|
|
const QPair<IDevice::ConstPtr, bool> result = m_removeAvdFutureWatcher.result();
|
|
|
|
const QString name = result.first->displayName();
|
|
|
|
if (result.second) {
|
|
|
|
qCDebug(androidDeviceLog, "Android AVD id \"%s\" removed from the system.", qPrintable(name));
|
|
|
|
// Remove the device from QtC after it's been removed using avdmanager.
|
|
|
|
DeviceManager::instance()->removeDevice(result.first->id());
|
|
|
|
} else {
|
|
|
|
AndroidDeviceWidget::criticalDialog(QObject::tr("An error occurred while removing the "
|
|
|
|
"Android AVD \"%1\" using avdmanager tool.").arg(name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
QString AndroidDeviceManager::emulatorName(const QString &serialNumber) const
|
|
|
|
{
|
|
|
|
QStringList args = AndroidDeviceInfo::adbSelector(serialNumber);
|
|
|
|
args.append({"emu", "avd", "name"});
|
|
|
|
return AndroidManager::runAdbCommand(args).stdOut();
|
|
|
|
}
|
|
|
|
|
2021-09-20 21:19:00 +03:00
|
|
|
void AndroidDeviceManager::setEmulatorArguments(QWidget *parent)
|
2021-09-11 18:38:13 +03:00
|
|
|
{
|
|
|
|
const QString helpUrl =
|
|
|
|
"https://developer.android.com/studio/run/emulator-commandline#startup-options";
|
|
|
|
|
2021-09-20 21:19:00 +03:00
|
|
|
QInputDialog dialog(parent ? parent : Core::ICore::dialogParent());
|
2021-10-28 10:03:28 +02:00
|
|
|
dialog.setWindowTitle(AndroidDevice::tr("Emulator Command-line Startup Options"));
|
|
|
|
dialog.setLabelText(AndroidDevice::tr("Emulator command-line startup options "
|
|
|
|
"(<a href=\"%1\">Help Web Page</a>):")
|
|
|
|
.arg(helpUrl));
|
2021-09-11 18:38:13 +03:00
|
|
|
dialog.setTextValue(m_androidConfig.emulatorArgs().join(' '));
|
|
|
|
|
|
|
|
if (auto label = dialog.findChild<QLabel*>()) {
|
|
|
|
label->setOpenExternalLinks(true);
|
|
|
|
label->setMinimumWidth(500);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dialog.exec() != QDialog::Accepted)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_androidConfig.setEmulatorArgs(Utils::ProcessArgs::splitArgs(dialog.textValue()));
|
|
|
|
}
|
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
QString AndroidDeviceManager::getRunningAvdsSerialNumber(const QString &name) const
|
2021-08-22 01:51:57 +03:00
|
|
|
{
|
2021-10-29 18:19:54 +03:00
|
|
|
for (const AndroidDeviceInfo &dev : m_androidConfig.connectedDevices()) {
|
|
|
|
if (!dev.serialNumber.startsWith("emulator"))
|
|
|
|
continue;
|
|
|
|
const QString stdOut = emulatorName(dev.serialNumber);
|
|
|
|
if (stdOut.isEmpty())
|
|
|
|
continue; // Not an avd
|
|
|
|
const QStringList outputLines = stdOut.split('\n');
|
|
|
|
if (outputLines.size() > 1 && outputLines.first() == name)
|
|
|
|
return dev.serialNumber;
|
2021-11-10 22:38:59 +01:00
|
|
|
}
|
2021-10-29 18:19:54 +03:00
|
|
|
|
|
|
|
return {};
|
2021-08-22 01:51:57 +03:00
|
|
|
}
|
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
void AndroidDeviceManager::setupDevicesWatcher()
|
2021-08-22 01:51:57 +03:00
|
|
|
{
|
2021-10-29 18:19:54 +03:00
|
|
|
if (!m_androidConfig.adbToolPath().exists()) {
|
|
|
|
qCDebug(androidDeviceLog) << "Cannot start ADB device watcher"
|
|
|
|
<< "because adb path does not exist.";
|
|
|
|
return;
|
|
|
|
}
|
2021-08-22 01:51:57 +03:00
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
if (!m_adbDeviceWatcherProcess)
|
|
|
|
m_adbDeviceWatcherProcess.reset(new Utils::QtcProcess(this));
|
2021-08-22 01:51:57 +03:00
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
if (m_adbDeviceWatcherProcess->isRunning()) {
|
|
|
|
qCDebug(androidDeviceLog) << "ADB device watcher is already running.";
|
|
|
|
return;
|
|
|
|
}
|
2021-08-22 01:51:57 +03:00
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
connect(m_adbDeviceWatcherProcess.get(), &Utils::QtcProcess::finished, this,
|
|
|
|
[]() { qCDebug(androidDeviceLog) << "ADB device watcher finished."; });
|
2021-08-22 01:51:57 +03:00
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
connect(m_adbDeviceWatcherProcess.get(), &Utils::QtcProcess::errorOccurred, this,
|
2022-02-18 14:28:34 +01:00
|
|
|
[this](QProcess::ProcessError) {
|
2021-10-29 18:19:54 +03:00
|
|
|
qCDebug(androidDeviceLog) << "ADB device watcher encountered an error:"
|
|
|
|
<< m_adbDeviceWatcherProcess->errorString();
|
|
|
|
if (!m_adbDeviceWatcherProcess->isRunning()) {
|
|
|
|
qCDebug(androidDeviceLog) << "Restarting the ADB device watcher now.";
|
|
|
|
QTimer::singleShot(0, m_adbDeviceWatcherProcess.get(), &Utils::QtcProcess::start);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
m_adbDeviceWatcherProcess->setStdErrLineCallback([](const QString &error) {
|
|
|
|
qCDebug(androidDeviceLog) << "ADB device watcher error" << error; });
|
|
|
|
m_adbDeviceWatcherProcess->setStdOutLineCallback([this](const QString &output) {
|
|
|
|
HandleDevicesListChange(output);
|
|
|
|
});
|
|
|
|
|
|
|
|
const Utils::CommandLine command = Utils::CommandLine(m_androidConfig.adbToolPath(),
|
|
|
|
{"track-devices"});
|
|
|
|
m_adbDeviceWatcherProcess->setCommand(command);
|
|
|
|
m_adbDeviceWatcherProcess->setEnvironment(AndroidConfigurations::toolsEnvironment(m_androidConfig));
|
|
|
|
m_adbDeviceWatcherProcess->start();
|
|
|
|
|
|
|
|
// Setup AVD filesystem watcher to listen for changes when an avd is created/deleted,
|
|
|
|
// or started/stopped
|
|
|
|
QString avdEnvVar = qEnvironmentVariable("ANDROID_AVD_HOME");
|
|
|
|
if (avdEnvVar.isEmpty()) {
|
|
|
|
avdEnvVar = qEnvironmentVariable("ANDROID_SDK_HOME");
|
|
|
|
if (avdEnvVar.isEmpty())
|
|
|
|
avdEnvVar = qEnvironmentVariable("HOME");
|
|
|
|
avdEnvVar.append("/.android/avd");
|
|
|
|
}
|
|
|
|
const Utils::FilePath avdPath = Utils::FilePath::fromUserInput(avdEnvVar);
|
|
|
|
m_avdFileSystemWatcher.addPath(avdPath.toString());
|
|
|
|
connect(&m_avdsFutureWatcher, &QFutureWatcherBase::finished,
|
|
|
|
this, &AndroidDeviceManager::HandleAvdsListChange);
|
|
|
|
connect(&m_avdFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, [this]() {
|
|
|
|
// If the avd list upate command is running no need to call it again.
|
|
|
|
if (!m_avdsFutureWatcher.isRunning())
|
|
|
|
updateAvdsList();
|
|
|
|
});
|
|
|
|
// Call initial update
|
|
|
|
updateAvdsList();
|
|
|
|
}
|
2021-08-22 01:51:57 +03:00
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
void AndroidDeviceManager::HandleAvdsListChange()
|
|
|
|
{
|
|
|
|
DeviceManager *const devMgr = DeviceManager::instance();
|
|
|
|
|
|
|
|
QVector<IDevice::ConstPtr> existingAvds;
|
2021-08-22 01:51:57 +03:00
|
|
|
for (int i = 0; i < devMgr->deviceCount(); ++i) {
|
|
|
|
const IDevice::ConstPtr dev = devMgr->deviceAt(i);
|
2021-10-29 18:19:54 +03:00
|
|
|
const bool isEmulator = dev->machineType() == IDevice::Emulator;
|
|
|
|
if (isEmulator && dev->type() == Constants::ANDROID_DEVICE_TYPE)
|
|
|
|
existingAvds.append(dev);
|
2021-08-22 01:51:57 +03:00
|
|
|
}
|
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
QVector<IDevice::ConstPtr> connectedDevs;
|
|
|
|
for (auto item : m_avdsFutureWatcher.result()) {
|
2021-08-22 01:51:57 +03:00
|
|
|
const Utils::Id deviceId = AndroidDevice::idFromDeviceInfo(item);
|
|
|
|
const QString displayName = AndroidDevice::displayNameFromInfo(item);
|
|
|
|
IDevice::ConstPtr dev = devMgr->find(deviceId);
|
|
|
|
if (!dev.isNull()) {
|
2021-10-29 18:19:54 +03:00
|
|
|
const auto androidDev = static_cast<const AndroidDevice *>(dev.data());
|
|
|
|
// DeviceManager doens't seem to hav a way to directly update the name, if the name
|
|
|
|
// of the device has changed, remove it and register it again with the new name.
|
|
|
|
// Also account for the case of an AVD registered through old QC which might have
|
|
|
|
// invalid data by checking the sdcard size value.
|
2022-02-16 14:32:48 +01:00
|
|
|
if (dev->displayName() != displayName
|
|
|
|
|| androidDev->sdcardSize() == AndroidDevice::tr("Unknown")) {
|
2021-10-29 18:19:54 +03:00
|
|
|
devMgr->removeDevice(dev->id());
|
|
|
|
} else {
|
|
|
|
// Find the state of the AVD retrieved from the AVD watcher
|
|
|
|
const QString serial = getRunningAvdsSerialNumber(item.avdname);
|
|
|
|
const IDevice::DeviceState state = getDeviceState(serial, IDevice::Emulator);
|
|
|
|
if (dev->deviceState() != state) {
|
|
|
|
devMgr->setDeviceState(dev->id(), state);
|
2021-08-22 01:51:57 +03:00
|
|
|
qCDebug(androidDeviceLog, "Device id \"%s\" changed its state.",
|
|
|
|
dev->id().toString().toUtf8().data());
|
|
|
|
}
|
|
|
|
connectedDevs.append(dev);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2019-02-20 19:13:28 +01:00
|
|
|
|
2021-08-22 01:51:57 +03:00
|
|
|
AndroidDevice *newDev = new AndroidDevice();
|
|
|
|
newDev->setupId(IDevice::AutoDetected, deviceId);
|
|
|
|
newDev->setDisplayName(displayName);
|
2021-10-06 22:35:12 +03:00
|
|
|
newDev->setMachineType(item.type);
|
|
|
|
newDev->setDeviceState(item.state);
|
2021-08-22 01:51:57 +03:00
|
|
|
AndroidDevice::setAndroidDeviceInfoExtras(newDev, item);
|
|
|
|
qCDebug(androidDeviceLog, "Registering new Android device id \"%s\".",
|
|
|
|
newDev->id().toString().toUtf8().data());
|
|
|
|
const IDevice::ConstPtr constNewDev = IDevice::ConstPtr(newDev);
|
2021-10-29 18:19:54 +03:00
|
|
|
devMgr->addDevice(IDevice::ConstPtr(constNewDev));
|
2021-08-22 01:51:57 +03:00
|
|
|
connectedDevs.append(constNewDev);
|
2021-10-29 18:19:54 +03:00
|
|
|
|
|
|
|
// Set devices no longer connected to disconnected state.
|
|
|
|
for (const IDevice::ConstPtr &dev : existingAvds) {
|
|
|
|
if (!connectedDevs.contains(dev)) {
|
|
|
|
qCDebug(androidDeviceLog, "Removing AVD id \"%s\" because it no longer exists.",
|
|
|
|
dev->id().toString().toUtf8().data());
|
|
|
|
devMgr->removeDevice(dev->id());
|
|
|
|
}
|
|
|
|
}
|
2021-08-22 01:51:57 +03:00
|
|
|
}
|
2021-10-29 18:19:54 +03:00
|
|
|
}
|
2021-08-22 01:51:57 +03:00
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
void AndroidDeviceManager::HandleDevicesListChange(const QString &serialNumber)
|
|
|
|
{
|
|
|
|
DeviceManager *const devMgr = DeviceManager::instance();
|
|
|
|
const QStringList serialBits = serialNumber.split('\t');
|
|
|
|
if (serialBits.size() < 2)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Sample output of adb track-devices, the first 4 digits are for state type
|
|
|
|
// and sometimes 4 zeros are reported as part for the serial number.
|
|
|
|
// 00546db0e8d7 authorizing
|
|
|
|
// 00546db0e8d7 device
|
|
|
|
// 0000001711201JEC207789 offline
|
|
|
|
// emulator-5554 device
|
|
|
|
QString dirtySerial = serialBits.first().trimmed();
|
|
|
|
if (dirtySerial.startsWith("0000"))
|
|
|
|
dirtySerial = dirtySerial.mid(4);
|
|
|
|
if (dirtySerial.startsWith("00"))
|
|
|
|
dirtySerial = dirtySerial.mid(4);
|
|
|
|
const bool isEmulator = dirtySerial.startsWith("emulator");
|
|
|
|
|
|
|
|
const QString &serial = dirtySerial;
|
|
|
|
const QString stateStr = serialBits.at(1).trimmed();
|
|
|
|
|
|
|
|
IDevice::DeviceState state;
|
|
|
|
if (stateStr == "device")
|
|
|
|
state = IDevice::DeviceReadyToUse;
|
|
|
|
else if (stateStr == "offline")
|
|
|
|
state = IDevice::DeviceDisconnected;
|
|
|
|
else
|
|
|
|
state = IDevice::DeviceConnected;
|
|
|
|
|
|
|
|
if (isEmulator) {
|
|
|
|
const QString avdName = emulatorName(serial);
|
|
|
|
const Utils::Id avdId = Utils::Id(Constants::ANDROID_DEVICE_ID).withSuffix(':' + avdName);
|
|
|
|
devMgr->setDeviceState(avdId, state);
|
|
|
|
} else {
|
|
|
|
const Utils::Id id = Utils::Id(Constants::ANDROID_DEVICE_ID).withSuffix(':' + serial);
|
2022-02-22 21:31:12 +02:00
|
|
|
QString displayName = AndroidConfigurations::currentConfig().getProductModel(serial);
|
|
|
|
// Check if the device is connected via WiFi. A sample serial of such devices can be
|
|
|
|
// like: "192.168.1.190:5555"
|
|
|
|
const QRegularExpression wifiSerialRegExp(
|
|
|
|
QLatin1String("(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}):(\\d{1,5})"));
|
|
|
|
if (wifiSerialRegExp.match(serial).hasMatch())
|
|
|
|
displayName += QLatin1String(" (WiFi)");
|
|
|
|
|
2021-10-29 18:19:54 +03:00
|
|
|
if (IDevice::ConstPtr dev = devMgr->find(id)) {
|
|
|
|
// DeviceManager doens't seem to have a way to directly update the name, if the name
|
|
|
|
// of the device has changed, remove it and register it again with the new name.
|
|
|
|
if (dev->displayName() == displayName)
|
|
|
|
devMgr->setDeviceState(id, state);
|
|
|
|
else
|
|
|
|
devMgr->removeDevice(id);
|
|
|
|
} else {
|
|
|
|
AndroidDevice *newDev = new AndroidDevice();
|
|
|
|
newDev->setupId(IDevice::AutoDetected, id);
|
|
|
|
newDev->setDisplayName(displayName);
|
|
|
|
newDev->setMachineType(IDevice::Hardware);
|
|
|
|
newDev->setDeviceState(state);
|
|
|
|
|
|
|
|
newDev->setExtraData(Constants::AndroidSerialNumber, serial);
|
|
|
|
newDev->setExtraData(Constants::AndroidCpuAbi, m_androidConfig.getAbis(serial));
|
|
|
|
newDev->setExtraData(Constants::AndroidSdk, m_androidConfig.getSDKVersion(serial));
|
|
|
|
|
|
|
|
qCDebug(androidDeviceLog, "Registering new Android device id \"%s\".",
|
|
|
|
newDev->id().toString().toUtf8().data());
|
|
|
|
devMgr->addDevice(IDevice::ConstPtr(newDev));
|
2021-08-22 01:51:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidDeviceManager *AndroidDeviceManager::instance()
|
|
|
|
{
|
|
|
|
static AndroidDeviceManager obj;
|
|
|
|
return &obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidDeviceManager::AndroidDeviceManager(QObject *parent)
|
2021-09-11 18:38:13 +03:00
|
|
|
: QObject(parent),
|
2021-10-25 15:58:02 +03:00
|
|
|
m_androidConfig(AndroidConfigurations::currentConfig()),
|
|
|
|
m_avdManager(m_androidConfig)
|
2021-08-22 01:51:57 +03:00
|
|
|
{
|
|
|
|
connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() {
|
2022-02-23 09:47:42 +01:00
|
|
|
if (m_adbDeviceWatcherProcess) {
|
|
|
|
m_adbDeviceWatcherProcess->terminate();
|
|
|
|
m_adbDeviceWatcherProcess->waitForFinished();
|
|
|
|
m_adbDeviceWatcherProcess.reset();
|
|
|
|
}
|
2021-08-22 01:51:57 +03:00
|
|
|
m_avdsFutureWatcher.waitForFinished();
|
2021-09-11 18:38:13 +03:00
|
|
|
m_removeAvdFutureWatcher.waitForFinished();
|
2021-08-22 01:51:57 +03:00
|
|
|
});
|
2021-09-11 18:38:13 +03:00
|
|
|
|
|
|
|
connect(&m_removeAvdFutureWatcher, &QFutureWatcherBase::finished,
|
|
|
|
this, &AndroidDeviceManager::handleAvdRemoved);
|
2021-08-22 01:51:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Factory
|
2022-01-26 09:05:35 +01:00
|
|
|
|
2019-02-20 19:13:28 +01:00
|
|
|
AndroidDeviceFactory::AndroidDeviceFactory()
|
2022-01-26 09:05:35 +01:00
|
|
|
: IDeviceFactory(Constants::ANDROID_DEVICE_TYPE),
|
2021-09-11 18:38:13 +03:00
|
|
|
m_androidConfig(AndroidConfigurations::currentConfig())
|
2019-02-20 19:13:28 +01:00
|
|
|
{
|
2021-10-25 12:56:52 +03:00
|
|
|
setDisplayName(AndroidDevice::tr("Android Device"));
|
2019-02-20 19:13:28 +01:00
|
|
|
setCombinedIcon(":/android/images/androiddevicesmall.png",
|
|
|
|
":/android/images/androiddevice.png");
|
2022-01-26 09:05:35 +01:00
|
|
|
|
2019-02-20 19:13:28 +01:00
|
|
|
setConstructionFunction(&AndroidDevice::create);
|
2022-01-26 10:00:24 +01:00
|
|
|
if (m_androidConfig.sdkToolsOk()) {
|
|
|
|
setCreator([this] {
|
|
|
|
AvdDialog dialog = AvdDialog(m_androidConfig, Core::ICore::dialogParent());
|
|
|
|
if (dialog.exec() != QDialog::Accepted)
|
|
|
|
return IDevice::Ptr();
|
|
|
|
|
|
|
|
const IDevice::Ptr dev = dialog.device();
|
|
|
|
if (const auto androidDev = static_cast<AndroidDevice *>(dev.data())) {
|
|
|
|
qCDebug(androidDeviceLog, "Created new Android AVD id \"%s\".",
|
|
|
|
qPrintable(androidDev->avdName()));
|
|
|
|
} else {
|
|
|
|
AndroidDeviceWidget::criticalDialog(
|
|
|
|
AndroidDevice::tr("The device info returned from AvdDialog is invalid."));
|
|
|
|
}
|
2021-09-11 18:38:13 +03:00
|
|
|
|
2022-01-26 10:00:24 +01:00
|
|
|
return IDevice::Ptr(dev);
|
|
|
|
});
|
|
|
|
}
|
2019-02-20 19:13:28 +01:00
|
|
|
}
|
|
|
|
|
2012-07-03 16:57:44 +03:00
|
|
|
} // namespace Internal
|
|
|
|
} // namespace Android
|