forked from qt-creator/qt-creator
Change device selection mechanism on Android
Currently, on deploy/debug steps on Android, an AndroidDeviceDialog is popped up each time a deployement is done to select a device. This can be avoidable by using Qt Creator DeviceKitAspect to have the list of devices easily selectable from the project mini-menu. This is better than the current way because it: * reduces the time from deployment to running the app * reduces the number of clicks * avoids having to select the same device each time or * if a default device is selected, this avoids having to go to project settings to reset the default device to be able to deploy to a new device. * it looks cleaner and more compatible with Creator. Task-number: QTCREATORBUG-23991 Change-Id: Ida4ab7245c1a3b0ca26c5ccdc9a21a072edf0725 Reviewed-by: Alessandro Portale <alessandro.portale@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
@@ -13,7 +13,6 @@ add_qtc_plugin(Android
|
||||
androiddebugsupport.cpp androiddebugsupport.h
|
||||
androiddeployqtstep.cpp androiddeployqtstep.h
|
||||
androiddevice.cpp androiddevice.h
|
||||
androiddevicedialog.cpp androiddevicedialog.h androiddevicedialog.ui
|
||||
androiddeviceinfo.cpp androiddeviceinfo.h
|
||||
androiderrormessage.cpp androiderrormessage.h
|
||||
androidextralibrarylistmodel.cpp androidextralibrarylistmodel.h
|
||||
|
@@ -33,7 +33,6 @@ HEADERS += \
|
||||
androidmanifesteditor.h \
|
||||
androidmanifesteditorwidget.h \
|
||||
androidmanifestdocument.h \
|
||||
androiddevicedialog.h \
|
||||
androiddeployqtstep.h \
|
||||
certificatesmodel.h \
|
||||
androidpotentialkit.h \
|
||||
@@ -82,7 +81,6 @@ SOURCES += \
|
||||
androidmanifesteditor.cpp \
|
||||
androidmanifesteditorwidget.cpp \
|
||||
androidmanifestdocument.cpp \
|
||||
androiddevicedialog.cpp \
|
||||
androiddeployqtstep.cpp \
|
||||
certificatesmodel.cpp \
|
||||
androidpotentialkit.cpp \
|
||||
@@ -109,7 +107,6 @@ FORMS += \
|
||||
androidsettingswidget.ui \
|
||||
addnewavddialog.ui \
|
||||
androidcreatekeystorecertificate.ui \
|
||||
androiddevicedialog.ui \
|
||||
androidsdkmanagerwidget.ui
|
||||
|
||||
RESOURCES = android.qrc
|
||||
|
@@ -35,9 +35,6 @@ Project {
|
||||
"androiddeployqtstep.h",
|
||||
"androiddebugsupport.cpp",
|
||||
"androiddebugsupport.h",
|
||||
"androiddevicedialog.cpp",
|
||||
"androiddevicedialog.h",
|
||||
"androiddevicedialog.ui",
|
||||
"androiddevice.cpp",
|
||||
"androiddevice.h",
|
||||
"androiddeviceinfo.cpp",
|
||||
|
@@ -29,7 +29,6 @@
|
||||
#include "androiddevice.h"
|
||||
#include "androidmanager.h"
|
||||
#include "androidqtversion.h"
|
||||
#include "androiddevicedialog.h"
|
||||
#include "avddialog.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
@@ -691,6 +690,26 @@ QString AndroidConfig::getAvdName(const QString &serialnumber)
|
||||
return QString::fromLatin1(name).trimmed();
|
||||
}
|
||||
|
||||
QStringList AndroidConfig::getRunningAvdsFromDevices(const QVector<AndroidDeviceInfo> &devs)
|
||||
{
|
||||
QStringList runningDevs;
|
||||
for (const AndroidDeviceInfo &dev : devs) {
|
||||
if (!dev.serialNumber.startsWith("emulator"))
|
||||
continue;
|
||||
QStringList args = AndroidDeviceInfo::adbSelector(dev.serialNumber);
|
||||
args.append({"emu", "avd", "name"});
|
||||
SdkToolResult result = AndroidManager::runAdbCommand(args);
|
||||
const QString stdOut = result.stdOut();
|
||||
if (stdOut.isEmpty())
|
||||
continue; // Not an avd
|
||||
const QStringList outputLines = stdOut.split('\n');
|
||||
if (outputLines.size() > 1)
|
||||
runningDevs.append(outputLines.first());
|
||||
}
|
||||
|
||||
return runningDevs;
|
||||
}
|
||||
|
||||
AndroidConfig::OpenGl AndroidConfig::getOpenGLEnabled(const QString &emulator) const
|
||||
{
|
||||
QDir dir = QDir::home();
|
||||
@@ -1067,54 +1086,6 @@ void AndroidConfigurations::setConfig(const AndroidConfig &devConfigs)
|
||||
emit m_instance->updated();
|
||||
}
|
||||
|
||||
AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(Project *project,
|
||||
int apiLevel, const QStringList &abis)
|
||||
{
|
||||
QString serialNumber;
|
||||
for (const QString &abi : abis) {
|
||||
serialNumber = defaultDevice(project, abi);
|
||||
if (!serialNumber.isEmpty())
|
||||
break;
|
||||
}
|
||||
|
||||
const AndroidDeviceInfo defaultDevice = AndroidDeviceDialog::defaultDeviceInfo(serialNumber);
|
||||
if (defaultDevice.isValid())
|
||||
return defaultDevice;
|
||||
|
||||
AndroidDeviceDialog dialog(apiLevel, abis, serialNumber, Core::ICore::dialogParent());
|
||||
AndroidDeviceInfo info = dialog.showAndGetSelectedDevice();
|
||||
if (dialog.saveDeviceSelection() && info.isValid()) {
|
||||
const QString newSerialNumber = info.type == AndroidDeviceInfo::Hardware ?
|
||||
info.serialNumber : info.avdname;
|
||||
if (!newSerialNumber.isEmpty()) {
|
||||
const QString preferredAbi = AndroidManager::devicePreferredAbi(info.cpuAbi, abis);
|
||||
AndroidConfigurations::setDefaultDevice(project, preferredAbi, newSerialNumber);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
void AndroidConfigurations::clearDefaultDevices(Project *project)
|
||||
{
|
||||
if (m_instance->m_defaultDeviceForAbi.contains(project))
|
||||
m_instance->m_defaultDeviceForAbi.remove(project);
|
||||
}
|
||||
|
||||
void AndroidConfigurations::setDefaultDevice(Project *project, const QString &abi, const QString &serialNumber)
|
||||
{
|
||||
m_instance->m_defaultDeviceForAbi[project][abi] = serialNumber;
|
||||
}
|
||||
|
||||
QString AndroidConfigurations::defaultDevice(Project *project, const QString &abi)
|
||||
{
|
||||
if (!m_instance->m_defaultDeviceForAbi.contains(project))
|
||||
return QString();
|
||||
const QMap<QString, QString> &map = m_instance->m_defaultDeviceForAbi.value(project);
|
||||
if (!map.contains(abi))
|
||||
return QString();
|
||||
return map.value(abi);
|
||||
}
|
||||
|
||||
static bool matchToolChain(const ToolChain *atc, const ToolChain *btc)
|
||||
{
|
||||
if (atc == btc)
|
||||
@@ -1306,15 +1277,6 @@ void AndroidConfigurations::updateAutomaticKitList()
|
||||
qtVersionsForArch[qtAbis.first()].append(qtVersion);
|
||||
}
|
||||
|
||||
DeviceManager *dm = DeviceManager::instance();
|
||||
IDevice::ConstPtr device = dm->find(Constants::ANDROID_DEVICE_ID);
|
||||
if (device.isNull()) {
|
||||
// no device, means no sdk path
|
||||
for (Kit *k : existingKits)
|
||||
KitManager::deregisterKit(k);
|
||||
return;
|
||||
}
|
||||
|
||||
// register new kits
|
||||
const QList<ToolChain *> toolchains = ToolChainManager::toolChains([](const ToolChain *tc) {
|
||||
return tc->isAutoDetected()
|
||||
@@ -1350,20 +1312,20 @@ void AndroidConfigurations::updateAutomaticKitList()
|
||||
ToolChainKitAspect::cToolChain(b));
|
||||
});
|
||||
|
||||
const auto initializeKit = [allLanguages, device, tc, qt](Kit *k) {
|
||||
const auto initializeKit = [allLanguages, tc, qt](Kit *k) {
|
||||
k->setAutoDetected(true);
|
||||
k->setAutoDetectionSource("AndroidConfiguration");
|
||||
DeviceTypeKitAspect::setDeviceTypeId(k, Constants::ANDROID_DEVICE_TYPE);
|
||||
for (ToolChain *tc : allLanguages)
|
||||
ToolChainKitAspect::setToolChain(k, tc);
|
||||
QtKitAspect::setQtVersion(k, qt);
|
||||
DeviceKitAspect::setDevice(k, device);
|
||||
QStringList abis = static_cast<const AndroidQtVersion *>(qt)->androidAbis();
|
||||
Debugger::DebuggerKitAspect::setDebugger(k, findOrRegisterDebugger(tc, abis));
|
||||
|
||||
k->setSticky(ToolChainKitAspect::id(), true);
|
||||
k->setSticky(QtKitAspect::id(), true);
|
||||
k->setSticky(DeviceKitAspect::id(), true);
|
||||
k->setMutable(DeviceKitAspect::id(), true);
|
||||
k->setSticky(DeviceTypeKitAspect::id(), true);
|
||||
|
||||
QString versionStr = QLatin1String("Qt %{Qt:Version}");
|
||||
@@ -1433,14 +1395,10 @@ AndroidConfigurations::AndroidConfigurations()
|
||||
: m_sdkManager(new AndroidSdkManager(m_config))
|
||||
{
|
||||
load();
|
||||
|
||||
connect(SessionManager::instance(), &SessionManager::projectRemoved,
|
||||
this, &AndroidConfigurations::clearDefaultDevices);
|
||||
connect(DeviceManager::instance(), &DeviceManager::devicesLoaded,
|
||||
this, &AndroidConfigurations::updateAndroidDevice);
|
||||
|
||||
m_force32bit = is32BitUserSpace();
|
||||
|
||||
m_instance = this;
|
||||
}
|
||||
|
||||
@@ -1545,11 +1503,13 @@ void AndroidConfigurations::load()
|
||||
|
||||
void AndroidConfigurations::updateAndroidDevice()
|
||||
{
|
||||
// Remove any dummy Android device, because it won't be usable.
|
||||
DeviceManager *const devMgr = DeviceManager::instance();
|
||||
if (m_instance->m_config.adbToolPath().exists())
|
||||
devMgr->addDevice(AndroidDevice::create());
|
||||
else if (devMgr->find(Constants::ANDROID_DEVICE_ID))
|
||||
devMgr->removeDevice(Constants::ANDROID_DEVICE_ID);
|
||||
IDevice::ConstPtr dev = devMgr->find(Constants::ANDROID_DEVICE_ID);
|
||||
if (dev)
|
||||
devMgr->removeDevice(dev->id());
|
||||
|
||||
AndroidDeviceManager::instance()->setupDevicesWatcher();
|
||||
}
|
||||
|
||||
AndroidConfigurations *AndroidConfigurations::m_instance = nullptr;
|
||||
|
@@ -171,6 +171,8 @@ public:
|
||||
|
||||
static Utils::FilePath getJdkPath();
|
||||
|
||||
static QStringList getRunningAvdsFromDevices(const QVector<AndroidDeviceInfo> &devs);
|
||||
|
||||
private:
|
||||
static QString getDeviceProperty(const Utils::FilePath &adbToolPath,
|
||||
const QString &device, const QString &property);
|
||||
@@ -213,10 +215,6 @@ public:
|
||||
static void setConfig(const AndroidConfig &config);
|
||||
static AndroidConfigurations *instance();
|
||||
|
||||
static AndroidDeviceInfo showDeviceDialog(ProjectExplorer::Project *project, int apiLevel, const QStringList &abis);
|
||||
static void setDefaultDevice(ProjectExplorer::Project *project, const QString &abi, const QString &serialNumber); // serial number or avd name
|
||||
static QString defaultDevice(ProjectExplorer::Project *project, const QString &abi); // serial number or avd name
|
||||
static void clearDefaultDevices(ProjectExplorer::Project *project);
|
||||
static void registerNewToolChains();
|
||||
static void registerCustomToolChainsAndDebuggers();
|
||||
static void removeUnusedDebuggers();
|
||||
@@ -240,8 +238,6 @@ private:
|
||||
static AndroidConfigurations *m_instance;
|
||||
AndroidConfig m_config;
|
||||
std::unique_ptr<Internal::AndroidSdkManager> m_sdkManager;
|
||||
|
||||
QMap<ProjectExplorer::Project *, QMap<QString, QString> > m_defaultDeviceForAbi;
|
||||
bool m_force32bit;
|
||||
};
|
||||
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <utils/id.h>
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
@@ -93,5 +94,15 @@ const char NdkLocation[] = "NdkLocation"; // FileName
|
||||
const char SdkLocation[] = "SdkLocation"; // FileName
|
||||
const char AndroidABIs[] = "AndroidABIs"; // QString
|
||||
|
||||
// Android Device
|
||||
const Utils::Id AndroidSerialNumber = "AndroidSerialNumber";
|
||||
const Utils::Id AndroidAvdName = "AndroidAvdName";
|
||||
const Utils::Id AndroidCpuAbi = "AndroidCpuAbi";
|
||||
const Utils::Id AndroidAvdTarget = "AndroidAvdTarget";
|
||||
const Utils::Id AndroidAvdDevice = "AndroidAvdDevice";
|
||||
const Utils::Id AndroidAvdSkin = "AndroidAvdSkin";
|
||||
const Utils::Id AndroidAvdSdcard = "AndroidAvdSdcard";
|
||||
const Utils::Id AndroidSdk = "AndroidSdk";
|
||||
|
||||
} // namespace Constants;
|
||||
} // namespace Android
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include "androidglobal.h"
|
||||
#include "androidavdmanager.h"
|
||||
#include "androidqtversion.h"
|
||||
#include "androiddevice.h"
|
||||
|
||||
#include <coreplugin/fileutils.h>
|
||||
#include <coreplugin/icore.h>
|
||||
@@ -147,14 +148,6 @@ bool AndroidDeployQtStep::init()
|
||||
if (androidDeployQtStep != this)
|
||||
info = androidDeployQtStep->m_deviceInfo;
|
||||
|
||||
if (!info.isValid()) {
|
||||
info = AndroidConfigurations::showDeviceDialog(project(), minTargetApi, m_androidABIs);
|
||||
m_deviceInfo = info; // Keep around for later steps
|
||||
}
|
||||
|
||||
if (!info.isValid()) // aborted
|
||||
return false;
|
||||
|
||||
const BuildSystem *bs = buildSystem();
|
||||
auto selectedAbis = bs->property(Constants::ANDROID_ABIS).toStringList();
|
||||
|
||||
@@ -165,6 +158,40 @@ bool AndroidDeployQtStep::init()
|
||||
if (selectedAbis.isEmpty())
|
||||
selectedAbis.append(bs->extraData(buildKey, Constants::AndroidArch).toString());
|
||||
|
||||
if (!info.isValid()) {
|
||||
const IDevice *dev = DeviceKitAspect::device(kit()).data();
|
||||
info = AndroidDevice::androidDeviceInfoFromIDevice(dev);
|
||||
m_deviceInfo = info; // Keep around for later steps
|
||||
|
||||
if (!info.isValid()) {
|
||||
const QString error = tr("The deployment device \"%1\" is invalid.")
|
||||
.arg(dev->displayName());
|
||||
emit addOutput(error, OutputFormat::Stderr);
|
||||
TaskHub::addTask(DeploymentTask(Task::Error, error));
|
||||
return false;
|
||||
}
|
||||
|
||||
const AndroidDevice *androidDev = static_cast<const AndroidDevice *>(dev);
|
||||
if (androidDev && !androidDev->canSupportAbis(selectedAbis)) {
|
||||
const QString error = tr("The deployment device \"%1\" doesn't support the "
|
||||
"architectures used by the kit.\n"
|
||||
"The kit supports \"%2\", but the device uses \"%3\".")
|
||||
.arg(dev->displayName()).arg(selectedAbis.join(", "))
|
||||
.arg(androidDev->supportedAbis().join(", "));
|
||||
emit addOutput(error, OutputFormat::Stderr);
|
||||
TaskHub::addTask(DeploymentTask(Task::Error, error));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (androidDev && !androidDev->canHandleDeployments()) {
|
||||
const QString error = tr("The deployment device \"%1\" is disconnected.")
|
||||
.arg(dev->displayName());
|
||||
emit addOutput(error, OutputFormat::Stderr);
|
||||
TaskHub::addTask(DeploymentTask(Task::Error, error));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const QtSupport::BaseQtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit());
|
||||
if (qt && qt->supportsMultipleQtAbis() && !selectedAbis.contains(info.cpuAbi.first())) {
|
||||
TaskHub::addTask(DeploymentTask(
|
||||
@@ -500,14 +527,6 @@ void AndroidDeployQtStep::runCommand(const CommandLine &command)
|
||||
QWidget *AndroidDeployQtStep::createConfigWidget()
|
||||
{
|
||||
auto widget = new QWidget;
|
||||
|
||||
auto resetDefaultDevices = new QPushButton(widget);
|
||||
resetDefaultDevices->setText(tr("Reset Default Deployment Devices"));
|
||||
|
||||
connect(resetDefaultDevices, &QAbstractButton::clicked, this, [this] {
|
||||
AndroidConfigurations::clearDefaultDevices(project());
|
||||
});
|
||||
|
||||
auto installCustomApkButton = new QPushButton(widget);
|
||||
installCustomApkButton->setText(tr("Install an APK File"));
|
||||
|
||||
@@ -523,7 +542,6 @@ QWidget *AndroidDeployQtStep::createConfigWidget()
|
||||
|
||||
Layouting::Form builder;
|
||||
builder.addRow(m_uninstallPreviousPackage);
|
||||
builder.addRow(resetDefaultDevices);
|
||||
builder.addRow(installCustomApkButton);
|
||||
builder.attachTo(widget);
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
@@ -24,19 +25,29 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "androiddevice.h"
|
||||
|
||||
#include "androidavdmanager.h"
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidconstants.h"
|
||||
#include "androidsignaloperation.h"
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidmanager.h"
|
||||
|
||||
#include <projectexplorer/devicesupport/devicemanager.h>
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
|
||||
#include <utils/url.h>
|
||||
#include <utils/runextensions.h>
|
||||
|
||||
#include <QLoggingCategory>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
namespace {
|
||||
static Q_LOGGING_CATEGORY(androidDeviceLog, "qtc.android.androiddevice", QtWarningMsg)
|
||||
}
|
||||
|
||||
// interval for updating the list of connected Android devices and emulators
|
||||
constexpr int deviceUpdaterMsInterval = 30000;
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
@@ -48,8 +59,151 @@ AndroidDevice::AndroidDevice()
|
||||
setDisplayType(tr("Android"));
|
||||
setMachineType(IDevice::Hardware);
|
||||
setOsType(Utils::OsTypeOtherUnix);
|
||||
setDeviceState(DeviceConnected);
|
||||
|
||||
setDeviceState(DeviceReadyToUse);
|
||||
addDeviceAction({tr("Refresh"), [](const IDevice::Ptr &device, QWidget *parent) {
|
||||
AndroidDeviceManager::instance()->updateDevicesListOnce();
|
||||
}});
|
||||
}
|
||||
|
||||
IDevice::Ptr AndroidDevice::create()
|
||||
{
|
||||
return IDevice::Ptr(new AndroidDevice);
|
||||
}
|
||||
|
||||
AndroidDeviceInfo AndroidDevice::androidDeviceInfoFromIDevice(const IDevice *dev)
|
||||
{
|
||||
AndroidDeviceInfo info;
|
||||
AndroidDeviceInfo::State state;
|
||||
if (dev->deviceState() == IDevice::DeviceReadyToUse)
|
||||
state = AndroidDeviceInfo::OkState;
|
||||
else if (dev->deviceState() == IDevice::DeviceDisconnected)
|
||||
state = AndroidDeviceInfo::OfflineState;
|
||||
else if (dev->deviceState() == IDevice::DeviceConnected)
|
||||
state = AndroidDeviceInfo::UnAuthorizedState;
|
||||
info.state = state;
|
||||
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();
|
||||
info.type = (dev->machineType() == ProjectExplorer::IDevice::Hardware
|
||||
? AndroidDeviceInfo::Hardware : AndroidDeviceInfo::Emulator);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void AndroidDevice::setAndroidDeviceInfoExtras(IDevice *dev, const AndroidDeviceInfo &info)
|
||||
{
|
||||
dev->setMachineType(info.type == AndroidDeviceInfo::Hardware
|
||||
? ProjectExplorer::IDevice::Hardware
|
||||
: ProjectExplorer::IDevice::Emulator);
|
||||
dev->setDeviceState(deviceStateFromInfo(info.state));
|
||||
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)
|
||||
{
|
||||
return info.type == AndroidDeviceInfo::Hardware
|
||||
? AndroidConfigurations::currentConfig().getProductModel(info.serialNumber)
|
||||
: info.avdname;
|
||||
}
|
||||
|
||||
Utils::Id AndroidDevice::idFromDeviceInfo(const AndroidDeviceInfo &info)
|
||||
{
|
||||
const QString id = (info.type == AndroidDeviceInfo::Hardware ? info.serialNumber
|
||||
: info.avdname);
|
||||
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);
|
||||
}
|
||||
|
||||
IDevice::DeviceState AndroidDevice::deviceStateFromInfo(AndroidDeviceInfo::State state)
|
||||
{
|
||||
if (state == AndroidDeviceInfo::OkState)
|
||||
return IDevice::DeviceReadyToUse;
|
||||
if (state == AndroidDeviceInfo::OfflineState)
|
||||
return IDevice::DeviceDisconnected;
|
||||
return IDevice::DeviceConnected;
|
||||
}
|
||||
|
||||
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;
|
||||
const bool isTheirsArm = abis.contains(ANDROID_ABI_ARMEABI_V7A)
|
||||
|| 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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return extraData(Constants::AndroidSerialNumber).toString();
|
||||
}
|
||||
|
||||
QString AndroidDevice::avdName() const
|
||||
{
|
||||
return extraData(Constants::AndroidAvdName).toString();
|
||||
}
|
||||
|
||||
int AndroidDevice::sdkLevel() const
|
||||
{
|
||||
return extraData(Constants::AndroidSdk).toInt();
|
||||
}
|
||||
|
||||
IDevice::DeviceInfo AndroidDevice::deviceInformation() const
|
||||
@@ -80,9 +234,128 @@ QUrl AndroidDevice::toolControlChannel(const ControlChannelHint &) const
|
||||
return url;
|
||||
}
|
||||
|
||||
void AndroidDeviceManager::updateDevicesList()
|
||||
{
|
||||
connect(&m_devicesUpdaterTimer, &QTimer::timeout, this, [this]() {
|
||||
updateDevicesListOnce();
|
||||
});
|
||||
updateDevicesListOnce();
|
||||
m_devicesUpdaterTimer.start(deviceUpdaterMsInterval);
|
||||
}
|
||||
|
||||
void AndroidDeviceManager::updateDevicesListOnce()
|
||||
{
|
||||
if (!m_avdsFutureWatcher.isRunning() && m_androidConfig.adbToolPath().exists()) {
|
||||
m_avdsFutureWatcher.setFuture((new AndroidAvdManager)->avdList());
|
||||
m_devicesFutureWatcher.setFuture(Utils::runAsync([this]() {
|
||||
return m_androidConfig.connectedDevices();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidDeviceManager::setupDevicesWatcher()
|
||||
{
|
||||
// The call to avdmanager is always slower than the call to adb devices,
|
||||
// so connecting the slot to the slower call should be enough.
|
||||
connect(&m_avdsFutureWatcher, &QFutureWatcherBase::finished,
|
||||
this, &AndroidDeviceManager::devicesListUpdated);
|
||||
updateDevicesList();
|
||||
}
|
||||
|
||||
void AndroidDeviceManager::devicesListUpdated()
|
||||
{
|
||||
QVector<AndroidDeviceInfo> connectedDevicesInfos;
|
||||
connectedDevicesInfos = m_devicesFutureWatcher.result();
|
||||
|
||||
// For checking the state of avds, since running avds are assigned a serial number of
|
||||
// the form emulator-xxxx, thus we have to manually check for the names.
|
||||
const QStringList runningAvds = m_androidConfig.getRunningAvdsFromDevices(connectedDevicesInfos);
|
||||
|
||||
AndroidDeviceInfoList devices = m_avdsFutureWatcher.result();
|
||||
const QSet<QString> startedAvds = Utils::transform<QSet>(connectedDevicesInfos,
|
||||
&AndroidDeviceInfo::avdname);
|
||||
for (const AndroidDeviceInfo &dev : devices)
|
||||
if (!startedAvds.contains(dev.avdname))
|
||||
connectedDevicesInfos << dev;
|
||||
|
||||
DeviceManager *const devMgr = DeviceManager::instance();
|
||||
|
||||
QVector<IDevice::ConstPtr> existingDevs;
|
||||
QVector<IDevice::ConstPtr> connectedDevs;
|
||||
|
||||
for (int i = 0; i < devMgr->deviceCount(); ++i) {
|
||||
const IDevice::ConstPtr dev = devMgr->deviceAt(i);
|
||||
if (dev->id().toString().startsWith(Constants::ANDROID_DEVICE_ID)) {
|
||||
existingDevs.append(dev);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto item : connectedDevicesInfos) {
|
||||
const Utils::Id deviceId = AndroidDevice::idFromDeviceInfo(item);
|
||||
const QString displayName = AndroidDevice::displayNameFromInfo(item);
|
||||
IDevice::ConstPtr dev = devMgr->find(deviceId);
|
||||
if (!dev.isNull()) {
|
||||
if (dev->displayName() == displayName) {
|
||||
IDevice::DeviceState newState;
|
||||
// If an AVD is not already running set its state to Connected instead of
|
||||
// ReadyToUse.
|
||||
if (dev->machineType() == IDevice::Emulator && !runningAvds.contains(displayName))
|
||||
newState = IDevice::DeviceConnected;
|
||||
else
|
||||
newState = AndroidDevice::deviceStateFromInfo(item.state);
|
||||
if (dev->deviceState() != newState) {
|
||||
qCDebug(androidDeviceLog, "Device id \"%s\" changed its state.",
|
||||
dev->id().toString().toUtf8().data());
|
||||
devMgr->setDeviceState(dev->id(), newState);
|
||||
}
|
||||
connectedDevs.append(dev);
|
||||
continue;
|
||||
} else {
|
||||
// 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.
|
||||
devMgr->removeDevice(dev->id());
|
||||
}
|
||||
}
|
||||
|
||||
AndroidDevice *newDev = new AndroidDevice();
|
||||
newDev->setupId(IDevice::AutoDetected, deviceId);
|
||||
newDev->setDisplayName(displayName);
|
||||
AndroidDevice::setAndroidDeviceInfoExtras(newDev, item);
|
||||
qCDebug(androidDeviceLog, "Registering new Android device id \"%s\".",
|
||||
newDev->id().toString().toUtf8().data());
|
||||
const IDevice::ConstPtr constNewDev = IDevice::ConstPtr(newDev);
|
||||
devMgr->addDevice(constNewDev);
|
||||
connectedDevs.append(constNewDev);
|
||||
}
|
||||
|
||||
// Set devices no longer connected to disconnected state.
|
||||
for (const IDevice::ConstPtr dev : existingDevs) {
|
||||
if (dev->id() != Constants::ANDROID_DEVICE_ID && !connectedDevs.contains(dev)
|
||||
&& dev->deviceState() != IDevice::DeviceDisconnected) {
|
||||
qCDebug(androidDeviceLog, "Device id \"%s\" is no longer connected.",
|
||||
dev->id().toString().toUtf8().data());
|
||||
devMgr->setDeviceState(dev->id(), IDevice::DeviceDisconnected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AndroidDeviceManager *AndroidDeviceManager::instance()
|
||||
{
|
||||
static AndroidDeviceManager obj;
|
||||
return &obj;
|
||||
}
|
||||
|
||||
AndroidDeviceManager::AndroidDeviceManager(QObject *parent)
|
||||
: m_androidConfig(AndroidConfigurations::currentConfig())
|
||||
{
|
||||
connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() {
|
||||
m_devicesUpdaterTimer.stop();
|
||||
m_avdsFutureWatcher.waitForFinished();
|
||||
m_devicesFutureWatcher.waitForFinished();
|
||||
});
|
||||
}
|
||||
|
||||
// Factory
|
||||
|
||||
AndroidDeviceFactory::AndroidDeviceFactory()
|
||||
: ProjectExplorer::IDeviceFactory(Constants::ANDROID_DEVICE_TYPE)
|
||||
{
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
@@ -25,9 +26,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "androidconfigurations.h"
|
||||
#include "androiddeviceinfo.h"
|
||||
|
||||
#include <projectexplorer/devicesupport/idevice.h>
|
||||
#include <projectexplorer/devicesupport/idevicefactory.h>
|
||||
|
||||
#include <QFutureWatcher>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
@@ -36,17 +43,32 @@ class AndroidDevice final : public ProjectExplorer::IDevice
|
||||
Q_DECLARE_TR_FUNCTIONS(Android::Internal::AndroidDevice)
|
||||
|
||||
public:
|
||||
static IDevice::Ptr create() { return IDevice::Ptr(new AndroidDevice); }
|
||||
|
||||
private:
|
||||
AndroidDevice();
|
||||
|
||||
ProjectExplorer::IDevice::DeviceInfo deviceInformation() const override;
|
||||
static IDevice::Ptr create();
|
||||
static AndroidDeviceInfo androidDeviceInfoFromIDevice(const IDevice *dev);
|
||||
static void setAndroidDeviceInfoExtras(IDevice *dev, const AndroidDeviceInfo &info);
|
||||
|
||||
static QString displayNameFromInfo(const AndroidDeviceInfo &info);
|
||||
static Utils::Id idFromDeviceInfo(const AndroidDeviceInfo &info);
|
||||
static Utils::Id idFromAvdInfo(const CreateAvdInfo &info);
|
||||
static IDevice::DeviceState deviceStateFromInfo(AndroidDeviceInfo::State state);
|
||||
|
||||
QStringList supportedAbis() const;
|
||||
bool canSupportAbis(const QStringList &abis) const;
|
||||
|
||||
bool canHandleDeployments() const;
|
||||
|
||||
bool isValid() const;
|
||||
QString serialNumber() const;
|
||||
QString avdName() const;
|
||||
int sdkLevel() const;
|
||||
|
||||
private:
|
||||
ProjectExplorer::IDevice::DeviceInfo deviceInformation() const override;
|
||||
ProjectExplorer::IDeviceWidget *createWidget() override;
|
||||
bool canAutoDetectPorts() const override;
|
||||
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override;
|
||||
|
||||
QUrl toolControlChannel(const ControlChannelHint &) const override;
|
||||
};
|
||||
|
||||
@@ -56,5 +78,23 @@ public:
|
||||
AndroidDeviceFactory();
|
||||
};
|
||||
|
||||
class AndroidDeviceManager : public QObject
|
||||
{
|
||||
public:
|
||||
static AndroidDeviceManager *instance();
|
||||
void setupDevicesWatcher();
|
||||
void updateDevicesList();
|
||||
void updateDevicesListOnce();
|
||||
|
||||
private:
|
||||
AndroidDeviceManager(QObject *parent = nullptr);
|
||||
void devicesListUpdated();
|
||||
|
||||
QFutureWatcher<AndroidDeviceInfoList> m_avdsFutureWatcher;
|
||||
QFutureWatcher<QVector<AndroidDeviceInfo>> m_devicesFutureWatcher;
|
||||
QTimer m_devicesUpdaterTimer;
|
||||
AndroidConfig m_androidConfig;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
||||
|
@@ -1,636 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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
|
||||
** 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.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "androiddevicedialog.h"
|
||||
#include "androidmanager.h"
|
||||
#include "androidavdmanager.h"
|
||||
#include "avddialog.h"
|
||||
#include "ui_androiddevicedialog.h"
|
||||
|
||||
#include <utils/environment.h>
|
||||
#include <utils/progressindicator.h>
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QToolTip>
|
||||
|
||||
using namespace Android;
|
||||
using namespace Android::Internal;
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
QVector<AndroidDeviceInfo> AndroidDeviceDialog::m_connectedDevices = {};
|
||||
|
||||
// yeah, writing tree models is fun!
|
||||
class AndroidDeviceModelNode
|
||||
{
|
||||
public:
|
||||
AndroidDeviceModelNode(AndroidDeviceModelNode *parent, const AndroidDeviceInfo &info, const QString &incompatibleReason = QString())
|
||||
: m_parent(parent), m_info(info), m_incompatibleReason(incompatibleReason)
|
||||
{
|
||||
if (m_parent)
|
||||
m_parent->m_children.append(this);
|
||||
}
|
||||
|
||||
AndroidDeviceModelNode(AndroidDeviceModelNode *parent, const QString &displayName)
|
||||
: m_parent(parent), m_displayName(displayName)
|
||||
{
|
||||
if (m_parent)
|
||||
m_parent->m_children.append(this);
|
||||
}
|
||||
|
||||
~AndroidDeviceModelNode()
|
||||
{
|
||||
if (m_parent)
|
||||
m_parent->m_children.removeOne(this);
|
||||
QList<AndroidDeviceModelNode *> children = m_children;
|
||||
qDeleteAll(children);
|
||||
}
|
||||
|
||||
AndroidDeviceModelNode *parent() const
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
QList<AndroidDeviceModelNode *> children() const
|
||||
{
|
||||
return m_children;
|
||||
}
|
||||
|
||||
AndroidDeviceInfo deviceInfo() const
|
||||
{
|
||||
return m_info;
|
||||
}
|
||||
|
||||
QString displayName() const
|
||||
{
|
||||
return m_displayName;
|
||||
}
|
||||
|
||||
QString incompatibleReason() const
|
||||
{
|
||||
return m_incompatibleReason;
|
||||
}
|
||||
|
||||
private:
|
||||
AndroidDeviceModelNode *m_parent;
|
||||
AndroidDeviceInfo m_info;
|
||||
QString m_incompatibleReason;
|
||||
QString m_displayName;
|
||||
QList<AndroidDeviceModelNode *> m_children;
|
||||
};
|
||||
|
||||
class AndroidDeviceModelDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AndroidDeviceModelDelegate(QObject * parent = nullptr)
|
||||
: QStyledItemDelegate(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~AndroidDeviceModelDelegate() override = default;
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
|
||||
{
|
||||
QStyleOptionViewItem opt = option;
|
||||
initStyleOption(&opt, index);
|
||||
painter->save();
|
||||
|
||||
auto node = static_cast<AndroidDeviceModelNode *>(index.internalPointer());
|
||||
AndroidDeviceInfo device = node->deviceInfo();
|
||||
|
||||
painter->setPen(Qt::NoPen);
|
||||
|
||||
// Paint Background
|
||||
QPalette palette = opt.palette; // we always draw enabled
|
||||
palette.setCurrentColorGroup(QPalette::Active);
|
||||
bool selected = opt.state & QStyle::State_Selected;
|
||||
QColor backgroundColor = selected ? palette.highlight().color()
|
||||
: palette.window().color();
|
||||
painter->setBrush(backgroundColor);
|
||||
|
||||
painter->drawRect(0, opt.rect.top(), opt.rect.width() + opt.rect.left(), opt.rect.height());
|
||||
|
||||
QColor textColor;
|
||||
// Set Text Color
|
||||
if (opt.state & QStyle::State_Selected)
|
||||
textColor = palette.highlightedText().color();
|
||||
else
|
||||
textColor = palette.text().color();
|
||||
painter->setPen(textColor);
|
||||
|
||||
if (!node->displayName().isEmpty()) { // Title
|
||||
// We have a top level node
|
||||
QFont font = opt.font;
|
||||
font.setPointSizeF(font.pointSizeF() * 1.2);
|
||||
font.setBold(true);
|
||||
|
||||
QFontMetrics fm(font);
|
||||
painter->setFont(font);
|
||||
int top = (opt.rect.bottom() + opt.rect.top() - fm.height()) / 2 + fm.ascent();
|
||||
painter->drawText(6, top, node->displayName());
|
||||
} else {
|
||||
QIcon icon(device.type == AndroidDeviceInfo::Hardware ? QLatin1String(":/projectexplorer/images/MaemoDevice.png")
|
||||
: QLatin1String(":/projectexplorer/images/Simulator.png"));
|
||||
int size = opt.rect.bottom() - opt.rect.top() - 12;
|
||||
QPixmap pixmap = icon.pixmap(size, size);
|
||||
painter->drawPixmap(6 + (size - pixmap.width()) / 2, opt.rect.top() + 6 + (size - pixmap.width()) / 2, pixmap);
|
||||
|
||||
QFontMetrics fm(opt.font);
|
||||
// TopLeft
|
||||
QString topLeft;
|
||||
if (device.type == AndroidDeviceInfo::Hardware)
|
||||
topLeft = AndroidConfigurations::currentConfig().getProductModel(device.serialNumber);
|
||||
else
|
||||
topLeft = device.avdname;
|
||||
painter->drawText(size + 12, 2 + opt.rect.top() + fm.ascent(), topLeft);
|
||||
|
||||
|
||||
// topRight
|
||||
auto drawTopRight = [&](const QString text, const QFontMetrics &fm) {
|
||||
painter->drawText(opt.rect.right() - fm.horizontalAdvance(text) - 6 , 2 + opt.rect.top() + fm.ascent(), text);
|
||||
};
|
||||
|
||||
if (device.type == AndroidDeviceInfo::Hardware) {
|
||||
drawTopRight(device.serialNumber, fm);
|
||||
} else {
|
||||
AndroidConfig::OpenGl openGl = AndroidConfigurations::currentConfig().getOpenGLEnabled(device.avdname);
|
||||
if (openGl == AndroidConfig::OpenGl::Enabled) {
|
||||
drawTopRight(tr("OpenGL enabled"), fm);
|
||||
} else if (openGl == AndroidConfig::OpenGl::Disabled) {
|
||||
QFont font = painter->font();
|
||||
font.setBold(true);
|
||||
painter->setFont(font);
|
||||
QFontMetrics fmBold(font);
|
||||
drawTopRight(tr("OpenGL disabled"), fmBold);
|
||||
font.setBold(false);
|
||||
painter->setFont(font);
|
||||
}
|
||||
}
|
||||
|
||||
// Directory
|
||||
QColor mix;
|
||||
mix.setRgbF(0.7 * textColor.redF() + 0.3 * backgroundColor.redF(),
|
||||
0.7 * textColor.greenF() + 0.3 * backgroundColor.greenF(),
|
||||
0.7 * textColor.blueF() + 0.3 * backgroundColor.blueF());
|
||||
painter->setPen(mix);
|
||||
|
||||
QString lineText;
|
||||
if (node->incompatibleReason().isEmpty()) {
|
||||
lineText = AndroidManager::androidNameForApiLevel(device.sdk) + QLatin1String(" ");
|
||||
lineText += AndroidDeviceDialog::tr("ABI:") + device.cpuAbi.join(QLatin1Char(' '));
|
||||
} else {
|
||||
lineText = node->incompatibleReason();
|
||||
QFont f = painter->font();
|
||||
f.setBold(true);
|
||||
painter->setFont(f);
|
||||
}
|
||||
painter->drawText(size + 12, opt.rect.top() + fm.ascent() + fm.height() + 6, lineText);
|
||||
}
|
||||
|
||||
// Separator lines
|
||||
painter->setPen(QColor::fromRgb(150,150,150));
|
||||
painter->drawLine(0, opt.rect.bottom(), opt.rect.right(), opt.rect.bottom());
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
|
||||
{
|
||||
QStyleOptionViewItem opt = option;
|
||||
initStyleOption(&opt, index);
|
||||
|
||||
QFontMetrics fm(option.font);
|
||||
QSize s;
|
||||
s.setWidth(option.rect.width());
|
||||
s.setHeight(fm.height() * 2 + 10);
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
class AndroidDeviceModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AndroidDeviceModel(int apiLevel, const QStringList &abis);
|
||||
QModelIndex index(int row, int column,
|
||||
const QModelIndex &parent = QModelIndex()) const override;
|
||||
QModelIndex parent(const QModelIndex &child) const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
|
||||
AndroidDeviceInfo device(QModelIndex index);
|
||||
void setDevices(const QVector<AndroidDeviceInfo> &devices);
|
||||
|
||||
QModelIndex indexFor(AndroidDeviceInfo::AndroidDeviceType type, const QString &serial);
|
||||
private:
|
||||
int m_apiLevel;
|
||||
QStringList m_abis;
|
||||
AndroidDeviceModelNode *m_root;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
/////////////////
|
||||
// AndroidDeviceModel
|
||||
/////////////////
|
||||
AndroidDeviceModel::AndroidDeviceModel(int apiLevel, const QStringList &abis)
|
||||
: m_apiLevel(apiLevel), m_abis(abis), m_root(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
QModelIndex AndroidDeviceModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (column != 0)
|
||||
return QModelIndex();
|
||||
|
||||
if (!m_root)
|
||||
return QModelIndex();
|
||||
|
||||
if (!parent.isValid()) {
|
||||
if (row < 0 || row >= m_root->children().count())
|
||||
return QModelIndex();
|
||||
return createIndex(row, column, m_root->children().at(row));
|
||||
}
|
||||
|
||||
auto node = static_cast<AndroidDeviceModelNode *>(parent.internalPointer());
|
||||
if (row < node->children().count())
|
||||
return createIndex(row, column, node->children().at(row));
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex AndroidDeviceModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
if (!child.isValid())
|
||||
return QModelIndex();
|
||||
if (!m_root)
|
||||
return QModelIndex();
|
||||
auto node = static_cast<AndroidDeviceModelNode *>(child.internalPointer());
|
||||
if (node == m_root)
|
||||
return QModelIndex();
|
||||
AndroidDeviceModelNode *parent = node->parent();
|
||||
|
||||
if (parent == m_root)
|
||||
return QModelIndex();
|
||||
|
||||
AndroidDeviceModelNode *grandParent = parent->parent();
|
||||
return createIndex(grandParent->children().indexOf(parent), 0, parent);
|
||||
}
|
||||
|
||||
int AndroidDeviceModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (!m_root)
|
||||
return 0;
|
||||
if (!parent.isValid())
|
||||
return m_root->children().count();
|
||||
auto node = static_cast<AndroidDeviceModelNode *>(parent.internalPointer());
|
||||
return node->children().count();
|
||||
}
|
||||
|
||||
int AndroidDeviceModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant AndroidDeviceModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
auto node = static_cast<AndroidDeviceModelNode *>(index.internalPointer());
|
||||
if (!node)
|
||||
return QVariant();
|
||||
return node->deviceInfo().serialNumber;
|
||||
}
|
||||
|
||||
Qt::ItemFlags AndroidDeviceModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
auto node = static_cast<AndroidDeviceModelNode *>(index.internalPointer());
|
||||
if (node)
|
||||
if (node->displayName().isEmpty() && node->incompatibleReason().isEmpty())
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
|
||||
return Qt::NoItemFlags;
|
||||
}
|
||||
|
||||
AndroidDeviceInfo AndroidDeviceModel::device(QModelIndex index)
|
||||
{
|
||||
auto node = static_cast<AndroidDeviceModelNode *>(index.internalPointer());
|
||||
if (!node)
|
||||
return AndroidDeviceInfo();
|
||||
return node->deviceInfo();
|
||||
}
|
||||
|
||||
void AndroidDeviceModel::setDevices(const QVector<AndroidDeviceInfo> &devices)
|
||||
{
|
||||
beginResetModel();
|
||||
delete m_root;
|
||||
m_root = new AndroidDeviceModelNode(nullptr, QString());
|
||||
|
||||
AndroidDeviceModelNode *compatibleDevices = new AndroidDeviceModelNode(m_root, AndroidDeviceDialog::tr("Compatible devices"));
|
||||
AndroidDeviceModelNode *incompatibleDevices = nullptr; // created on demand
|
||||
foreach (const AndroidDeviceInfo &device, devices) {
|
||||
QString error;
|
||||
if (device.state == AndroidDeviceInfo::UnAuthorizedState) {
|
||||
error = AndroidDeviceDialog::tr("Unauthorized. Please check the confirmation dialog on your device %1.")
|
||||
.arg(device.serialNumber);
|
||||
}else if (device.state == AndroidDeviceInfo::OfflineState) {
|
||||
error = AndroidDeviceDialog::tr("Offline. Please check the state of your device %1.")
|
||||
.arg(device.serialNumber);
|
||||
} else if (!AndroidManager::matchedAbis(device.cpuAbi, m_abis)) {
|
||||
error = AndroidDeviceDialog::tr("ABI is incompatible, device supports ABIs: %1.")
|
||||
.arg(device.cpuAbi.join(QLatin1Char(' ')));
|
||||
} else if (device.sdk < m_apiLevel) {
|
||||
error = AndroidDeviceDialog::tr("API Level of device is: %1.")
|
||||
.arg(device.sdk);
|
||||
} else {
|
||||
new AndroidDeviceModelNode(compatibleDevices, device);
|
||||
continue;
|
||||
}
|
||||
if (!incompatibleDevices)
|
||||
incompatibleDevices = new AndroidDeviceModelNode(m_root, AndroidDeviceDialog::tr("Incompatible devices"));
|
||||
new AndroidDeviceModelNode(incompatibleDevices, device, error);
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QModelIndex AndroidDeviceModel::indexFor(AndroidDeviceInfo::AndroidDeviceType type, const QString &serial)
|
||||
{
|
||||
foreach (AndroidDeviceModelNode *topLevelNode, m_root->children()) {
|
||||
QList<AndroidDeviceModelNode *> deviceNodes = topLevelNode->children();
|
||||
for (int i = 0; i < deviceNodes.size(); ++i) {
|
||||
const AndroidDeviceInfo &info = deviceNodes.at(i)->deviceInfo();
|
||||
if (info.type != type)
|
||||
continue;
|
||||
if ((type == AndroidDeviceInfo::Hardware && serial == info.serialNumber)
|
||||
|| (type == AndroidDeviceInfo::Emulator && serial == info.avdname))
|
||||
return createIndex(i, 0, deviceNodes.at(i));
|
||||
}
|
||||
}
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// AndroidDeviceDialog
|
||||
/////////////////
|
||||
|
||||
static inline QString msgConnect()
|
||||
{
|
||||
return AndroidDeviceDialog::tr("<p>Connect an Android device via USB and activate developer mode on it. "
|
||||
"Some devices require the installation of a USB driver.</p>");
|
||||
|
||||
}
|
||||
|
||||
static inline QString msgAdbListDevices()
|
||||
{
|
||||
return AndroidDeviceDialog::tr("<p>The adb tool in the Android SDK lists all connected devices if run via "adb devices".</p>");
|
||||
}
|
||||
|
||||
AndroidDeviceDialog::AndroidDeviceDialog(int apiLevel, const QStringList &abis,
|
||||
const QString &serialNumber, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
m_model(new AndroidDeviceModel(apiLevel, abis)),
|
||||
m_ui(new Ui::AndroidDeviceDialog),
|
||||
m_apiLevel(apiLevel),
|
||||
m_abis(abis),
|
||||
m_defaultDevice(serialNumber),
|
||||
m_avdManager(new AndroidAvdManager)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_ui->deviceView->setModel(m_model);
|
||||
m_ui->deviceView->setItemDelegate(new AndroidDeviceModelDelegate(m_ui->deviceView));
|
||||
m_ui->deviceView->setHeaderHidden(true);
|
||||
m_ui->deviceView->setRootIsDecorated(false);
|
||||
m_ui->deviceView->setUniformRowHeights(true);
|
||||
m_ui->deviceView->setExpandsOnDoubleClick(false);
|
||||
|
||||
m_ui->defaultDeviceCheckBox->setText(tr("Always use this device for this project"));
|
||||
|
||||
m_ui->noDeviceFoundLabel->setText(QLatin1String("<p align=\"center\"><span style=\" font-size:16pt;\">")
|
||||
+ tr("No Device Found") + QLatin1String("</span></p><br/>")
|
||||
+ msgConnect() + QLatin1String("<br/>")
|
||||
+ msgAdbListDevices());
|
||||
connect(m_ui->missingLabel, &QLabel::linkActivated,
|
||||
this, &AndroidDeviceDialog::showHelp);
|
||||
|
||||
connect(m_ui->refreshDevicesButton, &QAbstractButton::clicked,
|
||||
this, &AndroidDeviceDialog::refreshDeviceList);
|
||||
|
||||
connect(m_ui->createAVDButton, &QAbstractButton::clicked,
|
||||
this, &AndroidDeviceDialog::createAvd);
|
||||
connect(m_ui->deviceView, &QAbstractItemView::doubleClicked,
|
||||
this, &QDialog::accept);
|
||||
|
||||
connect(&m_futureWatcherAddDevice, &QFutureWatcherBase::finished,
|
||||
this, &AndroidDeviceDialog::avdAdded);
|
||||
connect(&m_futureWatcherRefreshDevices, &QFutureWatcherBase::finished,
|
||||
this, &AndroidDeviceDialog::devicesRefreshed);
|
||||
|
||||
connect(m_ui->deviceView->selectionModel(), &QItemSelectionModel::currentChanged,
|
||||
this, &AndroidDeviceDialog::enableOkayButton);
|
||||
|
||||
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||
|
||||
m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Large, this);
|
||||
m_progressIndicator->attachToWidget(m_ui->deviceView);
|
||||
|
||||
if (serialNumber.isEmpty()) {
|
||||
m_ui->lookingForDevice->setVisible(false);
|
||||
m_ui->lookingForDeviceCancel->setVisible(false);
|
||||
} else {
|
||||
m_ui->lookingForDevice->setVisible(true);
|
||||
m_ui->lookingForDevice->setText(tr("Looking for default device <b>%1</b>.").arg(serialNumber));
|
||||
m_ui->lookingForDeviceCancel->setVisible(true);
|
||||
}
|
||||
|
||||
connect(m_ui->lookingForDeviceCancel, &QPushButton::clicked,
|
||||
this, &AndroidDeviceDialog::defaultDeviceClear);
|
||||
}
|
||||
|
||||
AndroidDeviceDialog::~AndroidDeviceDialog()
|
||||
{
|
||||
m_futureWatcherAddDevice.waitForFinished();
|
||||
m_futureWatcherRefreshDevices.waitForFinished();
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
AndroidDeviceInfo AndroidDeviceDialog::defaultDeviceInfo(const QString &serialNumber)
|
||||
{
|
||||
AndroidDeviceDialog::updateConnectedDevicesList();
|
||||
|
||||
if (serialNumber.isEmpty())
|
||||
return {};
|
||||
|
||||
return Utils::findOrDefault(m_connectedDevices, [serialNumber](const AndroidDeviceInfo &info) {
|
||||
return info.serialNumber == serialNumber || info.avdname == serialNumber;
|
||||
});
|
||||
}
|
||||
|
||||
AndroidDeviceInfo AndroidDeviceDialog::showAndGetSelectedDevice()
|
||||
{
|
||||
auto dev = defaultDeviceInfo(m_defaultDevice);
|
||||
if (dev.isValid())
|
||||
return dev;
|
||||
|
||||
refreshDeviceList();
|
||||
|
||||
if (exec() == QDialog::Accepted)
|
||||
return m_model->device(m_ui->deviceView->currentIndex());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool AndroidDeviceDialog::saveDeviceSelection() const
|
||||
{
|
||||
return m_ui->defaultDeviceCheckBox->isChecked();
|
||||
}
|
||||
|
||||
void AndroidDeviceDialog::updateConnectedDevicesList()
|
||||
{
|
||||
m_connectedDevices = AndroidConfig::connectedDevices(AndroidConfigurations::currentConfig()
|
||||
.adbToolPath());
|
||||
}
|
||||
|
||||
void AndroidDeviceDialog::refreshDeviceList()
|
||||
{
|
||||
m_ui->refreshDevicesButton->setEnabled(false);
|
||||
m_progressIndicator->show();
|
||||
m_futureWatcherRefreshDevices.setFuture(m_avdManager->avdList());
|
||||
}
|
||||
|
||||
void AndroidDeviceDialog::devicesRefreshed()
|
||||
{
|
||||
m_progressIndicator->hide();
|
||||
QString serialNumber;
|
||||
AndroidDeviceInfo::AndroidDeviceType deviceType = AndroidDeviceInfo::Hardware;
|
||||
QModelIndex currentIndex = m_ui->deviceView->currentIndex();
|
||||
if (currentIndex.isValid()) { // save currently selected index
|
||||
AndroidDeviceInfo info = m_model->device(currentIndex);
|
||||
deviceType = info.type;
|
||||
serialNumber = deviceType == AndroidDeviceInfo::Hardware ? info.serialNumber : info.avdname;
|
||||
}
|
||||
|
||||
AndroidDeviceInfoList devices = m_futureWatcherRefreshDevices.result();
|
||||
QSet<QString> startedAvds = Utils::transform<QSet>(m_connectedDevices,
|
||||
&AndroidDeviceInfo::avdname);
|
||||
|
||||
for (const AndroidDeviceInfo &dev : devices)
|
||||
if (!startedAvds.contains(dev.avdname))
|
||||
m_connectedDevices << dev;
|
||||
|
||||
m_model->setDevices(m_connectedDevices);
|
||||
|
||||
m_ui->deviceView->expand(m_model->index(0, 0));
|
||||
if (m_model->rowCount() > 1) // we have a incompatible device node
|
||||
m_ui->deviceView->expand(m_model->index(1, 0));
|
||||
|
||||
// Smartly select a index
|
||||
QModelIndex newIndex;
|
||||
if (!m_defaultDevice.isEmpty()) {
|
||||
newIndex = m_model->indexFor(AndroidDeviceInfo::Hardware, m_defaultDevice);
|
||||
if (!newIndex.isValid())
|
||||
newIndex = m_model->indexFor(AndroidDeviceInfo::Emulator, m_defaultDevice);
|
||||
if (!newIndex.isValid()) // not found the default device
|
||||
defaultDeviceClear();
|
||||
}
|
||||
|
||||
if (!newIndex.isValid() && !m_avdNameFromAdd.isEmpty()) {
|
||||
newIndex = m_model->indexFor(AndroidDeviceInfo::Emulator, m_avdNameFromAdd);
|
||||
m_avdNameFromAdd.clear();
|
||||
}
|
||||
|
||||
if (!newIndex.isValid() && !serialNumber.isEmpty())
|
||||
newIndex = m_model->indexFor(deviceType, serialNumber);
|
||||
|
||||
if (!newIndex.isValid() && !m_connectedDevices.isEmpty()) {
|
||||
AndroidDeviceInfo info = m_connectedDevices.first();
|
||||
const QString &name = info.type == AndroidDeviceInfo::Hardware ? info.serialNumber : info.avdname;
|
||||
newIndex = m_model->indexFor(info.type, name);
|
||||
}
|
||||
|
||||
m_ui->deviceView->setCurrentIndex(newIndex);
|
||||
|
||||
m_ui->stackedWidget->setCurrentIndex(m_connectedDevices.isEmpty() ? 1 : 0);
|
||||
|
||||
m_ui->refreshDevicesButton->setEnabled(true);
|
||||
m_connectedDevices.clear();
|
||||
}
|
||||
|
||||
void AndroidDeviceDialog::createAvd()
|
||||
{
|
||||
m_ui->createAVDButton->setEnabled(false);
|
||||
CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, AndroidConfigurations::sdkManager(),
|
||||
AndroidConfigurations::currentConfig(), m_apiLevel, m_abis);
|
||||
|
||||
if (!info.isValid()) {
|
||||
m_ui->createAVDButton->setEnabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
m_futureWatcherAddDevice.setFuture(m_avdManager->createAvd(info));
|
||||
}
|
||||
|
||||
void AndroidDeviceDialog::avdAdded()
|
||||
{
|
||||
m_ui->createAVDButton->setEnabled(true);
|
||||
CreateAvdInfo info = m_futureWatcherAddDevice.result();
|
||||
if (!info.error.isEmpty()) {
|
||||
QMessageBox::critical(this, QApplication::translate("AndroidConfig", "Error Creating AVD"), info.error);
|
||||
return;
|
||||
}
|
||||
|
||||
m_avdNameFromAdd = info.name;
|
||||
refreshDeviceList();
|
||||
}
|
||||
|
||||
void AndroidDeviceDialog::enableOkayButton()
|
||||
{
|
||||
AndroidDeviceModelNode *node = static_cast<AndroidDeviceModelNode *>(m_ui->deviceView->currentIndex().internalPointer());
|
||||
bool enable = node && (!node->deviceInfo().serialNumber.isEmpty() || !node->deviceInfo().avdname.isEmpty());
|
||||
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enable);
|
||||
}
|
||||
|
||||
void AndroidDeviceDialog::showHelp()
|
||||
{
|
||||
QPoint pos = m_ui->missingLabel->pos();
|
||||
pos = m_ui->missingLabel->parentWidget()->mapToGlobal(pos);
|
||||
QToolTip::showText(pos, msgConnect() + msgAdbListDevices(), this);
|
||||
}
|
||||
|
||||
void AndroidDeviceDialog::defaultDeviceClear()
|
||||
{
|
||||
m_ui->lookingForDevice->setVisible(false);
|
||||
m_ui->lookingForDeviceCancel->setVisible(false);
|
||||
m_defaultDevice.clear();
|
||||
}
|
||||
|
||||
#include "androiddevicedialog.moc"
|
@@ -1,88 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** 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
|
||||
** 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.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "androidconfigurations.h"
|
||||
|
||||
#include <QVector>
|
||||
#include <QDialog>
|
||||
#include <QFutureWatcher>
|
||||
#include <QTime>
|
||||
|
||||
#include <memory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QModelIndex;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Utils { class ProgressIndicator; }
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
class AndroidAvdManager;
|
||||
class AndroidDeviceModel;
|
||||
namespace Ui { class AndroidDeviceDialog; }
|
||||
|
||||
class AndroidDeviceDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AndroidDeviceDialog(int apiLevel, const QStringList &abis,
|
||||
const QString &serialNumber, QWidget *parent = nullptr);
|
||||
~AndroidDeviceDialog() override;
|
||||
|
||||
AndroidDeviceInfo showAndGetSelectedDevice();
|
||||
static AndroidDeviceInfo defaultDeviceInfo(const QString &serialNumber);
|
||||
|
||||
bool saveDeviceSelection() const;
|
||||
|
||||
private:
|
||||
void refreshDeviceList();
|
||||
void createAvd();
|
||||
void showHelp();
|
||||
void avdAdded();
|
||||
void devicesRefreshed();
|
||||
void enableOkayButton();
|
||||
void defaultDeviceClear();
|
||||
static void updateConnectedDevicesList();
|
||||
|
||||
AndroidDeviceModel *m_model;
|
||||
Ui::AndroidDeviceDialog *m_ui;
|
||||
Utils::ProgressIndicator *m_progressIndicator;
|
||||
int m_apiLevel;
|
||||
QStringList m_abis;
|
||||
QString m_avdNameFromAdd;
|
||||
QString m_defaultDevice;
|
||||
static QVector<AndroidDeviceInfo> m_connectedDevices;
|
||||
std::unique_ptr<AndroidAvdManager> m_avdManager;
|
||||
QFutureWatcher<CreateAvdInfo> m_futureWatcherAddDevice;
|
||||
QFutureWatcher<AndroidDeviceInfoList> m_futureWatcherRefreshDevices;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
@@ -1,215 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Android::Internal::AndroidDeviceDialog</class>
|
||||
<widget class="QDialog" name="Android::Internal::AndroidDeviceDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>788</width>
|
||||
<height>466</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Select Android Device</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="6" column="2">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="defaultDeviceCheckBox">
|
||||
<property name="toolTip">
|
||||
<string>This can be later reset in deployment settings in the Projects mode.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Always use this device for architecture %1 for this project</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="devicesPage">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<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 row="1" column="0" colspan="2">
|
||||
<widget class="QTreeView" name="deviceView">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>600</width>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QLabel" name="missingLabel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><a href="aaa"><span style=" text-decoration: underline; color:#0057ae;">My device is missing</span></a></p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lookingForDevice">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="lookingForDeviceCancel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="noDevicesPage">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<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 row="0" column="0">
|
||||
<widget class="QLabel" name="noDeviceFoundLabel">
|
||||
<property name="text">
|
||||
<string notr="true"><html><head/><body><p><br/></p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="4">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QPushButton" name="createAVDButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create Android Virtual Device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QPushButton" name="refreshDevicesButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Refresh Device List</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>lookingForDeviceCancel</tabstop>
|
||||
<tabstop>deviceView</tabstop>
|
||||
<tabstop>defaultDeviceCheckBox</tabstop>
|
||||
<tabstop>refreshDevicesButton</tabstop>
|
||||
<tabstop>createAVDButton</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Android::Internal::AndroidDeviceDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Android::Internal::AndroidDeviceDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@@ -25,16 +25,17 @@
|
||||
|
||||
#include "androidmanager.h"
|
||||
|
||||
#include "androidbuildapkstep.h"
|
||||
#include "androidconstants.h"
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidrunconfiguration.h"
|
||||
#include "androidglobal.h"
|
||||
#include "androidtoolchain.h"
|
||||
#include "androiddeployqtstep.h"
|
||||
#include "androidqtversion.h"
|
||||
#include "androidavdmanager.h"
|
||||
#include "androidbuildapkstep.h"
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidconstants.h"
|
||||
#include "androiddeployqtstep.h"
|
||||
#include "androiddevice.h"
|
||||
#include "androidglobal.h"
|
||||
#include "androidqtversion.h"
|
||||
#include "androidrunconfiguration.h"
|
||||
#include "androidsdkmanager.h"
|
||||
#include "androidtoolchain.h"
|
||||
|
||||
#include <coreplugin/documentmanager.h>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
@@ -552,7 +553,8 @@ void AndroidManager::installQASIPackage(Target *target, const FilePath &packageP
|
||||
if (appAbis.isEmpty())
|
||||
return;
|
||||
const int deviceAPILevel = AndroidManager::minimumSDK(target);
|
||||
AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(target->project(), deviceAPILevel, appAbis);
|
||||
const IDevice::ConstPtr device = DeviceKitAspect::device(target->kit());
|
||||
AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromIDevice(device.data());
|
||||
if (!info.isValid()) // aborted
|
||||
return;
|
||||
|
||||
|
@@ -69,9 +69,7 @@ bool AndroidPotentialKit::isEnabled() const
|
||||
QList<ProjectExplorer::Kit *> kits = ProjectExplorer::KitManager::kits();
|
||||
foreach (ProjectExplorer::Kit *kit, kits) {
|
||||
Utils::Id deviceId = ProjectExplorer::DeviceKitAspect::deviceId(kit);
|
||||
if (kit->isAutoDetected()
|
||||
&& deviceId == Utils::Id(Constants::ANDROID_DEVICE_ID)
|
||||
&& !kit->isSdkProvided()) {
|
||||
if (kit->isAutoDetected() && !kit->isSdkProvided()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -121,9 +119,7 @@ void AndroidPotentialKitWidget::recheck()
|
||||
QList<ProjectExplorer::Kit *> kits = ProjectExplorer::KitManager::kits();
|
||||
foreach (ProjectExplorer::Kit *kit, kits) {
|
||||
Utils::Id deviceId = ProjectExplorer::DeviceKitAspect::deviceId(kit);
|
||||
if (kit->isAutoDetected()
|
||||
&& deviceId == Utils::Id(Constants::ANDROID_DEVICE_ID)
|
||||
&& !kit->isSdkProvided()) {
|
||||
if (kit->isAutoDetected() && !kit->isSdkProvided()) {
|
||||
setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
@@ -26,12 +26,13 @@
|
||||
|
||||
#include "androidrunner.h"
|
||||
|
||||
#include "androidavdmanager.h"
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidconstants.h"
|
||||
#include "androiddeployqtstep.h"
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidrunconfiguration.h"
|
||||
#include "androiddevice.h"
|
||||
#include "androidmanager.h"
|
||||
#include "androidavdmanager.h"
|
||||
#include "androidrunconfiguration.h"
|
||||
#include "androidrunnerworker.h"
|
||||
|
||||
#include <coreplugin/messagemanager.h>
|
||||
@@ -39,6 +40,7 @@
|
||||
#include <projectexplorer/projectexplorersettings.h>
|
||||
#include <projectexplorer/runconfigurationaspects.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
#include <utils/url.h>
|
||||
|
||||
#include <QHostAddress>
|
||||
@@ -185,9 +187,9 @@ void AndroidRunner::launchAVD()
|
||||
int deviceAPILevel = AndroidManager::minimumSDK(m_target);
|
||||
QStringList androidAbis = AndroidManager::applicationAbis(m_target);
|
||||
|
||||
// Get AVD info.
|
||||
AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(
|
||||
m_target->project(), deviceAPILevel, androidAbis);
|
||||
// Get AVD info
|
||||
const IDevice::ConstPtr device = DeviceKitAspect::device(m_target->kit());
|
||||
AndroidDeviceInfo info = AndroidDevice::androidDeviceInfoFromIDevice(device.data());
|
||||
AndroidManager::setDeviceSerialNumber(m_target, info.serialNumber);
|
||||
emit androidDeviceInfoChanged(info);
|
||||
if (info.isValid()) {
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 976 B |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
@@ -29,8 +29,6 @@
|
||||
<file>images/RunSettings.png</file>
|
||||
<file>images/EditorSettings.png</file>
|
||||
<file>images/ProjectDependencies.png</file>
|
||||
<file>images/MaemoDevice.png</file>
|
||||
<file>images/Simulator.png</file>
|
||||
<file>images/devicestatusindicator.png</file>
|
||||
<file>images/devicestatusindicator@2x.png</file>
|
||||
<file>images/build.png</file>
|
||||
|
@@ -344,10 +344,6 @@ void IconLister::addProjectExplorerIcons()
|
||||
""},
|
||||
{QIcon(":/projectexplorer/images/ProjectDependencies.png"), "ProjectDependencies.png", prefix,
|
||||
""},
|
||||
{QIcon(":/projectexplorer/images/MaemoDevice.png"), "MaemoDevice.png", prefix,
|
||||
""},
|
||||
{QIcon(":/projectexplorer/images/Simulator.png"), "Simulator.png", prefix,
|
||||
""},
|
||||
{QIcon(":/projectexplorer/images/targetpanel_bottom.png"), "targetpanel_bottom.png", prefix,
|
||||
""},
|
||||
{QIcon(":/projectexplorer/images/unconfigured.png"), "unconfigured.png", prefix,
|
||||
|
Reference in New Issue
Block a user