forked from qt-creator/qt-creator
Move AVD Manager from Android Settings to Device Settings
Move AVD management and creation to Qt Creator's DeviceManager facilities. This allows AVDs to be created from the Devices settings page and their details and control/action buttons for starting/stopping, etc. are added there as well. This makes the process similar to other device types that Qt Creator supports, to get a similar experience. Task-number: QTCREATORBUG-23991 Change-Id: I16c52b3cc73035e0ee12fd54ae9dad4595c8cda5 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
@@ -70,6 +70,7 @@ public:
|
|||||||
int sdcardSize = 0;
|
int sdcardSize = 0;
|
||||||
QString error; // only used in the return value of createAVD
|
QString error; // only used in the return value of createAVD
|
||||||
bool overwrite = false;
|
bool overwrite = false;
|
||||||
|
bool cancelled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SdkForQtVersions
|
struct SdkForQtVersions
|
||||||
|
@@ -31,16 +31,24 @@
|
|||||||
#include "androidconstants.h"
|
#include "androidconstants.h"
|
||||||
#include "androidmanager.h"
|
#include "androidmanager.h"
|
||||||
#include "androidsignaloperation.h"
|
#include "androidsignaloperation.h"
|
||||||
|
#include "avddialog.h"
|
||||||
|
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
#include <projectexplorer/devicesupport/devicemanager.h>
|
#include <projectexplorer/devicesupport/devicemanager.h>
|
||||||
#include <projectexplorer/devicesupport/idevicewidget.h>
|
#include <projectexplorer/devicesupport/idevicewidget.h>
|
||||||
#include <projectexplorer/runconfiguration.h>
|
#include <projectexplorer/runconfiguration.h>
|
||||||
|
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/url.h>
|
#include <utils/url.h>
|
||||||
|
|
||||||
|
#include <QEventLoop>
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
|
#include <QInputDialog>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
|
|
||||||
@@ -60,6 +68,9 @@ public:
|
|||||||
AndroidDeviceWidget(const ProjectExplorer::IDevice::Ptr &device);
|
AndroidDeviceWidget(const ProjectExplorer::IDevice::Ptr &device);
|
||||||
|
|
||||||
void updateDeviceFromUi() final {}
|
void updateDeviceFromUi() final {}
|
||||||
|
static QString dialogTitle();
|
||||||
|
static bool criticalDialog(const QString &error);
|
||||||
|
static bool questionDialog(const QString &question);
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device)
|
AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device)
|
||||||
@@ -98,6 +109,38 @@ AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString AndroidDeviceWidget::dialogTitle()
|
||||||
|
{
|
||||||
|
return tr("Android Device Manager");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AndroidDeviceWidget::criticalDialog(const QString &error)
|
||||||
|
{
|
||||||
|
qCDebug(androidDeviceLog) << error;
|
||||||
|
QMessageBox box(Core::ICore::dialogParent());
|
||||||
|
box.QDialog::setWindowTitle(dialogTitle());
|
||||||
|
box.setText(error);
|
||||||
|
box.setIcon(QMessageBox::Critical);
|
||||||
|
box.setWindowFlag(Qt::WindowTitleHint);
|
||||||
|
return box.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AndroidDeviceWidget::questionDialog(const QString &question)
|
||||||
|
{
|
||||||
|
QMessageBox box(Core::ICore::dialogParent());
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
AndroidDevice::AndroidDevice()
|
AndroidDevice::AndroidDevice()
|
||||||
{
|
{
|
||||||
setupId(IDevice::AutoDetected, Constants::ANDROID_DEVICE_ID);
|
setupId(IDevice::AutoDetected, Constants::ANDROID_DEVICE_ID);
|
||||||
@@ -111,6 +154,20 @@ AndroidDevice::AndroidDevice()
|
|||||||
addDeviceAction({tr("Refresh"), [](const IDevice::Ptr &device, QWidget *parent) {
|
addDeviceAction({tr("Refresh"), [](const IDevice::Ptr &device, QWidget *parent) {
|
||||||
AndroidDeviceManager::instance()->updateDevicesListOnce();
|
AndroidDeviceManager::instance()->updateDevicesListOnce();
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
addDeviceAction({tr("Start AVD"), [](const IDevice::Ptr &device, QWidget *parent) {
|
||||||
|
if (device->machineType() == IDevice::Emulator)
|
||||||
|
AndroidDeviceManager::instance()->startAvd(device);
|
||||||
|
}});
|
||||||
|
|
||||||
|
addDeviceAction({tr("Erase AVD"), [](const IDevice::Ptr &device, QWidget *parent) {
|
||||||
|
if (device->machineType() == IDevice::Emulator)
|
||||||
|
AndroidDeviceManager::instance()->eraseAvd(device);
|
||||||
|
}});
|
||||||
|
|
||||||
|
addDeviceAction({tr("AVD Arguments"), [](const IDevice::Ptr &device, QWidget *parent) {
|
||||||
|
AndroidDeviceManager::instance()->setEmulatorArguments();
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
IDevice::Ptr AndroidDevice::create()
|
IDevice::Ptr AndroidDevice::create()
|
||||||
@@ -350,6 +407,81 @@ void AndroidDeviceManager::updateDevicesListOnce()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device)
|
||||||
|
{
|
||||||
|
if (device.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (device->machineType() == IDevice::Hardware)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QString name = static_cast<const AndroidDevice *>(device.data())->avdName();
|
||||||
|
const QString question = tr("Erase the Android AVD \"%1\"?\nThis cannot be undone.").arg(name);
|
||||||
|
if (!AndroidDeviceWidget::questionDialog(question))
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidDeviceManager::setEmulatorArguments()
|
||||||
|
{
|
||||||
|
const QString helpUrl =
|
||||||
|
"https://developer.android.com/studio/run/emulator-commandline#startup-options";
|
||||||
|
|
||||||
|
QInputDialog dialog(Core::ICore::dialogParent());
|
||||||
|
dialog.setWindowTitle(tr("Emulator Command-line Startup Options"));
|
||||||
|
dialog.setLabelText(tr("Emulator command-line startup options "
|
||||||
|
"(<a href=\"%1\">Help Web Page</a>):").arg(helpUrl));
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
|
||||||
void AndroidDeviceManager::setupDevicesWatcher()
|
void AndroidDeviceManager::setupDevicesWatcher()
|
||||||
{
|
{
|
||||||
// The call to avdmanager is always slower than the call to adb devices,
|
// The call to avdmanager is always slower than the call to adb devices,
|
||||||
@@ -443,23 +575,80 @@ AndroidDeviceManager *AndroidDeviceManager::instance()
|
|||||||
}
|
}
|
||||||
|
|
||||||
AndroidDeviceManager::AndroidDeviceManager(QObject *parent)
|
AndroidDeviceManager::AndroidDeviceManager(QObject *parent)
|
||||||
: QObject(parent), m_androidConfig(AndroidConfigurations::currentConfig())
|
: QObject(parent),
|
||||||
|
m_androidConfig(AndroidConfigurations::currentConfig()),
|
||||||
|
m_avdManager(m_androidConfig)
|
||||||
{
|
{
|
||||||
connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() {
|
connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() {
|
||||||
m_devicesUpdaterTimer.stop();
|
m_devicesUpdaterTimer.stop();
|
||||||
m_avdsFutureWatcher.waitForFinished();
|
m_avdsFutureWatcher.waitForFinished();
|
||||||
m_devicesFutureWatcher.waitForFinished();
|
m_devicesFutureWatcher.waitForFinished();
|
||||||
|
m_removeAvdFutureWatcher.waitForFinished();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(&m_removeAvdFutureWatcher, &QFutureWatcherBase::finished,
|
||||||
|
this, &AndroidDeviceManager::handleAvdRemoved);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Factory
|
// Factory
|
||||||
AndroidDeviceFactory::AndroidDeviceFactory()
|
AndroidDeviceFactory::AndroidDeviceFactory()
|
||||||
: ProjectExplorer::IDeviceFactory(Constants::ANDROID_DEVICE_TYPE)
|
: ProjectExplorer::IDeviceFactory(Constants::ANDROID_DEVICE_TYPE),
|
||||||
|
m_androidConfig(AndroidConfigurations::currentConfig())
|
||||||
{
|
{
|
||||||
setDisplayName(AndroidDevice::tr("Android Device"));
|
setDisplayName(AndroidDevice::tr("Android Virtual Device"));
|
||||||
setCombinedIcon(":/android/images/androiddevicesmall.png",
|
setCombinedIcon(":/android/images/androiddevicesmall.png",
|
||||||
":/android/images/androiddevice.png");
|
":/android/images/androiddevice.png");
|
||||||
setConstructionFunction(&AndroidDevice::create);
|
setConstructionFunction(&AndroidDevice::create);
|
||||||
|
setCanCreate(m_androidConfig.sdkToolsOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
IDevice::Ptr AndroidDeviceFactory::create() const
|
||||||
|
{
|
||||||
|
AndroidSdkManager sdkManager = AndroidSdkManager(m_androidConfig);
|
||||||
|
const CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(Core::ICore::dialogParent(),
|
||||||
|
&sdkManager, m_androidConfig);
|
||||||
|
if (!info.isValid()) {
|
||||||
|
if (!info.cancelled) {
|
||||||
|
AndroidDeviceWidget::criticalDialog(
|
||||||
|
QObject::tr("The returned device info is invalid."));
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AndroidAvdManager avdManager = AndroidAvdManager(m_androidConfig);
|
||||||
|
QFutureWatcher<CreateAvdInfo> createAvdFutureWatcher;
|
||||||
|
createAvdFutureWatcher.setFuture(avdManager.createAvd(info));
|
||||||
|
|
||||||
|
QEventLoop loop;
|
||||||
|
QObject::connect(&createAvdFutureWatcher, &QFutureWatcher<CreateAvdInfo>::finished,
|
||||||
|
&loop, &QEventLoop::quit);
|
||||||
|
QObject::connect(&createAvdFutureWatcher, &QFutureWatcher<CreateAvdInfo>::canceled,
|
||||||
|
&loop, &QEventLoop::quit);
|
||||||
|
loop.exec(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
|
||||||
|
QFuture<CreateAvdInfo> future = createAvdFutureWatcher.future();
|
||||||
|
if (!(future.isResultReadyAt(0) && future.result().isValid())) {
|
||||||
|
AndroidDeviceWidget::criticalDialog(QObject::tr("The device info returned by "
|
||||||
|
"avdmanager tool is invalid for the device name \"%1\".").arg(info.name));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateAvdInfo newAvdInfo = createAvdFutureWatcher.result();
|
||||||
|
|
||||||
|
AndroidDevice *dev = new AndroidDevice();
|
||||||
|
const Utils::Id deviceId = AndroidDevice::idFromAvdInfo(newAvdInfo);
|
||||||
|
dev->setupId(IDevice::AutoDetected, deviceId);
|
||||||
|
dev->setMachineType(IDevice::Emulator);
|
||||||
|
dev->setDisplayName(newAvdInfo.name);
|
||||||
|
dev->setDeviceState(IDevice::DeviceConnected);
|
||||||
|
dev->setExtraData(Constants::AndroidAvdName, newAvdInfo.name);
|
||||||
|
dev->setExtraData(Constants::AndroidCpuAbi, {newAvdInfo.abi});
|
||||||
|
dev->setExtraData(Constants::AndroidSdk, newAvdInfo.systemImage->apiLevel());
|
||||||
|
dev->setExtraData(Constants::AndroidAvdSdcard, QString("%1 MB").arg(newAvdInfo.sdcardSize));
|
||||||
|
dev->setExtraData(Constants::AndroidAvdDevice, newAvdInfo.deviceDefinition);
|
||||||
|
|
||||||
|
qCDebug(androidDeviceLog, "Created new Android AVD id \"%s\".", qPrintable(newAvdInfo.name));
|
||||||
|
return IDevice::Ptr(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "androidavdmanager.h"
|
||||||
#include "androidconfigurations.h"
|
#include "androidconfigurations.h"
|
||||||
#include "androiddeviceinfo.h"
|
#include "androiddeviceinfo.h"
|
||||||
|
|
||||||
@@ -84,6 +85,10 @@ class AndroidDeviceFactory final : public ProjectExplorer::IDeviceFactory
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AndroidDeviceFactory();
|
AndroidDeviceFactory();
|
||||||
|
ProjectExplorer::IDevice::Ptr create() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AndroidConfig m_androidConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AndroidDeviceManager : public QObject
|
class AndroidDeviceManager : public QObject
|
||||||
@@ -94,13 +99,21 @@ public:
|
|||||||
void updateDevicesList();
|
void updateDevicesList();
|
||||||
void updateDevicesListOnce();
|
void updateDevicesListOnce();
|
||||||
|
|
||||||
|
void startAvd(const ProjectExplorer::IDevice::Ptr &device);
|
||||||
|
void eraseAvd(const ProjectExplorer::IDevice::Ptr &device);
|
||||||
|
|
||||||
|
void setEmulatorArguments();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AndroidDeviceManager(QObject *parent = nullptr);
|
AndroidDeviceManager(QObject *parent = nullptr);
|
||||||
void devicesListUpdated();
|
void devicesListUpdated();
|
||||||
|
void handleAvdRemoved();
|
||||||
|
|
||||||
QFutureWatcher<AndroidDeviceInfoList> m_avdsFutureWatcher;
|
QFutureWatcher<AndroidDeviceInfoList> m_avdsFutureWatcher;
|
||||||
QFutureWatcher<QVector<AndroidDeviceInfo>> m_devicesFutureWatcher;
|
QFutureWatcher<QVector<AndroidDeviceInfo>> m_devicesFutureWatcher;
|
||||||
|
QFutureWatcher<QPair<ProjectExplorer::IDevice::ConstPtr, bool>> m_removeAvdFutureWatcher;
|
||||||
QTimer m_devicesUpdaterTimer;
|
QTimer m_devicesUpdaterTimer;
|
||||||
|
AndroidAvdManager m_avdManager;
|
||||||
AndroidConfig m_androidConfig;
|
AndroidConfig m_androidConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -27,14 +27,12 @@
|
|||||||
|
|
||||||
#include "ui_androidsettingswidget.h"
|
#include "ui_androidsettingswidget.h"
|
||||||
|
|
||||||
#include "androidavdmanager.h"
|
|
||||||
#include "androidconfigurations.h"
|
#include "androidconfigurations.h"
|
||||||
#include "androidconstants.h"
|
#include "androidconstants.h"
|
||||||
#include "androidsdkdownloader.h"
|
#include "androidsdkdownloader.h"
|
||||||
#include "androidsdkmanager.h"
|
#include "androidsdkmanager.h"
|
||||||
#include "androidsdkmanagerwidget.h"
|
#include "androidsdkmanagerwidget.h"
|
||||||
#include "androidtoolchain.h"
|
#include "androidtoolchain.h"
|
||||||
#include "avddialog.h"
|
|
||||||
|
|
||||||
#include <projectexplorer/projectexplorerconstants.h>
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
|
|
||||||
@@ -76,22 +74,8 @@ namespace Android {
|
|||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class AndroidSdkManagerWidget;
|
class AndroidSdkManagerWidget;
|
||||||
class AndroidAvdManager;
|
|
||||||
class SummaryWidget;
|
class SummaryWidget;
|
||||||
|
|
||||||
class AvdModel final : public ListModel<AndroidDeviceInfo>
|
|
||||||
{
|
|
||||||
Q_DECLARE_TR_FUNCTIONS(Android::Internal::AvdModel)
|
|
||||||
|
|
||||||
public:
|
|
||||||
AvdModel();
|
|
||||||
|
|
||||||
QVariant itemData(const AndroidDeviceInfo &info, int column, int role) const final;
|
|
||||||
|
|
||||||
QString avdName(const QModelIndex &index) const;
|
|
||||||
QModelIndex indexForAvdName(const QString &avdName) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AndroidSettingsWidget final : public Core::IOptionsPageWidget
|
class AndroidSettingsWidget final : public Core::IOptionsPageWidget
|
||||||
{
|
{
|
||||||
Q_DECLARE_TR_FUNCTIONS(Android::Internal::AndroidSettingsWidget)
|
Q_DECLARE_TR_FUNCTIONS(Android::Internal::AndroidSettingsWidget)
|
||||||
@@ -114,20 +98,9 @@ private:
|
|||||||
void openNDKDownloadUrl();
|
void openNDKDownloadUrl();
|
||||||
void openOpenJDKDownloadUrl();
|
void openOpenJDKDownloadUrl();
|
||||||
void downloadOpenSslRepo(const bool silent = false);
|
void downloadOpenSslRepo(const bool silent = false);
|
||||||
void addAVD();
|
|
||||||
void avdAdded();
|
|
||||||
void removeAVD();
|
|
||||||
void startAVD();
|
|
||||||
void avdActivated(const QModelIndex &);
|
|
||||||
void editEmulatorArgsAVD();
|
|
||||||
void createKitToggled();
|
void createKitToggled();
|
||||||
|
|
||||||
void updateUI();
|
void updateUI();
|
||||||
void updateAvds();
|
|
||||||
|
|
||||||
void startUpdateAvd();
|
|
||||||
void enableAvdControls();
|
|
||||||
void disableAvdControls();
|
|
||||||
|
|
||||||
void downloadSdk();
|
void downloadSdk();
|
||||||
void addCustomNdkItem();
|
void addCustomNdkItem();
|
||||||
@@ -136,12 +109,7 @@ private:
|
|||||||
Ui_AndroidSettingsWidget m_ui;
|
Ui_AndroidSettingsWidget m_ui;
|
||||||
AndroidSdkManagerWidget *m_sdkManagerWidget = nullptr;
|
AndroidSdkManagerWidget *m_sdkManagerWidget = nullptr;
|
||||||
AndroidConfig m_androidConfig{AndroidConfigurations::currentConfig()};
|
AndroidConfig m_androidConfig{AndroidConfigurations::currentConfig()};
|
||||||
AvdModel m_AVDModel;
|
|
||||||
QFutureWatcher<CreateAvdInfo> m_futureWatcher;
|
|
||||||
|
|
||||||
QFutureWatcher<AndroidDeviceInfoList> m_virtualDevicesWatcher;
|
|
||||||
QString m_lastAddedAvd;
|
|
||||||
AndroidAvdManager m_avdManager{m_androidConfig};
|
|
||||||
AndroidSdkManager m_sdkManager{m_androidConfig};
|
AndroidSdkManager m_sdkManager{m_androidConfig};
|
||||||
AndroidSdkDownloader m_sdkDownloader;
|
AndroidSdkDownloader m_sdkDownloader;
|
||||||
bool m_isInitialReloadDone = false;
|
bool m_isInitialReloadDone = false;
|
||||||
@@ -253,44 +221,6 @@ private:
|
|||||||
QMap<int, RowData> m_validationData;
|
QMap<int, RowData> m_validationData;
|
||||||
};
|
};
|
||||||
|
|
||||||
QModelIndex AvdModel::indexForAvdName(const QString &avdName) const
|
|
||||||
{
|
|
||||||
return findIndex([avdName](const AndroidDeviceInfo &info) { return info.avdname == avdName; });
|
|
||||||
}
|
|
||||||
|
|
||||||
QString AvdModel::avdName(const QModelIndex &index) const
|
|
||||||
{
|
|
||||||
return dataAt(index.row()).avdname;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant AvdModel::itemData(const AndroidDeviceInfo &info, int column, int role) const
|
|
||||||
{
|
|
||||||
if (role != Qt::DisplayRole)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
switch (column) {
|
|
||||||
case 0:
|
|
||||||
return info.avdname;
|
|
||||||
case 1:
|
|
||||||
return info.sdk;
|
|
||||||
case 2:
|
|
||||||
return info.cpuAbi.isEmpty() ? QVariant() : QVariant(info.cpuAbi.first());
|
|
||||||
case 3:
|
|
||||||
return info.avdDevice.isEmpty() ? QVariant("Custom") : info.avdDevice;
|
|
||||||
case 4:
|
|
||||||
return info.avdTarget;
|
|
||||||
case 5:
|
|
||||||
return info.avdSdcardSize;
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
AvdModel::AvdModel()
|
|
||||||
{
|
|
||||||
//: AVD - Android Virtual Device
|
|
||||||
setHeader({tr("AVD Name"), tr("API"), tr("CPU/ABI"), tr("Device Type"), tr("Target"), tr("SD-card Size")});
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidSettingsWidget::showEvent(QShowEvent *event)
|
void AndroidSettingsWidget::showEvent(QShowEvent *event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(event)
|
Q_UNUSED(event)
|
||||||
@@ -432,11 +362,6 @@ AndroidSettingsWidget::AndroidSettingsWidget()
|
|||||||
m_ui.openSslPathChooser->setFilePath(m_androidConfig.openSslLocation());
|
m_ui.openSslPathChooser->setFilePath(m_androidConfig.openSslLocation());
|
||||||
|
|
||||||
m_ui.CreateKitCheckBox->setChecked(m_androidConfig.automaticKitCreation());
|
m_ui.CreateKitCheckBox->setChecked(m_androidConfig.automaticKitCreation());
|
||||||
m_ui.AVDTableView->setModel(&m_AVDModel);
|
|
||||||
m_ui.AVDTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
|
||||||
for (int column : {1, 2, 5})
|
|
||||||
m_ui.AVDTableView->horizontalHeader()->setSectionResizeMode(
|
|
||||||
column, QHeaderView::ResizeToContents);
|
|
||||||
|
|
||||||
const QIcon downloadIcon = Icons::ONLINE.icon();
|
const QIcon downloadIcon = Icons::ONLINE.icon();
|
||||||
m_ui.downloadSDKToolButton->setIcon(downloadIcon);
|
m_ui.downloadSDKToolButton->setIcon(downloadIcon);
|
||||||
@@ -475,24 +400,6 @@ AndroidSettingsWidget::AndroidSettingsWidget()
|
|||||||
|
|
||||||
connect(m_ui.openSslPathChooser, &PathChooser::rawPathChanged,
|
connect(m_ui.openSslPathChooser, &PathChooser::rawPathChanged,
|
||||||
this, &AndroidSettingsWidget::validateOpenSsl);
|
this, &AndroidSettingsWidget::validateOpenSsl);
|
||||||
connect(&m_virtualDevicesWatcher, &QFutureWatcherBase::finished,
|
|
||||||
this, &AndroidSettingsWidget::updateAvds);
|
|
||||||
connect(m_ui.AVDRefreshPushButton, &QAbstractButton::clicked,
|
|
||||||
this, &AndroidSettingsWidget::startUpdateAvd);
|
|
||||||
connect(&m_futureWatcher, &QFutureWatcherBase::finished,
|
|
||||||
this, &AndroidSettingsWidget::avdAdded);
|
|
||||||
connect(m_ui.AVDAddPushButton, &QAbstractButton::clicked,
|
|
||||||
this, &AndroidSettingsWidget::addAVD);
|
|
||||||
connect(m_ui.AVDRemovePushButton, &QAbstractButton::clicked,
|
|
||||||
this, &AndroidSettingsWidget::removeAVD);
|
|
||||||
connect(m_ui.AVDStartPushButton, &QAbstractButton::clicked,
|
|
||||||
this, &AndroidSettingsWidget::startAVD);
|
|
||||||
connect(m_ui.AVDTableView, &QAbstractItemView::activated,
|
|
||||||
this, &AndroidSettingsWidget::avdActivated);
|
|
||||||
connect(m_ui.AVDTableView, &QAbstractItemView::clicked,
|
|
||||||
this, &AndroidSettingsWidget::avdActivated);
|
|
||||||
connect(m_ui.AVDAdvancedOptionsPushButton, &QAbstractButton::clicked,
|
|
||||||
this, &AndroidSettingsWidget::editEmulatorArgsAVD);
|
|
||||||
connect(m_ui.CreateKitCheckBox, &QAbstractButton::toggled,
|
connect(m_ui.CreateKitCheckBox, &QAbstractButton::toggled,
|
||||||
this, &AndroidSettingsWidget::createKitToggled);
|
this, &AndroidSettingsWidget::createKitToggled);
|
||||||
connect(m_ui.downloadNDKToolButton, &QAbstractButton::clicked,
|
connect(m_ui.downloadNDKToolButton, &QAbstractButton::clicked,
|
||||||
@@ -530,38 +437,6 @@ AndroidSettingsWidget::~AndroidSettingsWidget()
|
|||||||
{
|
{
|
||||||
// Deleting m_sdkManagerWidget will cancel all ongoing and pending sdkmanager operations.
|
// Deleting m_sdkManagerWidget will cancel all ongoing and pending sdkmanager operations.
|
||||||
delete m_sdkManagerWidget;
|
delete m_sdkManagerWidget;
|
||||||
m_futureWatcher.waitForFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidSettingsWidget::disableAvdControls()
|
|
||||||
{
|
|
||||||
m_ui.AVDAddPushButton->setEnabled(false);
|
|
||||||
m_ui.AVDTableView->setEnabled(false);
|
|
||||||
m_ui.AVDRemovePushButton->setEnabled(false);
|
|
||||||
m_ui.AVDStartPushButton->setEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidSettingsWidget::enableAvdControls()
|
|
||||||
{
|
|
||||||
m_ui.AVDTableView->setEnabled(true);
|
|
||||||
m_ui.AVDAddPushButton->setEnabled(true);
|
|
||||||
avdActivated(m_ui.AVDTableView->currentIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidSettingsWidget::startUpdateAvd()
|
|
||||||
{
|
|
||||||
disableAvdControls();
|
|
||||||
m_virtualDevicesWatcher.setFuture(m_avdManager.avdList());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidSettingsWidget::updateAvds()
|
|
||||||
{
|
|
||||||
m_AVDModel.setAllData(m_virtualDevicesWatcher.result());
|
|
||||||
if (!m_lastAddedAvd.isEmpty()) {
|
|
||||||
m_ui.AVDTableView->setCurrentIndex(m_AVDModel.indexForAvdName(m_lastAddedAvd));
|
|
||||||
m_lastAddedAvd.clear();
|
|
||||||
}
|
|
||||||
enableAvdControls();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidSettingsWidget::validateJdk()
|
void AndroidSettingsWidget::validateJdk()
|
||||||
@@ -648,7 +523,6 @@ void AndroidSettingsWidget::validateSdk()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
startUpdateAvd();
|
|
||||||
updateNdkList();
|
updateNdkList();
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
@@ -754,80 +628,6 @@ void AndroidSettingsWidget::downloadOpenSslRepo(const bool silent)
|
|||||||
gitCloner->start();
|
gitCloner->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidSettingsWidget::addAVD()
|
|
||||||
{
|
|
||||||
disableAvdControls();
|
|
||||||
CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, &m_sdkManager, m_androidConfig);
|
|
||||||
|
|
||||||
if (!info.isValid()) {
|
|
||||||
enableAvdControls();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_futureWatcher.setFuture(m_avdManager.createAvd(info));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidSettingsWidget::avdAdded()
|
|
||||||
{
|
|
||||||
CreateAvdInfo info = m_futureWatcher.result();
|
|
||||||
if (!info.error.isEmpty()) {
|
|
||||||
enableAvdControls();
|
|
||||||
QMessageBox::critical(this, QApplication::translate("AndroidConfig", "Error Creating AVD"), info.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
startUpdateAvd();
|
|
||||||
m_lastAddedAvd = info.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidSettingsWidget::removeAVD()
|
|
||||||
{
|
|
||||||
disableAvdControls();
|
|
||||||
QString avdName = m_AVDModel.avdName(m_ui.AVDTableView->currentIndex());
|
|
||||||
if (QMessageBox::question(this, tr("Remove Android Virtual Device"),
|
|
||||||
tr("Remove device \"%1\"? This cannot be undone.").arg(avdName),
|
|
||||||
QMessageBox::Yes | QMessageBox::No)
|
|
||||||
== QMessageBox::No) {
|
|
||||||
enableAvdControls();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_avdManager.removeAvd(avdName);
|
|
||||||
startUpdateAvd();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidSettingsWidget::startAVD()
|
|
||||||
{
|
|
||||||
m_avdManager.startAvdAsync(m_AVDModel.avdName(m_ui.AVDTableView->currentIndex()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidSettingsWidget::avdActivated(const QModelIndex &index)
|
|
||||||
{
|
|
||||||
m_ui.AVDRemovePushButton->setEnabled(index.isValid());
|
|
||||||
m_ui.AVDStartPushButton->setEnabled(index.isValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidSettingsWidget::editEmulatorArgsAVD()
|
|
||||||
{
|
|
||||||
const QString helpUrl =
|
|
||||||
"https://developer.android.com/studio/run/emulator-commandline#startup-options";
|
|
||||||
|
|
||||||
QInputDialog dialog(this);
|
|
||||||
dialog.setWindowTitle(tr("Emulator Command-line Startup Options"));
|
|
||||||
dialog.setLabelText(tr("Emulator command-line startup options (<a href=\"%1\">Help Web Page</a>):").arg(helpUrl));
|
|
||||||
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(ProcessArgs::splitArgs(dialog.textValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidSettingsWidget::createKitToggled()
|
void AndroidSettingsWidget::createKitToggled()
|
||||||
{
|
{
|
||||||
m_androidConfig.setAutomaticKitCreation(m_ui.CreateKitCheckBox->isChecked());
|
m_androidConfig.setAutomaticKitCreation(m_ui.CreateKitCheckBox->isChecked());
|
||||||
@@ -840,7 +640,6 @@ void AndroidSettingsWidget::updateUI()
|
|||||||
const bool androidSetupOk = m_androidSummary->allRowsOk();
|
const bool androidSetupOk = m_androidSummary->allRowsOk();
|
||||||
const bool openSslOk = m_openSslSummary->allRowsOk();
|
const bool openSslOk = m_openSslSummary->allRowsOk();
|
||||||
|
|
||||||
m_ui.avdManagerTab->setEnabled(javaSetupOk && androidSetupOk);
|
|
||||||
m_ui.sdkManagerTab->setEnabled(sdkToolsOk);
|
m_ui.sdkManagerTab->setEnabled(sdkToolsOk);
|
||||||
|
|
||||||
const QListWidgetItem *currentItem = m_ui.ndkListWidget->currentItem();
|
const QListWidgetItem *currentItem = m_ui.ndkListWidget->currentItem();
|
||||||
|
@@ -269,142 +269,6 @@
|
|||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="avdManagerTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>AVD Manager</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QTableView" name="AVDTableView">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="selectionMode">
|
|
||||||
<enum>QAbstractItemView::SingleSelection</enum>
|
|
||||||
</property>
|
|
||||||
<property name="selectionBehavior">
|
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
|
||||||
</property>
|
|
||||||
<property name="textElideMode">
|
|
||||||
<enum>Qt::ElideMiddle</enum>
|
|
||||||
</property>
|
|
||||||
<attribute name="horizontalHeaderHighlightSections">
|
|
||||||
<bool>false</bool>
|
|
||||||
</attribute>
|
|
||||||
<attribute name="verticalHeaderVisible">
|
|
||||||
<bool>false</bool>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="AVDStartPushButton">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Start...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="AVDRefreshPushButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Refresh List</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer_2">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeType">
|
|
||||||
<enum>QSizePolicy::Fixed</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>8</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="AVDAddPushButton">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Add...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="AVDRemovePushButton">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Remove</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<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>
|
|
||||||
<widget class="QPushButton" name="AVDAdvancedOptionsPushButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Advanced Options...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="sdkManagerTab">
|
<widget class="QWidget" name="sdkManagerTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>SDK Manager</string>
|
<string>SDK Manager</string>
|
||||||
|
@@ -105,7 +105,8 @@ CreateAvdInfo AvdDialog::gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager
|
|||||||
{
|
{
|
||||||
CreateAvdInfo result;
|
CreateAvdInfo result;
|
||||||
AvdDialog d(minApiLevel, sdkManager, abis, config, parent);
|
AvdDialog d(minApiLevel, sdkManager, abis, config, parent);
|
||||||
if (d.exec() != QDialog::Accepted || !d.isValid())
|
result.cancelled = (d.exec() != QDialog::Accepted);
|
||||||
|
if (result.cancelled || !d.isValid())
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result.systemImage = d.systemImage();
|
result.systemImage = d.systemImage();
|
||||||
|
Reference in New Issue
Block a user