Commit 59709631 authored by Daniel Teske's avatar Daniel Teske

Android: Fix deployment to wrong avd

We used to only identify the avd by api level and abi. That was
obviously incorrect, but at the time I didn't know how to get
the actual avd name from a running emulator.

Turns out this is reasonable easy via telnet on the emulator port.

Change-Id: I387901a5294674f44399c0726abcc9feea221e8d
Task-number: QTCREATORBUG-13095
Reviewed-by: default avatarBogDan Vatra <bogdan@kde.org>
parent b0498646
......@@ -68,6 +68,8 @@
#include <QStringListModel>
#include <QMessageBox>
#include <QTcpSocket>
#include <QHostAddress>
#include <functional>
......@@ -129,6 +131,8 @@ namespace {
return dev1.type == AndroidDeviceInfo::Hardware;
if (dev1.sdk != dev2.sdk)
return dev1.sdk < dev2.sdk;
if (dev1.avdname != dev2.avdname)
return dev1.avdname < dev2.avdname;
return dev1.serialNumber < dev2.serialNumber;
}
......@@ -564,6 +568,10 @@ QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(const QString &adbToo
dev.state = AndroidDeviceInfo::OfflineState;
else
dev.state = AndroidDeviceInfo::OkState;
if (dev.type == AndroidDeviceInfo::Emulator)
dev.avdname = getAvdName(dev.serialNumber);
devices.push_back(dev);
}
......@@ -700,7 +708,7 @@ QVector<AndroidDeviceInfo> AndroidConfig::androidVirtualDevices(const QString &a
int index = line.indexOf(QLatin1Char(':')) + 2;
if (index >= line.size())
break;
dev.serialNumber = line.mid(index).trimmed();
dev.avdname = line.mid(index).trimmed();
dev.sdk = -1;
dev.cpuAbi.clear();
++i;
......@@ -752,10 +760,10 @@ QVector<AndroidDeviceInfo> AndroidConfig::androidVirtualDevices(const QString &a
return devices;
}
QString AndroidConfig::startAVD(const QString &name, int apiLevel, QString cpuAbi) const
QString AndroidConfig::startAVD(const QString &name) const
{
if (!findAvd(apiLevel, cpuAbi).isEmpty() || startAVDAsync(name))
return waitForAvd(apiLevel, cpuAbi);
if (!findAvd(name).isEmpty() || startAVDAsync(name))
return waitForAvd(name);
return QString();
}
......@@ -779,17 +787,14 @@ bool AndroidConfig::startAVDAsync(const QString &avdName) const
return true;
}
QString AndroidConfig::findAvd(int apiLevel, const QString &cpuAbi) const
QString AndroidConfig::findAvd(const QString &avdName) const
{
QVector<AndroidDeviceInfo> devices = connectedDevices();
foreach (AndroidDeviceInfo device, devices) {
if (!device.serialNumber.startsWith(QLatin1String("emulator")))
continue;
if (!device.cpuAbi.contains(cpuAbi))
continue;
if (device.sdk != apiLevel)
if (device.type != AndroidDeviceInfo::Emulator)
continue;
return device.serialNumber;
if (device.avdname == avdName)
return device.serialNumber;
}
return QString();
}
......@@ -821,7 +826,7 @@ bool AndroidConfig::waitForBooted(const QString &serialNumber, const QFutureInte
return false;
}
QString AndroidConfig::waitForAvd(int apiLevel, const QString &cpuAbi, const QFutureInterface<bool> &fi) const
QString AndroidConfig::waitForAvd(const QString &avdName, const QFutureInterface<bool> &fi) const
{
// we cannot use adb -e wait-for-device, since that doesn't work if a emulator is already running
// 60 rounds of 2s sleeping, two minutes for the avd to start
......@@ -829,7 +834,7 @@ QString AndroidConfig::waitForAvd(int apiLevel, const QString &cpuAbi, const QFu
for (int i = 0; i < 60; ++i) {
if (fi.isCanceled())
return QString();
serialNumber = findAvd(apiLevel, cpuAbi);
serialNumber = findAvd(avdName);
if (!serialNumber.isEmpty())
return waitForBooted(serialNumber, fi) ? serialNumber : QString();
Utils::sleep(2000);
......@@ -889,6 +894,36 @@ int AndroidConfig::getSDKVersion(const QString &adbToolPath, const QString &devi
return tmp.trimmed().toInt();
}
QString AndroidConfig::getAvdName(const QString &serialnumber)
{
int index = serialnumber.indexOf(QLatin1String("-"));
if (index == -1)
return QString();
bool ok;
int port = serialnumber.mid(index + 1).toInt(&ok);
if (!ok)
return QString();
QByteArray avdName = "avd name\n";
QTcpSocket tcpSocket;
tcpSocket.connectToHost(QHostAddress(QHostAddress::LocalHost), port);
tcpSocket.waitForConnected();
tcpSocket.write(avdName + "exit\n");
tcpSocket.waitForDisconnected();
QByteArray response = tcpSocket.readAll();
int start = response.indexOf("OK\r\n");
if (start == -1)
return QString();
start = start + 4;
int end = response.indexOf("\r\n", start);
if (end == -1)
return QString();
return QString::fromLatin1(response.mid(start, end - start));
}
AndroidConfig::OpenGl AndroidConfig::getOpenGLEnabled(const QString &emulator) const
{
QDir dir = QDir::home();
......
......@@ -60,6 +60,7 @@ class AndroidPlugin;
struct AndroidDeviceInfo
{
QString serialNumber;
QString avdname;
QStringList cpuAbi;
int sdk;
enum State { OkState, UnAuthorizedState, OfflineState };
......@@ -154,10 +155,10 @@ public:
QVector<AndroidDeviceInfo> androidVirtualDevices() const;
static QVector<AndroidDeviceInfo> androidVirtualDevices(const QString &androidTool, const Utils::Environment &environment);
QString startAVD(const QString &name, int apiLevel, QString cpuAbi) const;
QString startAVD(const QString &name) const;
bool startAVDAsync(const QString &avdName) const;
QString findAvd(int apiLevel, const QString &cpuAbi) const;
QString waitForAvd(int apiLevel, const QString &cpuAbi, const QFutureInterface<bool> &fi = QFutureInterface<bool>()) const;
QString findAvd(const QString &avdName) const;
QString waitForAvd(const QString &avdName, const QFutureInterface<bool> &fi = QFutureInterface<bool>()) const;
QString bestNdkPlatformMatch(int target) const;
static ProjectExplorer::Abi abiForToolChainPrefix(const QString &toolchainPrefix);
......@@ -185,6 +186,7 @@ private:
static QStringList getAbis(const QString &adbToolPath, const QString &device);
static bool isBootToQt(const QString &adbToolPath, const QString &device);
bool isBootToQt(const QString &device) const;
static QString getAvdName(const QString &serialnumber);
void updateAvailableSdkPlatforms() const;
void updateNdkInformation() const;
......
......@@ -191,22 +191,17 @@ bool AndroidDeployQtStep::init()
return false;
}
m_deviceAPILevel = AndroidManager::minimumSDK(target());
int deviceAPILevel = AndroidManager::minimumSDK(target());
AndroidConfigurations::Options options = AndroidConfigurations::None;
if (androidBuildApkStep->deployAction() == AndroidBuildApkStep::DebugDeployment)
options = AndroidConfigurations::FilterAndroid5;
AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(project(), m_deviceAPILevel, m_targetArch, options);
if (info.serialNumber.isEmpty()) // aborted
AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(project(), deviceAPILevel, m_targetArch, options);
if (info.serialNumber.isEmpty() && info.avdname.isEmpty()) // aborted
return false;
if (info.type == AndroidDeviceInfo::Emulator) {
m_avdName = info.serialNumber;
m_serialNumber.clear();
m_deviceAPILevel = info.sdk;
} else {
m_avdName.clear();
m_serialNumber = info.serialNumber;
}
m_avdName = info.avdname;
m_serialNumber = info.serialNumber;
AndroidManager::setDeviceSerialNumber(target(), m_serialNumber);
ProjectExplorer::BuildConfiguration *bc = target()->activeBuildConfiguration();
......@@ -278,7 +273,7 @@ bool AndroidDeployQtStep::init()
m_adbPath = AndroidConfigurations::currentConfig().adbToolPath().toString();
if (AndroidConfigurations::currentConfig().findAvd(m_deviceAPILevel, m_targetArch).isEmpty())
if (AndroidConfigurations::currentConfig().findAvd(m_avdName).isEmpty())
AndroidConfigurations::currentConfig().startAVDAsync(m_avdName);
return true;
}
......@@ -400,7 +395,7 @@ void AndroidDeployQtStep::slotSetSerialNumber(const QString &serialNumber)
void AndroidDeployQtStep::run(QFutureInterface<bool> &fi)
{
if (!m_avdName.isEmpty()) {
QString serialNumber = AndroidConfigurations::currentConfig().waitForAvd(m_deviceAPILevel, m_targetArch, fi);
QString serialNumber = AndroidConfigurations::currentConfig().waitForAvd(m_avdName, fi);
if (serialNumber.isEmpty()) {
fi.reportResult(false);
emit finished();
......
......@@ -129,7 +129,6 @@ private:
QString m_apkPath;
QString m_targetArch;
int m_deviceAPILevel;
bool m_uninstallPreviousPackage;
bool m_uninstallPreviousPackageRun;
static const Core::Id Id;
......
......@@ -34,6 +34,7 @@
#include <utils/environment.h>
#include <utils/progressindicator.h>
#include <utils/algorithm.h>
#include <QMessageBox>
#include <QPainter>
......@@ -167,9 +168,11 @@ public:
QFontMetrics fm(opt.font);
// TopLeft
QString topLeft = device.serialNumber;
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);
......@@ -181,7 +184,7 @@ public:
if (device.type == AndroidDeviceInfo::Hardware) {
drawTopRight(device.serialNumber, fm);
} else {
AndroidConfig::OpenGl openGl = AndroidConfigurations::currentConfig().getOpenGLEnabled(device.serialNumber);
AndroidConfig::OpenGl openGl = AndroidConfigurations::currentConfig().getOpenGLEnabled(device.avdname);
if (openGl == AndroidConfig::OpenGl::Enabled) {
drawTopRight(tr("OpenGL enabled"), fm);
} else if (openGl == AndroidConfig::OpenGl::Disabled) {
......@@ -249,7 +252,7 @@ public:
AndroidDeviceInfo device(QModelIndex index);
void setDevices(const QVector<AndroidDeviceInfo> &devices);
QModelIndex indexFor(const QString &serial);
QModelIndex indexFor(AndroidDeviceInfo::AndroidDeviceType type, const QString &serial);
private:
int m_apiLevel;
QString m_abi;
......@@ -385,12 +388,16 @@ void AndroidDeviceModel::setDevices(const QVector<AndroidDeviceInfo> &devices)
endResetModel();
}
QModelIndex AndroidDeviceModel::indexFor(const QString &serial)
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) {
if (deviceNodes.at(i)->deviceInfo().serialNumber == serial)
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));
}
}
......@@ -498,12 +505,16 @@ QVector<AndroidDeviceInfo> AndroidDeviceDialog::refreshDevices(const QString &ad
const QString &androidToolPath,
const Utils::Environment &environment)
{
QVector<AndroidDeviceInfo> devices;
foreach (const AndroidDeviceInfo &info, AndroidConfig::connectedDevices(adbToolPath))
if (info.type == AndroidDeviceInfo::Hardware)
devices << info;
QVector<AndroidDeviceInfo> devices = AndroidConfig::connectedDevices(adbToolPath);
QSet<QString> startedAvds = Utils::transform<QSet>(devices,
[] (const AndroidDeviceInfo &info) {
return info.avdname;
});
devices += AndroidConfig::androidVirtualDevices(androidToolPath, environment);
for (const AndroidDeviceInfo &dev : AndroidConfig::androidVirtualDevices(androidToolPath, environment))
if (!startedAvds.contains(dev.avdname))
devices << dev;
return devices;
}
......@@ -511,13 +522,18 @@ void AndroidDeviceDialog::devicesRefreshed()
{
m_progressIndicator->hide();
QString serialNumber;
if (!m_serialNumberFromAdd.isEmpty()) {
serialNumber = m_serialNumberFromAdd;
m_serialNumberFromAdd.clear();
AndroidDeviceInfo::AndroidDeviceType deviceType;
if (!m_avdNameFromAdd.isEmpty()) {
serialNumber = m_avdNameFromAdd;
m_avdNameFromAdd.clear();
deviceType = AndroidDeviceInfo::Emulator;
} else {
QModelIndex currentIndex = m_ui->deviceView->currentIndex();
if (currentIndex.isValid())
serialNumber = m_model->device(currentIndex).serialNumber;
if (currentIndex.isValid()) {
AndroidDeviceInfo info = m_model->device(currentIndex);
deviceType = info.type;
serialNumber = deviceType == AndroidDeviceInfo::Hardware ? info.serialNumber : info.avdname;
}
}
QVector<AndroidDeviceInfo> devices = m_futureWatcherRefreshDevices.result();
......@@ -530,10 +546,13 @@ void AndroidDeviceDialog::devicesRefreshed()
// Smartly select a index
QModelIndex newIndex;
if (!serialNumber.isEmpty())
newIndex = m_model->indexFor(serialNumber);
newIndex = m_model->indexFor(deviceType, serialNumber);
if (!newIndex.isValid() && !devices.isEmpty())
newIndex = m_model->indexFor(devices.first().serialNumber);
if (!newIndex.isValid() && !devices.isEmpty()) {
AndroidDeviceInfo info = devices.first();
const QString &name = info.type == AndroidDeviceInfo::Hardware ? info.serialNumber : info.avdname;
newIndex = m_model->indexFor(info.type, name);
}
m_ui->deviceView->setCurrentIndex(newIndex);
......@@ -564,14 +583,14 @@ void AndroidDeviceDialog::avdAdded()
return;
}
m_serialNumberFromAdd = info.name;
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();
bool enable = node && (!node->deviceInfo().serialNumber.isEmpty() || !node->deviceInfo().avdname.isEmpty());
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enable);
}
......
......@@ -80,7 +80,7 @@ private:
Utils::ProgressIndicator *m_progressIndicator;
int m_apiLevel;
QString m_abi;
QString m_serialNumberFromAdd;
QString m_avdNameFromAdd;
QFutureWatcher<AndroidConfig::CreateAvdInfo> m_futureWatcherAddDevice;
QFutureWatcher<QVector<AndroidDeviceInfo>> m_futureWatcherRefreshDevices;
};
......
......@@ -493,14 +493,14 @@ void AndroidManager::cleanLibsOnDevice(ProjectExplorer::Target *target)
return;
int deviceAPILevel = AndroidManager::minimumSDK(target);
AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(target->project(), deviceAPILevel, targetArch, AndroidConfigurations::None);
if (info.serialNumber.isEmpty()) // aborted
if (info.serialNumber.isEmpty() && info.avdname.isEmpty()) // aborted
return;
deviceAPILevel = info.sdk;
QString deviceSerialNumber = info.serialNumber;
if (info.type == AndroidDeviceInfo::Emulator) {
deviceSerialNumber = AndroidConfigurations::currentConfig().startAVD(deviceSerialNumber, deviceAPILevel, targetArch);
deviceSerialNumber = AndroidConfigurations::currentConfig().startAVD(info.avdname);
if (deviceSerialNumber.isEmpty())
Core::MessageManager::write(tr("Starting Android virtual device failed."));
}
......@@ -523,13 +523,13 @@ void AndroidManager::installQASIPackage(ProjectExplorer::Target *target, const Q
return;
int deviceAPILevel = AndroidManager::minimumSDK(target);
AndroidDeviceInfo info = AndroidConfigurations::showDeviceDialog(target->project(), deviceAPILevel, targetArch, AndroidConfigurations::None);
if (info.serialNumber.isEmpty()) // aborted
if (info.serialNumber.isEmpty() && info.avdname.isEmpty()) // aborted
return;
deviceAPILevel = info.sdk;
QString deviceSerialNumber = info.serialNumber;
if (info.type == AndroidDeviceInfo::Emulator) {
deviceSerialNumber = AndroidConfigurations::currentConfig().startAVD(deviceSerialNumber, deviceAPILevel, targetArch);
deviceSerialNumber = AndroidConfigurations::currentConfig().startAVD(info.avdname);
if (deviceSerialNumber.isEmpty())
Core::MessageManager::write(tr("Starting Android virtual device failed."));
}
......
......@@ -79,7 +79,7 @@ QModelIndex AvdModel::indexForAvdName(const QString &avdName) const
QString AvdModel::avdName(const QModelIndex &index) const
{
return m_list.at(index.row()).serialNumber;
return m_list.at(index.row()).avdname;
}
QVariant AvdModel::data(const QModelIndex &index, int role) const
......@@ -88,7 +88,7 @@ QVariant AvdModel::data(const QModelIndex &index, int role) const
return QVariant();
switch (index.column()) {
case 0:
return m_list[index.row()].serialNumber;
return m_list[index.row()].avdname;
case 1:
return QString::fromLatin1("API %1").arg(m_list[index.row()].sdk);
case 2: {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment