2012-04-18 20:30:57 +03:00
|
|
|
/**************************************************************************
|
|
|
|
**
|
2014-01-07 13:27:11 +01:00
|
|
|
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
|
2012-10-02 09:12:39 +02:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
2012-04-18 20:30:57 +03:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2012-04-18 20:30:57 +03:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
|
|
|
** use the contact form at http://qt.digia.com/contact-us.
|
2012-04-18 20:30:57 +03:00
|
|
|
**
|
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
|
|
** General Public License version 2.1 as published by the Free Software
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
|
|
**
|
|
|
|
** In addition, as a special exception, Digia gives you certain additional
|
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
2012-04-18 20:30:57 +03:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
#include "androidconfigurations.h"
|
|
|
|
#include "androidconstants.h"
|
2013-02-14 15:51:59 +01:00
|
|
|
#include "androidtoolchain.h"
|
|
|
|
#include "androiddevice.h"
|
|
|
|
#include "androidgdbserverkitinformation.h"
|
2013-08-01 12:49:47 +02:00
|
|
|
#include "androidqtversion.h"
|
2013-09-10 19:19:31 +02:00
|
|
|
#include "androiddevicedialog.h"
|
2014-03-24 16:31:28 +01:00
|
|
|
#include "avddialog.h"
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
#include <coreplugin/icore.h>
|
2013-11-22 16:40:41 +01:00
|
|
|
#include <coreplugin/messagemanager.h>
|
2012-08-23 15:53:58 +02:00
|
|
|
#include <utils/hostosinfo.h>
|
2012-04-18 20:30:57 +03:00
|
|
|
#include <utils/persistentsettings.h>
|
2013-02-14 15:51:59 +01:00
|
|
|
#include <projectexplorer/kitmanager.h>
|
|
|
|
#include <projectexplorer/kitinformation.h>
|
|
|
|
#include <projectexplorer/devicesupport/devicemanager.h>
|
|
|
|
#include <projectexplorer/toolchainmanager.h>
|
2013-09-10 19:19:31 +02:00
|
|
|
#include <projectexplorer/session.h>
|
2013-10-25 13:47:08 +02:00
|
|
|
#include <debugger/debuggeritemmanager.h>
|
2013-02-14 15:51:59 +01:00
|
|
|
#include <debugger/debuggerkitinformation.h>
|
|
|
|
#include <qtsupport/baseqtversion.h>
|
|
|
|
#include <qtsupport/qtkitinformation.h>
|
|
|
|
#include <qtsupport/qtversionmanager.h>
|
2013-04-17 11:52:16 +02:00
|
|
|
#include <utils/environment.h>
|
2013-09-08 23:02:28 +03:00
|
|
|
#include <utils/sleep.h>
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
#include <QDateTime>
|
|
|
|
#include <QSettings>
|
|
|
|
#include <QStringList>
|
|
|
|
#include <QProcess>
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QDirIterator>
|
|
|
|
#include <QMetaObject>
|
2014-03-24 16:31:28 +01:00
|
|
|
#include <QApplication>
|
2014-04-11 13:31:01 +02:00
|
|
|
#include <QtConcurrentRun>
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
#include <QStringListModel>
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
using namespace ProjectExplorer;
|
2012-04-18 20:30:57 +03:00
|
|
|
using namespace Utils;
|
|
|
|
|
|
|
|
namespace Android {
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
const QLatin1String SettingsGroup("AndroidConfigurations");
|
|
|
|
const QLatin1String SDKLocationKey("SDKLocation");
|
|
|
|
const QLatin1String NDKLocationKey("NDKLocation");
|
|
|
|
const QLatin1String NDKToolchainVersionKey("NDKToolchainVersion");
|
|
|
|
const QLatin1String AntLocationKey("AntLocation");
|
|
|
|
const QLatin1String OpenJDKLocationKey("OpenJDKLocation");
|
|
|
|
const QLatin1String KeystoreLocationKey("KeystoreLocation");
|
2013-02-14 15:51:59 +01:00
|
|
|
const QLatin1String AutomaticKitCreationKey("AutomatiKitCreation");
|
2013-05-16 15:49:24 +02:00
|
|
|
const QLatin1String MakeExtraSearchDirectory("MakeExtraSearchDirectory");
|
2013-09-10 19:19:31 +02:00
|
|
|
const QLatin1String DefaultDevice("DefaultDevice");
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String PartitionSizeKey("PartitionSize");
|
2013-04-04 01:29:47 -07:00
|
|
|
const QLatin1String ToolchainHostKey("ToolchainHost");
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String ArmToolchainPrefix("arm-linux-androideabi");
|
|
|
|
const QLatin1String X86ToolchainPrefix("x86");
|
2013-02-16 18:05:11 +02:00
|
|
|
const QLatin1String MipsToolchainPrefix("mipsel-linux-android");
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String ArmToolsPrefix("arm-linux-androideabi");
|
2013-02-16 18:04:00 +02:00
|
|
|
const QLatin1String X86ToolsPrefix("i686-linux-android");
|
2013-02-16 18:05:11 +02:00
|
|
|
const QLatin1String MipsToolsPrefix("mipsel-linux-android");
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String Unknown("unknown");
|
|
|
|
const QLatin1String keytoolName("keytool");
|
|
|
|
const QLatin1String jarsignerName("jarsigner");
|
|
|
|
const QLatin1String changeTimeStamp("ChangeTimeStamp");
|
|
|
|
|
2012-12-07 19:52:47 +02:00
|
|
|
static QString sdkSettingsFileName()
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-02-20 16:17:48 +01:00
|
|
|
return QFileInfo(Core::ICore::settings(QSettings::SystemScope)->fileName()).absolutePath()
|
|
|
|
+ QLatin1String("/qtcreator/android.xml");
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2012-07-03 16:57:44 +03:00
|
|
|
bool androidDevicesLessThan(const AndroidDeviceInfo &dev1, const AndroidDeviceInfo &dev2)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-08-28 14:59:51 +02:00
|
|
|
if (dev1.serialNumber.contains(QLatin1String("????")) == dev2.serialNumber.contains(QLatin1String("????")))
|
|
|
|
return !dev1.serialNumber.contains(QLatin1String("????"));
|
2013-09-10 19:19:31 +02:00
|
|
|
if (dev1.type != dev2.type)
|
|
|
|
return dev1.type == AndroidDeviceInfo::Hardware;
|
2013-08-28 12:33:57 +02:00
|
|
|
if (dev1.sdk != dev2.sdk)
|
|
|
|
return dev1.sdk < dev2.sdk;
|
2013-09-10 19:19:31 +02:00
|
|
|
|
2013-08-28 12:33:57 +02:00
|
|
|
return dev1.serialNumber < dev2.serialNumber;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
2014-04-10 15:52:02 +02:00
|
|
|
|
|
|
|
static QStringList cleanAndroidABIs(const QStringList &abis)
|
|
|
|
{
|
|
|
|
QStringList res;
|
|
|
|
foreach (const QString &abi, abis) {
|
|
|
|
int index = abi.lastIndexOf(QLatin1Char('/'));
|
|
|
|
if (index == -1)
|
|
|
|
res << abi;
|
|
|
|
else
|
|
|
|
res << abi.mid(index + 1);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
//////////////////////////////////
|
|
|
|
// AndroidConfig
|
|
|
|
//////////////////////////////////
|
|
|
|
|
|
|
|
Abi::Architecture AndroidConfig::architectureForToolChainPrefix(const QString& toolchainprefix)
|
2013-01-25 16:49:22 +01:00
|
|
|
{
|
|
|
|
if (toolchainprefix == ArmToolchainPrefix)
|
|
|
|
return Abi::ArmArchitecture;
|
|
|
|
if (toolchainprefix == X86ToolchainPrefix)
|
|
|
|
return Abi::X86Architecture;
|
2013-02-16 18:05:11 +02:00
|
|
|
if (toolchainprefix == MipsToolchainPrefix)
|
|
|
|
return Abi::MipsArchitecture;
|
2013-01-25 16:49:22 +01:00
|
|
|
return Abi::UnknownArchitecture;
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
QLatin1String AndroidConfig::toolchainPrefix(Abi::Architecture architecture)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
|
|
|
switch (architecture) {
|
2012-08-09 01:56:51 +02:00
|
|
|
case Abi::ArmArchitecture:
|
2012-04-18 20:30:57 +03:00
|
|
|
return ArmToolchainPrefix;
|
2012-08-09 01:56:51 +02:00
|
|
|
case Abi::X86Architecture:
|
2012-04-18 20:30:57 +03:00
|
|
|
return X86ToolchainPrefix;
|
2013-02-16 18:05:11 +02:00
|
|
|
case Abi::MipsArchitecture:
|
|
|
|
return MipsToolchainPrefix;
|
2012-04-18 20:30:57 +03:00
|
|
|
default:
|
|
|
|
return Unknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
QLatin1String AndroidConfig::toolsPrefix(Abi::Architecture architecture)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
|
|
|
switch (architecture) {
|
2012-08-09 01:56:51 +02:00
|
|
|
case Abi::ArmArchitecture:
|
2012-04-18 20:30:57 +03:00
|
|
|
return ArmToolsPrefix;
|
2012-08-09 01:56:51 +02:00
|
|
|
case Abi::X86Architecture:
|
2012-04-18 20:30:57 +03:00
|
|
|
return X86ToolsPrefix;
|
2013-02-16 18:05:11 +02:00
|
|
|
case Abi::MipsArchitecture:
|
|
|
|
return MipsToolsPrefix;
|
2012-04-18 20:30:57 +03:00
|
|
|
default:
|
|
|
|
return Unknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
void AndroidConfig::load(const QSettings &settings)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
|
|
|
// user settings
|
2013-12-16 20:19:07 +01:00
|
|
|
m_partitionSize = settings.value(PartitionSizeKey, 1024).toInt();
|
|
|
|
m_sdkLocation = FileName::fromString(settings.value(SDKLocationKey).toString());
|
|
|
|
m_ndkLocation = FileName::fromString(settings.value(NDKLocationKey).toString());
|
|
|
|
m_antLocation = FileName::fromString(settings.value(AntLocationKey).toString());
|
|
|
|
m_openJDKLocation = FileName::fromString(settings.value(OpenJDKLocationKey).toString());
|
|
|
|
m_keystoreLocation = FileName::fromString(settings.value(KeystoreLocationKey).toString());
|
|
|
|
m_toolchainHost = settings.value(ToolchainHostKey).toString();
|
|
|
|
m_automaticKitCreation = settings.value(AutomaticKitCreationKey, true).toBool();
|
2013-05-16 15:49:24 +02:00
|
|
|
QString extraDirectory = settings.value(MakeExtraSearchDirectory).toString();
|
2013-12-16 20:19:07 +01:00
|
|
|
m_makeExtraSearchDirectories.clear();
|
2013-12-04 12:49:25 +01:00
|
|
|
if (!extraDirectory.isEmpty())
|
2013-12-16 20:19:07 +01:00
|
|
|
m_makeExtraSearchDirectories << extraDirectory;
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
PersistentSettingsReader reader;
|
2012-12-07 19:52:47 +02:00
|
|
|
if (reader.load(FileName::fromString(sdkSettingsFileName()))
|
|
|
|
&& settings.value(changeTimeStamp).toInt() != QFileInfo(sdkSettingsFileName()).lastModified().toMSecsSinceEpoch() / 1000) {
|
2012-04-18 20:30:57 +03:00
|
|
|
// persisten settings
|
2013-12-16 20:19:07 +01:00
|
|
|
m_sdkLocation = FileName::fromString(reader.restoreValue(SDKLocationKey).toString());
|
|
|
|
m_ndkLocation = FileName::fromString(reader.restoreValue(NDKLocationKey).toString());
|
|
|
|
m_antLocation = FileName::fromString(reader.restoreValue(AntLocationKey).toString());
|
|
|
|
m_openJDKLocation = FileName::fromString(reader.restoreValue(OpenJDKLocationKey).toString());
|
|
|
|
m_keystoreLocation = FileName::fromString(reader.restoreValue(KeystoreLocationKey).toString());
|
|
|
|
m_toolchainHost = reader.restoreValue(ToolchainHostKey).toString();
|
2013-02-14 15:51:59 +01:00
|
|
|
QVariant v = reader.restoreValue(AutomaticKitCreationKey);
|
|
|
|
if (v.isValid())
|
2013-12-16 20:19:07 +01:00
|
|
|
m_automaticKitCreation = v.toBool();
|
2013-05-16 15:49:24 +02:00
|
|
|
QString extraDirectory = reader.restoreValue(MakeExtraSearchDirectory).toString();
|
2013-12-16 20:19:07 +01:00
|
|
|
m_makeExtraSearchDirectories.clear();
|
2013-12-04 12:49:25 +01:00
|
|
|
if (!extraDirectory.isEmpty())
|
2013-12-16 20:19:07 +01:00
|
|
|
m_makeExtraSearchDirectories << extraDirectory;
|
2012-04-18 20:30:57 +03:00
|
|
|
// persistent settings
|
|
|
|
}
|
2013-12-16 20:19:07 +01:00
|
|
|
m_availableSdkPlatformsUpToDate = false;
|
|
|
|
m_NdkInformationUpToDate = false;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
AndroidConfig::AndroidConfig()
|
2013-12-16 20:19:07 +01:00
|
|
|
: m_availableSdkPlatformsUpToDate(false),
|
|
|
|
m_NdkInformationUpToDate(false)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::save(QSettings &settings) const
|
|
|
|
{
|
2012-12-07 19:52:47 +02:00
|
|
|
QFileInfo fileInfo(sdkSettingsFileName());
|
2012-04-18 20:30:57 +03:00
|
|
|
if (fileInfo.exists())
|
|
|
|
settings.setValue(changeTimeStamp, fileInfo.lastModified().toMSecsSinceEpoch() / 1000);
|
|
|
|
|
|
|
|
// user settings
|
2013-12-16 20:19:07 +01:00
|
|
|
settings.setValue(SDKLocationKey, m_sdkLocation.toString());
|
|
|
|
settings.setValue(NDKLocationKey, m_ndkLocation.toString());
|
|
|
|
settings.setValue(AntLocationKey, m_antLocation.toString());
|
|
|
|
settings.setValue(OpenJDKLocationKey, m_openJDKLocation.toString());
|
|
|
|
settings.setValue(KeystoreLocationKey, m_keystoreLocation.toString());
|
|
|
|
settings.setValue(PartitionSizeKey, m_partitionSize);
|
|
|
|
settings.setValue(AutomaticKitCreationKey, m_automaticKitCreation);
|
|
|
|
settings.setValue(ToolchainHostKey, m_toolchainHost);
|
2013-06-04 11:45:19 +02:00
|
|
|
settings.setValue(MakeExtraSearchDirectory,
|
2013-12-16 20:19:07 +01:00
|
|
|
m_makeExtraSearchDirectories.isEmpty() ? QString()
|
|
|
|
: m_makeExtraSearchDirectories.at(0));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
void AndroidConfig::updateNdkInformation() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
if (m_NdkInformationUpToDate)
|
|
|
|
return;
|
2013-10-17 13:12:45 +02:00
|
|
|
m_availableNdkPlatforms.clear();
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName path = ndkLocation();
|
2012-06-23 12:24:44 +03:00
|
|
|
QDirIterator it(path.appendPath(QLatin1String("platforms")).toString(), QStringList() << QLatin1String("android-*"), QDir::Dirs);
|
2012-04-18 20:30:57 +03:00
|
|
|
while (it.hasNext()) {
|
|
|
|
const QString &fileName = it.next();
|
2013-10-17 13:12:45 +02:00
|
|
|
m_availableNdkPlatforms.push_back(fileName.mid(fileName.lastIndexOf(QLatin1Char('-')) + 1).toInt());
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
2013-10-17 13:12:45 +02:00
|
|
|
qSort(m_availableNdkPlatforms.begin(), m_availableNdkPlatforms.end(), qGreater<int>());
|
2013-12-16 20:19:07 +01:00
|
|
|
|
|
|
|
// detect toolchain host
|
|
|
|
QStringList hostPatterns;
|
|
|
|
switch (HostOsInfo::hostOs()) {
|
|
|
|
case OsTypeLinux:
|
|
|
|
hostPatterns << QLatin1String("linux*");
|
|
|
|
break;
|
|
|
|
case OsTypeWindows:
|
|
|
|
hostPatterns << QLatin1String("windows*");
|
|
|
|
break;
|
|
|
|
case OsTypeMac:
|
|
|
|
hostPatterns << QLatin1String("darwin*");
|
|
|
|
break;
|
|
|
|
default: /* unknown host */ return;
|
|
|
|
}
|
|
|
|
|
2014-02-20 15:08:52 +01:00
|
|
|
path = ndkLocation();
|
2013-12-16 20:19:07 +01:00
|
|
|
QDirIterator jt(path.appendPath(QLatin1String("prebuilt")).toString(), hostPatterns, QDir::Dirs);
|
|
|
|
if (jt.hasNext()) {
|
|
|
|
jt.next();
|
|
|
|
m_toolchainHost = jt.fileName();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_NdkInformationUpToDate = true;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2014-03-24 16:31:28 +01:00
|
|
|
bool AndroidConfig::sortSdkPlatformByApiLevel(const SdkPlatform &a, const SdkPlatform &b)
|
|
|
|
{
|
|
|
|
if (a.apiLevel != b.apiLevel)
|
|
|
|
return a.apiLevel > b.apiLevel;
|
|
|
|
if (a.name != b.name)
|
|
|
|
return a.name < b.name;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
void AndroidConfig::updateAvailableSdkPlatforms() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
if (m_availableSdkPlatformsUpToDate)
|
|
|
|
return;
|
2013-10-17 13:23:08 +02:00
|
|
|
m_availableSdkPlatforms.clear();
|
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
QProcess proc;
|
2013-11-19 17:25:32 +01:00
|
|
|
proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
|
2012-04-24 15:49:09 +02:00
|
|
|
proc.start(androidToolPath().toString(), QStringList() << QLatin1String("list") << QLatin1String("target")); // list avaialbe AVDs
|
2013-11-21 15:54:03 +01:00
|
|
|
if (!proc.waitForFinished(5000)) {
|
2012-04-18 20:30:57 +03:00
|
|
|
proc.terminate();
|
2013-10-17 13:23:08 +02:00
|
|
|
return;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
2014-03-24 16:31:28 +01:00
|
|
|
|
|
|
|
SdkPlatform platform;
|
2012-06-24 22:12:39 -07:00
|
|
|
while (proc.canReadLine()) {
|
2012-07-16 11:04:42 +02:00
|
|
|
const QString line = QString::fromLocal8Bit(proc.readLine().trimmed());
|
2014-03-24 16:31:28 +01:00
|
|
|
if (line.startsWith(QLatin1String("id:")) && line.contains(QLatin1String("android-"))) {
|
|
|
|
int index = line.indexOf(QLatin1String("\"android-"));
|
|
|
|
if (index == -1)
|
|
|
|
continue;
|
|
|
|
QString androidTarget = line.mid(index + 1, line.length() - index - 2);
|
|
|
|
platform.apiLevel = androidTarget.mid(androidTarget.lastIndexOf(QLatin1Char('-')) + 1).toInt();
|
|
|
|
} else if (line.startsWith(QLatin1String("Name:"))) {
|
|
|
|
platform.name = line.mid(6);
|
2014-04-10 15:52:02 +02:00
|
|
|
} else if (line.startsWith(QLatin1String("Tag/ABIs :"))) {
|
|
|
|
platform.abis = cleanAndroidABIs(line.mid(10).trimmed().split(QLatin1String(", ")));
|
2014-03-24 16:31:28 +01:00
|
|
|
} else if (line.startsWith(QLatin1String("ABIs"))) {
|
2014-04-10 15:52:02 +02:00
|
|
|
platform.abis = cleanAndroidABIs(line.mid(6).trimmed().split(QLatin1String(", ")));
|
2014-03-24 16:31:28 +01:00
|
|
|
} else if (line.startsWith(QLatin1String("---")) || line.startsWith(QLatin1String("==="))) {
|
|
|
|
if (platform.apiLevel == -1)
|
|
|
|
continue;
|
|
|
|
auto it = qLowerBound(m_availableSdkPlatforms.begin(), m_availableSdkPlatforms.end(),
|
|
|
|
platform, sortSdkPlatformByApiLevel);
|
|
|
|
m_availableSdkPlatforms.insert(it, platform);
|
|
|
|
platform = SdkPlatform();
|
|
|
|
}
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
2014-04-10 15:52:22 +02:00
|
|
|
|
|
|
|
if (platform.apiLevel != -1) {
|
|
|
|
auto it = qLowerBound(m_availableSdkPlatforms.begin(), m_availableSdkPlatforms.end(),
|
|
|
|
platform, sortSdkPlatformByApiLevel);
|
|
|
|
m_availableSdkPlatforms.insert(it, platform);
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
m_availableSdkPlatformsUpToDate = true;
|
2013-10-17 13:23:08 +02:00
|
|
|
}
|
|
|
|
|
2014-03-24 16:31:28 +01:00
|
|
|
QStringList AndroidConfig::apiLevelNamesFor(const QList<SdkPlatform> &platforms)
|
|
|
|
{
|
|
|
|
QStringList results;
|
|
|
|
foreach (const SdkPlatform &platform, platforms)
|
|
|
|
results << QLatin1String("android-") + QString::number(platform.apiLevel);
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<SdkPlatform> AndroidConfig::sdkTargets(int minApiLevel) const
|
2013-10-17 13:23:08 +02:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
updateAvailableSdkPlatforms();
|
2014-03-24 16:31:28 +01:00
|
|
|
QList<SdkPlatform> result;
|
2013-10-17 13:23:08 +02:00
|
|
|
for (int i = 0; i < m_availableSdkPlatforms.size(); ++i) {
|
2014-03-24 16:31:28 +01:00
|
|
|
if (m_availableSdkPlatforms.at(i).apiLevel >= minApiLevel)
|
|
|
|
result << m_availableSdkPlatforms.at(i);
|
2013-10-17 13:23:08 +02:00
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::adbToolPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
Utils::FileName path = m_sdkLocation;
|
2012-08-31 16:39:20 +02:00
|
|
|
return path.appendPath(QLatin1String("platform-tools/adb" QTC_HOST_EXE_SUFFIX));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
Utils::Environment AndroidConfig::androidToolEnvironment() const
|
2013-11-19 17:25:32 +01:00
|
|
|
{
|
|
|
|
Utils::Environment env = Utils::Environment::systemEnvironment();
|
2013-12-16 20:19:07 +01:00
|
|
|
if (!m_openJDKLocation.isEmpty())
|
|
|
|
env.set(QLatin1String("JAVA_HOME"), m_openJDKLocation.toUserOutput());
|
2013-11-19 17:25:32 +01:00
|
|
|
return env;
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::androidToolPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2012-08-23 15:53:58 +02:00
|
|
|
if (HostOsInfo::isWindowsHost()) {
|
|
|
|
// I want to switch from using android.bat to using an executable. All it really does is call
|
|
|
|
// Java and I've made some progress on it. So if android.exe exists, return that instead.
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName path = m_sdkLocation;
|
2012-08-31 16:39:20 +02:00
|
|
|
path.appendPath(QLatin1String("tools/android" QTC_HOST_EXE_SUFFIX));
|
2012-08-23 15:53:58 +02:00
|
|
|
if (path.toFileInfo().exists())
|
|
|
|
return path;
|
2013-12-16 20:19:07 +01:00
|
|
|
path = m_sdkLocation;
|
2012-09-04 13:45:03 +02:00
|
|
|
return path.appendPath(QLatin1String("tools/android" ANDROID_BAT_SUFFIX));
|
2012-08-23 15:53:58 +02:00
|
|
|
} else {
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName path = m_sdkLocation;
|
2012-08-23 15:53:58 +02:00
|
|
|
return path.appendPath(QLatin1String("tools/android"));
|
|
|
|
}
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::antToolPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
if (!m_antLocation.isEmpty())
|
|
|
|
return m_antLocation;
|
2012-04-18 20:30:57 +03:00
|
|
|
else
|
2014-02-07 15:46:36 +01:00
|
|
|
return FileName::fromLatin1("ant");
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::emulatorToolPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName path = m_sdkLocation;
|
2012-08-31 16:39:20 +02:00
|
|
|
return path.appendPath(QLatin1String("tools/emulator" QTC_HOST_EXE_SUFFIX));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::toolPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName path = m_ndkLocation;
|
2012-04-24 15:49:09 +02:00
|
|
|
return path.appendPath(QString::fromLatin1("toolchains/%1-%2/prebuilt/%3/bin/%4")
|
2012-04-18 20:30:57 +03:00
|
|
|
.arg(toolchainPrefix(architecture))
|
2013-01-25 16:49:22 +01:00
|
|
|
.arg(ndkToolChainVersion)
|
2013-12-16 20:19:07 +01:00
|
|
|
.arg(toolchainHost())
|
2012-04-24 15:49:09 +02:00
|
|
|
.arg(toolsPrefix(architecture)));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::stripPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-10-30 16:24:58 +01:00
|
|
|
return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-strip" QTC_HOST_EXE_SUFFIX));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::readelfPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-10-30 16:24:58 +01:00
|
|
|
return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-readelf" QTC_HOST_EXE_SUFFIX));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::gccPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
|
2013-04-04 01:29:47 -07:00
|
|
|
{
|
2013-10-30 16:24:58 +01:00
|
|
|
return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-gcc" QTC_HOST_EXE_SUFFIX));
|
2013-04-04 01:29:47 -07:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::gdbPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-10-30 16:24:58 +01:00
|
|
|
return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-gdb" QTC_HOST_EXE_SUFFIX));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::openJDKBinPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName path = m_openJDKLocation;
|
2012-04-24 15:49:09 +02:00
|
|
|
if (!path.isEmpty())
|
|
|
|
return path.appendPath(QLatin1String("bin"));
|
|
|
|
return path;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::keytoolPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2012-04-24 15:49:09 +02:00
|
|
|
return openJDKBinPath().appendPath(keytoolName);
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::jarsignerPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2012-04-24 15:49:09 +02:00
|
|
|
return openJDKBinPath().appendPath(jarsignerName);
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::zipalignPath() const
|
2012-06-23 13:18:01 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName path = m_sdkLocation;
|
2012-08-31 16:39:20 +02:00
|
|
|
return path.appendPath(QLatin1String("tools/zipalign" QTC_HOST_EXE_SUFFIX));
|
2012-06-23 13:18:01 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(QString *error) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2012-07-03 16:57:44 +03:00
|
|
|
QVector<AndroidDeviceInfo> devices;
|
2012-04-18 20:30:57 +03:00
|
|
|
QProcess adbProc;
|
2012-04-24 15:49:09 +02:00
|
|
|
adbProc.start(adbToolPath().toString(), QStringList() << QLatin1String("devices"));
|
2013-11-21 15:54:03 +01:00
|
|
|
if (!adbProc.waitForFinished(5000)) {
|
2012-12-10 23:43:21 +00:00
|
|
|
adbProc.kill();
|
2013-07-03 17:58:48 +02:00
|
|
|
if (error)
|
2013-12-16 20:19:07 +01:00
|
|
|
*error = QApplication::translate("AndroidConfiguration",
|
|
|
|
"Could not run: %1")
|
|
|
|
.arg(adbToolPath().toString() + QLatin1String(" devices"));
|
2012-04-18 20:30:57 +03:00
|
|
|
return devices;
|
|
|
|
}
|
|
|
|
QList<QByteArray> adbDevs = adbProc.readAll().trimmed().split('\n');
|
2013-10-22 13:51:17 +03:00
|
|
|
if (adbDevs.empty())
|
|
|
|
return devices;
|
|
|
|
|
|
|
|
while (adbDevs.first().startsWith("* daemon"))
|
|
|
|
adbDevs.removeFirst(); // remove the daemon logs
|
|
|
|
adbDevs.removeFirst(); // remove "List of devices attached" header line
|
2013-02-24 18:04:36 +04:00
|
|
|
|
|
|
|
// workaround for '????????????' serial numbers:
|
|
|
|
// can use "adb -d" when only one usb device attached
|
2012-04-18 20:30:57 +03:00
|
|
|
foreach (const QByteArray &device, adbDevs) {
|
2013-08-28 12:50:32 +02:00
|
|
|
const QString serialNo = QString::fromLatin1(device.left(device.indexOf('\t')).trimmed());
|
|
|
|
const QString deviceType = QString::fromLatin1(device.mid(device.indexOf('\t'))).trimmed();
|
2013-11-15 16:29:53 +01:00
|
|
|
if (isBootToQt(serialNo))
|
|
|
|
continue;
|
2013-08-28 12:50:32 +02:00
|
|
|
AndroidDeviceInfo dev;
|
2013-02-24 18:04:36 +04:00
|
|
|
dev.serialNumber = serialNo;
|
2013-09-10 19:19:31 +02:00
|
|
|
dev.type = serialNo.startsWith(QLatin1String("emulator")) ? AndroidDeviceInfo::Emulator : AndroidDeviceInfo::Hardware;
|
2012-04-18 20:30:57 +03:00
|
|
|
dev.sdk = getSDKVersion(dev.serialNumber);
|
2013-07-04 12:43:26 +02:00
|
|
|
dev.cpuAbi = getAbis(dev.serialNumber);
|
2014-03-10 15:18:46 +01:00
|
|
|
if (deviceType == QLatin1String("unauthorized"))
|
|
|
|
dev.state = AndroidDeviceInfo::UnAuthorizedState;
|
|
|
|
else if (deviceType == QLatin1String("offline"))
|
|
|
|
dev.state = AndroidDeviceInfo::OfflineState;
|
|
|
|
else
|
|
|
|
dev.state = AndroidDeviceInfo::OkState;
|
2012-04-18 20:30:57 +03:00
|
|
|
devices.push_back(dev);
|
|
|
|
}
|
2013-08-28 12:50:32 +02:00
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
qSort(devices.begin(), devices.end(), androidDevicesLessThan);
|
2013-07-03 17:58:48 +02:00
|
|
|
if (devices.isEmpty() && error)
|
2013-12-16 20:19:07 +01:00
|
|
|
*error = QApplication::translate("AndroidConfiguration",
|
|
|
|
"No devices found in output of: %1")
|
|
|
|
.arg(adbToolPath().toString() + QLatin1String(" devices"));
|
2012-04-18 20:30:57 +03:00
|
|
|
return devices;
|
|
|
|
}
|
|
|
|
|
2014-04-11 13:31:01 +02:00
|
|
|
AndroidConfig::CreateAvdInfo AndroidConfig::gatherCreateAVDInfo(QWidget *parent, int minApiLevel, QString targetArch) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2014-04-11 13:31:01 +02:00
|
|
|
CreateAvdInfo result;
|
2014-03-24 16:31:28 +01:00
|
|
|
AvdDialog d(minApiLevel, targetArch, this, parent);
|
|
|
|
if (d.exec() != QDialog::Accepted || !d.isValid())
|
2014-04-11 13:31:01 +02:00
|
|
|
return result;
|
2014-03-24 16:31:28 +01:00
|
|
|
|
2014-04-11 13:31:01 +02:00
|
|
|
result.target = d.target();
|
|
|
|
result.name = d.name();
|
|
|
|
result.abi = d.abi();
|
|
|
|
result.sdcardSize = d.sdcardSize();
|
|
|
|
return result;
|
|
|
|
}
|
2014-03-24 11:56:26 +01:00
|
|
|
|
2014-04-11 13:31:01 +02:00
|
|
|
QFuture<AndroidConfig::CreateAvdInfo> AndroidConfig::createAVD(CreateAvdInfo info) const
|
|
|
|
{
|
|
|
|
return QtConcurrent::run(&AndroidConfig::createAVDImpl, info, androidToolPath(), androidToolEnvironment());
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2014-04-11 13:31:01 +02:00
|
|
|
AndroidConfig::CreateAvdInfo AndroidConfig::createAVDImpl(CreateAvdInfo info, Utils::FileName androidToolPath, Utils::Environment env)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
|
|
|
QProcess proc;
|
2014-04-11 13:31:01 +02:00
|
|
|
proc.setProcessEnvironment(env.toProcessEnvironment());
|
|
|
|
QStringList arguments;
|
|
|
|
arguments << QLatin1String("create") << QLatin1String("avd")
|
|
|
|
<< QLatin1String("-t") << info.target
|
|
|
|
<< QLatin1String("-n") << info.name
|
|
|
|
<< QLatin1String("-b") << info.abi
|
|
|
|
<< QLatin1String("-c") << QString::fromLatin1("%1M").arg(info.sdcardSize);
|
|
|
|
proc.start(androidToolPath.toString(), arguments);
|
|
|
|
if (!proc.waitForStarted()) {
|
|
|
|
info.error = QApplication::translate("AndroidConfig", "Could not start process \"%1 %2\"")
|
|
|
|
.arg(androidToolPath.toString(), arguments.join(QLatin1String(" ")));
|
|
|
|
return info;
|
|
|
|
}
|
2013-10-10 17:19:28 +02:00
|
|
|
|
|
|
|
proc.write(QByteArray("yes\n")); // yes to "Do you wish to create a custom hardware profile"
|
|
|
|
|
|
|
|
QByteArray question;
|
|
|
|
while (true) {
|
|
|
|
proc.waitForReadyRead(500);
|
|
|
|
question += proc.readAllStandardOutput();
|
|
|
|
if (question.endsWith(QByteArray("]:"))) {
|
|
|
|
// truncate to last line
|
|
|
|
int index = question.lastIndexOf(QByteArray("\n"));
|
|
|
|
if (index != -1)
|
|
|
|
question = question.mid(index);
|
|
|
|
if (question.contains("hw.gpu.enabled"))
|
|
|
|
proc.write(QByteArray("yes\n"));
|
|
|
|
else
|
|
|
|
proc.write(QByteArray("\n"));
|
|
|
|
question.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (proc.state() != QProcess::Running)
|
|
|
|
break;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
2013-10-10 17:19:28 +02:00
|
|
|
|
|
|
|
proc.waitForFinished();
|
|
|
|
|
2014-03-24 11:56:26 +01:00
|
|
|
QString errorOutput = QString::fromLocal8Bit(proc.readAllStandardError());
|
|
|
|
// The exit code is always 0, so we need to check stderr
|
|
|
|
// For now assume that any output at all indicates a error
|
|
|
|
if (!errorOutput.isEmpty()) {
|
2014-04-11 13:31:01 +02:00
|
|
|
info.error = errorOutput;
|
2014-03-24 11:56:26 +01:00
|
|
|
}
|
|
|
|
|
2014-04-11 13:31:01 +02:00
|
|
|
return info;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
bool AndroidConfig::removeAVD(const QString &name) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
|
|
|
QProcess proc;
|
2013-11-19 17:25:32 +01:00
|
|
|
proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
|
2012-04-24 15:49:09 +02:00
|
|
|
proc.start(androidToolPath().toString(),
|
2012-04-18 20:30:57 +03:00
|
|
|
QStringList() << QLatin1String("delete") << QLatin1String("avd")
|
|
|
|
<< QLatin1String("-n") << name);
|
2013-11-21 15:54:03 +01:00
|
|
|
if (!proc.waitForFinished(5000)) {
|
2012-04-18 20:30:57 +03:00
|
|
|
proc.terminate();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return !proc.exitCode();
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
QVector<AndroidDeviceInfo> AndroidConfig::androidVirtualDevices() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2012-07-03 16:57:44 +03:00
|
|
|
QVector<AndroidDeviceInfo> devices;
|
2012-04-18 20:30:57 +03:00
|
|
|
QProcess proc;
|
2013-11-19 17:25:32 +01:00
|
|
|
proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
|
2012-04-24 15:49:09 +02:00
|
|
|
proc.start(androidToolPath().toString(),
|
2012-04-18 20:30:57 +03:00
|
|
|
QStringList() << QLatin1String("list") << QLatin1String("avd")); // list available AVDs
|
2013-11-21 15:54:03 +01:00
|
|
|
if (!proc.waitForFinished(5000)) {
|
2012-04-18 20:30:57 +03:00
|
|
|
proc.terminate();
|
|
|
|
return devices;
|
|
|
|
}
|
|
|
|
QList<QByteArray> avds = proc.readAll().trimmed().split('\n');
|
2013-10-22 13:51:17 +03:00
|
|
|
if (avds.empty())
|
|
|
|
return devices;
|
|
|
|
|
|
|
|
while (avds.first().startsWith("* daemon"))
|
|
|
|
avds.removeFirst(); // remove the daemon logs
|
|
|
|
avds.removeFirst(); // remove "List of devices attached" header line
|
|
|
|
|
2012-07-03 16:57:44 +03:00
|
|
|
AndroidDeviceInfo dev;
|
2012-04-18 20:30:57 +03:00
|
|
|
for (int i = 0; i < avds.size(); i++) {
|
|
|
|
QString line = QLatin1String(avds[i]);
|
|
|
|
if (!line.contains(QLatin1String("Name:")))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
dev.serialNumber = line.mid(line.indexOf(QLatin1Char(':')) + 2).trimmed();
|
|
|
|
++i;
|
|
|
|
for (; i < avds.size(); ++i) {
|
|
|
|
line = QLatin1String(avds[i]);
|
|
|
|
if (line.contains(QLatin1String("---------")))
|
|
|
|
break;
|
|
|
|
if (line.contains(QLatin1String("Target:")))
|
|
|
|
dev.sdk = line.mid(line.lastIndexOf(QLatin1Char(' '))).remove(QLatin1Char(')')).toInt();
|
2014-03-07 10:23:06 +02:00
|
|
|
if (line.contains(QLatin1String("Tag/ABI:")))
|
|
|
|
dev.cpuAbi = QStringList() << line.mid(line.lastIndexOf(QLatin1Char('/')) +1);
|
|
|
|
else if (line.contains(QLatin1String("ABI:")))
|
2013-07-04 12:43:26 +02:00
|
|
|
dev.cpuAbi = QStringList() << line.mid(line.lastIndexOf(QLatin1Char(' '))).trimmed();
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
2013-07-05 18:54:42 +02:00
|
|
|
// armeabi-v7a devices can also run armeabi code
|
|
|
|
if (dev.cpuAbi == QStringList(QLatin1String("armeabi-v7a")))
|
|
|
|
dev.cpuAbi << QLatin1String("armeabi");
|
2014-03-10 15:18:46 +01:00
|
|
|
dev.state = AndroidDeviceInfo::OkState;
|
2013-09-10 19:19:31 +02:00
|
|
|
dev.type = AndroidDeviceInfo::Emulator;
|
2012-04-18 20:30:57 +03:00
|
|
|
devices.push_back(dev);
|
|
|
|
}
|
|
|
|
qSort(devices.begin(), devices.end(), androidDevicesLessThan);
|
|
|
|
|
|
|
|
return devices;
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
QString AndroidConfig::startAVD(const QString &name, int apiLevel, QString cpuAbi) const
|
2013-07-05 18:54:42 +02:00
|
|
|
{
|
2013-11-13 16:32:38 +01:00
|
|
|
if (!findAvd(apiLevel, cpuAbi).isEmpty() || startAVDAsync(name))
|
2013-07-05 18:54:42 +02:00
|
|
|
return waitForAvd(apiLevel, cpuAbi);
|
|
|
|
return QString();
|
|
|
|
}
|
2012-04-18 20:30:57 +03:00
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
bool AndroidConfig::startAVDAsync(const QString &avdName) const
|
2013-07-05 18:54:42 +02:00
|
|
|
{
|
|
|
|
QProcess *avdProcess = new QProcess();
|
2013-12-16 20:19:07 +01:00
|
|
|
avdProcess->connect(avdProcess, SIGNAL(finished(int)), avdProcess, SLOT(deleteLater()));
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
// start the emulator
|
2012-10-24 10:03:11 +02:00
|
|
|
avdProcess->start(emulatorToolPath().toString(),
|
2013-12-16 20:19:07 +01:00
|
|
|
QStringList() << QLatin1String("-partition-size") << QString::number(partitionSize())
|
2012-04-18 20:30:57 +03:00
|
|
|
<< QLatin1String("-avd") << avdName);
|
2012-10-24 10:03:11 +02:00
|
|
|
if (!avdProcess->waitForStarted(-1)) {
|
|
|
|
delete avdProcess;
|
2013-07-05 18:54:42 +02:00
|
|
|
return false;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
2013-07-05 18:54:42 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
QString AndroidConfig::findAvd(int apiLevel, const QString &cpuAbi) const
|
2013-10-17 17:40:56 +02:00
|
|
|
{
|
|
|
|
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)
|
|
|
|
continue;
|
2013-11-13 16:32:38 +01:00
|
|
|
return device.serialNumber;
|
2013-10-17 17:40:56 +02:00
|
|
|
}
|
2013-11-13 16:32:38 +01:00
|
|
|
return QString();
|
2013-10-17 17:40:56 +02:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
bool AndroidConfig::isConnected(const QString &serialNumber) const
|
2013-07-05 18:54:42 +02:00
|
|
|
{
|
2013-11-13 16:35:29 +01:00
|
|
|
QVector<AndroidDeviceInfo> devices = connectedDevices();
|
|
|
|
foreach (AndroidDeviceInfo device, devices) {
|
|
|
|
if (device.serialNumber == serialNumber)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2013-07-05 18:54:42 +02:00
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
bool AndroidConfig::waitForBooted(const QString &serialNumber, const QFutureInterface<bool> &fi) const
|
2013-11-13 16:35:29 +01:00
|
|
|
{
|
|
|
|
// found a serial number, now wait until it's done booting...
|
|
|
|
for (int i = 0; i < 60; ++i) {
|
|
|
|
if (fi.isCanceled())
|
|
|
|
return false;
|
|
|
|
if (hasFinishedBooting(serialNumber)) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
Utils::sleep(2000);
|
|
|
|
if (!isConnected(serialNumber)) // device was disconnected
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
QString AndroidConfig::waitForAvd(int apiLevel, const QString &cpuAbi, const QFutureInterface<bool> &fi) const
|
2013-11-13 16:35:29 +01:00
|
|
|
{
|
|
|
|
// 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
|
2013-07-05 18:54:42 +02:00
|
|
|
QString serialNumber;
|
2013-11-13 16:35:29 +01:00
|
|
|
for (int i = 0; i < 60; ++i) {
|
|
|
|
if (fi.isCanceled())
|
2012-10-24 10:03:11 +02:00
|
|
|
return QString();
|
2013-11-13 16:35:29 +01:00
|
|
|
serialNumber = findAvd(apiLevel, cpuAbi);
|
|
|
|
if (!serialNumber.isEmpty())
|
|
|
|
return waitForBooted(serialNumber, fi) ? serialNumber : QString();
|
|
|
|
Utils::sleep(2000);
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
bool AndroidConfig::isBootToQt(const QString &device) const
|
2013-11-15 16:29:53 +01:00
|
|
|
{
|
|
|
|
// workaround for '????????????' serial numbers
|
|
|
|
QStringList arguments = AndroidDeviceInfo::adbSelector(device);
|
|
|
|
arguments << QLatin1String("shell")
|
|
|
|
<< QLatin1String("ls -l /system/bin/appcontroller || ls -l /usr/bin/appcontroller && echo Boot2Qt");
|
|
|
|
|
|
|
|
QProcess adbProc;
|
|
|
|
adbProc.start(adbToolPath().toString(), arguments);
|
2013-11-21 15:54:03 +01:00
|
|
|
if (!adbProc.waitForFinished(5000)) {
|
2013-11-15 16:29:53 +01:00
|
|
|
adbProc.kill();
|
2013-11-19 17:25:03 +01:00
|
|
|
return false;
|
2013-11-15 16:29:53 +01:00
|
|
|
}
|
|
|
|
return adbProc.readAll().contains("Boot2Qt");
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
int AndroidConfig::getSDKVersion(const QString &device) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-02-24 18:04:36 +04:00
|
|
|
// workaround for '????????????' serial numbers
|
|
|
|
QStringList arguments = AndroidDeviceInfo::adbSelector(device);
|
|
|
|
arguments << QLatin1String("shell") << QLatin1String("getprop")
|
|
|
|
<< QLatin1String("ro.build.version.sdk");
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
QProcess adbProc;
|
2013-02-24 18:04:36 +04:00
|
|
|
adbProc.start(adbToolPath().toString(), arguments);
|
2013-11-21 15:54:03 +01:00
|
|
|
if (!adbProc.waitForFinished(5000)) {
|
2012-12-10 23:43:21 +00:00
|
|
|
adbProc.kill();
|
2012-04-18 20:30:57 +03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return adbProc.readAll().trimmed().toInt();
|
|
|
|
}
|
|
|
|
|
2013-07-03 17:58:48 +02:00
|
|
|
//!
|
|
|
|
//! \brief AndroidConfigurations::getProductModel
|
|
|
|
//! \param device serial number
|
|
|
|
//! \return the produce model of the device or if that cannot be read the serial number
|
|
|
|
//!
|
2013-12-16 20:19:07 +01:00
|
|
|
QString AndroidConfig::getProductModel(const QString &device) const
|
2013-07-03 17:58:48 +02:00
|
|
|
{
|
2013-09-10 19:19:31 +02:00
|
|
|
if (m_serialNumberToDeviceName.contains(device))
|
|
|
|
return m_serialNumberToDeviceName.value(device);
|
2013-07-03 17:58:48 +02:00
|
|
|
// workaround for '????????????' serial numbers
|
|
|
|
QStringList arguments = AndroidDeviceInfo::adbSelector(device);
|
|
|
|
arguments << QLatin1String("shell") << QLatin1String("getprop")
|
|
|
|
<< QLatin1String("ro.product.model");
|
|
|
|
|
|
|
|
QProcess adbProc;
|
|
|
|
adbProc.start(adbToolPath().toString(), arguments);
|
2013-11-21 15:54:03 +01:00
|
|
|
if (!adbProc.waitForFinished(5000)) {
|
2013-07-03 17:58:48 +02:00
|
|
|
adbProc.kill();
|
|
|
|
return device;
|
|
|
|
}
|
|
|
|
QString model = QString::fromLocal8Bit(adbProc.readAll().trimmed());
|
|
|
|
if (model.isEmpty())
|
|
|
|
return device;
|
2013-09-10 19:19:31 +02:00
|
|
|
if (!device.startsWith(QLatin1String("????")))
|
|
|
|
m_serialNumberToDeviceName.insert(device, model);
|
2013-07-03 17:58:48 +02:00
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
bool AndroidConfig::hasFinishedBooting(const QString &device) const
|
2013-07-05 18:54:42 +02:00
|
|
|
{
|
|
|
|
QStringList arguments = AndroidDeviceInfo::adbSelector(device);
|
|
|
|
arguments << QLatin1String("shell") << QLatin1String("getprop")
|
|
|
|
<< QLatin1String("init.svc.bootanim");
|
|
|
|
|
|
|
|
QProcess adbProc;
|
|
|
|
adbProc.start(adbToolPath().toString(), arguments);
|
2013-11-21 15:54:03 +01:00
|
|
|
if (!adbProc.waitForFinished(5000)) {
|
2013-07-05 18:54:42 +02:00
|
|
|
adbProc.kill();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QString value = QString::fromLocal8Bit(adbProc.readAll().trimmed());
|
|
|
|
if (value == QLatin1String("stopped"))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
QStringList AndroidConfig::getAbis(const QString &device) const
|
2013-05-03 15:10:21 +02:00
|
|
|
{
|
|
|
|
QStringList result;
|
2013-11-15 16:45:55 +01:00
|
|
|
for (int i = 1; i < 6; ++i) {
|
2013-05-03 15:10:21 +02:00
|
|
|
QStringList arguments = AndroidDeviceInfo::adbSelector(device);
|
|
|
|
arguments << QLatin1String("shell") << QLatin1String("getprop");
|
|
|
|
if (i == 1)
|
|
|
|
arguments << QLatin1String("ro.product.cpu.abi");
|
|
|
|
else
|
|
|
|
arguments << QString::fromLatin1("ro.product.cpu.abi%1").arg(i);
|
|
|
|
|
|
|
|
QProcess adbProc;
|
|
|
|
adbProc.start(adbToolPath().toString(), arguments);
|
2013-11-21 15:54:03 +01:00
|
|
|
if (!adbProc.waitForFinished(5000)) {
|
2013-05-03 15:10:21 +02:00
|
|
|
adbProc.kill();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
QString abi = QString::fromLocal8Bit(adbProc.readAll().trimmed());
|
|
|
|
if (abi.isEmpty())
|
|
|
|
break;
|
|
|
|
result << abi;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-03-24 16:31:28 +01:00
|
|
|
SdkPlatform AndroidConfig::highestAndroidSdk() const
|
2013-09-17 18:24:57 +02:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
updateAvailableSdkPlatforms();
|
2013-10-17 13:23:08 +02:00
|
|
|
if (m_availableSdkPlatforms.isEmpty())
|
2014-03-24 16:31:28 +01:00
|
|
|
return SdkPlatform();
|
|
|
|
return m_availableSdkPlatforms.first();
|
2013-09-17 18:24:57 +02:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
QString AndroidConfig::bestNdkPlatformMatch(const QString &targetAPI) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
updateNdkInformation();
|
2012-04-18 20:30:57 +03:00
|
|
|
int target = targetAPI.mid(targetAPI.lastIndexOf(QLatin1Char('-')) + 1).toInt();
|
2013-10-17 13:12:45 +02:00
|
|
|
foreach (int apiLevel, m_availableNdkPlatforms) {
|
2012-04-18 20:30:57 +03:00
|
|
|
if (apiLevel <= target)
|
|
|
|
return QString::fromLatin1("android-%1").arg(apiLevel);
|
|
|
|
}
|
|
|
|
return QLatin1String("android-8");
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::sdkLocation() const
|
2013-05-16 15:49:24 +02:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
return m_sdkLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setSdkLocation(const FileName &sdkLocation)
|
|
|
|
{
|
|
|
|
m_sdkLocation = sdkLocation;
|
|
|
|
m_availableSdkPlatformsUpToDate = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileName AndroidConfig::ndkLocation() const
|
|
|
|
{
|
|
|
|
return m_ndkLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setNdkLocation(const FileName &ndkLocation)
|
|
|
|
{
|
|
|
|
m_ndkLocation = ndkLocation;
|
|
|
|
m_NdkInformationUpToDate = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileName AndroidConfig::antLocation() const
|
|
|
|
{
|
|
|
|
return m_antLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setAntLocation(const FileName &antLocation)
|
|
|
|
{
|
|
|
|
m_antLocation = antLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileName AndroidConfig::openJDKLocation() const
|
|
|
|
{
|
|
|
|
return m_openJDKLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setOpenJDKLocation(const FileName &openJDKLocation)
|
|
|
|
{
|
|
|
|
m_openJDKLocation = openJDKLocation;
|
|
|
|
m_availableSdkPlatformsUpToDate = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileName AndroidConfig::keystoreLocation() const
|
|
|
|
{
|
|
|
|
return m_keystoreLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setKeystoreLocation(const FileName &keystoreLocation)
|
|
|
|
{
|
|
|
|
m_keystoreLocation = keystoreLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidConfig::toolchainHost() const
|
|
|
|
{
|
|
|
|
updateNdkInformation();
|
|
|
|
return m_toolchainHost;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList AndroidConfig::makeExtraSearchDirectories() const
|
|
|
|
{
|
|
|
|
return m_makeExtraSearchDirectories;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned AndroidConfig::partitionSize() const
|
|
|
|
{
|
|
|
|
return m_partitionSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setPartitionSize(unsigned partitionSize)
|
|
|
|
{
|
|
|
|
m_partitionSize = partitionSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AndroidConfig::automaticKitCreation() const
|
|
|
|
{
|
|
|
|
return m_automaticKitCreation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setAutomaticKitCreation(bool b)
|
|
|
|
{
|
|
|
|
m_automaticKitCreation = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////
|
|
|
|
// AndroidConfigurations
|
|
|
|
///////////////////////////////////
|
|
|
|
void AndroidConfigurations::setConfig(const AndroidConfig &devConfigs)
|
|
|
|
{
|
|
|
|
m_instance->m_config = devConfigs;
|
|
|
|
|
|
|
|
m_instance->save();
|
|
|
|
m_instance->updateAndroidDevice();
|
2014-03-11 13:05:36 +01:00
|
|
|
m_instance->updateToolChainList();
|
|
|
|
m_instance->updateAutomaticKitList();
|
2013-12-16 20:19:07 +01:00
|
|
|
emit m_instance->updated();
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(ProjectExplorer::Project *project, int apiLevel, const QString &abi)
|
|
|
|
{
|
|
|
|
QString serialNumber = defaultDevice(project, abi);
|
|
|
|
if (!serialNumber.isEmpty()) {
|
|
|
|
// search for that device
|
|
|
|
foreach (const AndroidDeviceInfo &info, AndroidConfigurations::currentConfig().connectedDevices())
|
|
|
|
if (info.serialNumber == serialNumber
|
|
|
|
&& info.sdk >= apiLevel)
|
|
|
|
return info;
|
|
|
|
|
|
|
|
foreach (const AndroidDeviceInfo &info, AndroidConfigurations::currentConfig().androidVirtualDevices())
|
|
|
|
if (info.serialNumber == serialNumber
|
|
|
|
&& info.sdk >= apiLevel)
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidDeviceDialog dialog(apiLevel, abi, Core::ICore::mainWindow());
|
|
|
|
if (dialog.exec() == QDialog::Accepted) {
|
|
|
|
AndroidDeviceInfo info = dialog.device();
|
|
|
|
if (dialog.saveDeviceSelection()) {
|
|
|
|
if (!info.serialNumber.isEmpty())
|
|
|
|
AndroidConfigurations::setDefaultDevice(project, abi, info.serialNumber);
|
|
|
|
}
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
return AndroidDeviceInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfigurations::clearDefaultDevices(ProjectExplorer::Project *project)
|
|
|
|
{
|
|
|
|
if (m_instance->m_defaultDeviceForAbi.contains(project))
|
|
|
|
m_instance->m_defaultDeviceForAbi.remove(project);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfigurations::setDefaultDevice(ProjectExplorer::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);
|
2013-05-16 15:49:24 +02:00
|
|
|
}
|
|
|
|
|
2013-08-08 19:15:23 +03:00
|
|
|
static bool equalKits(Kit *a, Kit *b)
|
2013-02-14 15:51:59 +01:00
|
|
|
{
|
|
|
|
return ToolChainKitInformation::toolChain(a) == ToolChainKitInformation::toolChain(b)
|
|
|
|
&& QtSupport::QtKitInformation::qtVersion(a) == QtSupport::QtKitInformation::qtVersion(b);
|
|
|
|
}
|
|
|
|
|
2014-03-11 13:05:36 +01:00
|
|
|
void AndroidConfigurations::updateToolChainList()
|
|
|
|
{
|
|
|
|
QList<ToolChain *> existingToolChains = ToolChainManager::toolChains();
|
|
|
|
QList<ToolChain *> toolchains = AndroidToolChainFactory::createToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation());
|
|
|
|
foreach (ToolChain *tc, toolchains) {
|
|
|
|
bool found = false;
|
|
|
|
for (int i = 0; i < existingToolChains.count(); ++i) {
|
|
|
|
if (*(existingToolChains.at(i)) == *tc) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found)
|
|
|
|
delete tc;
|
|
|
|
else
|
|
|
|
ToolChainManager::registerToolChain(tc);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (ToolChain *tc, existingToolChains) {
|
|
|
|
if (tc->type() == QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE)) {
|
|
|
|
if (!tc->isValid())
|
|
|
|
ToolChainManager::deregisterToolChain(tc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-14 15:51:59 +01:00
|
|
|
void AndroidConfigurations::updateAutomaticKitList()
|
|
|
|
{
|
|
|
|
QList<AndroidToolChain *> toolchains;
|
2013-12-16 20:19:07 +01:00
|
|
|
if (AndroidConfigurations::currentConfig().automaticKitCreation()) {
|
2013-02-14 15:51:59 +01:00
|
|
|
// having a empty toolchains list will remove all autodetected kits for android
|
|
|
|
// exactly what we want in that case
|
2013-08-29 13:14:19 +02:00
|
|
|
foreach (ToolChain *tc, ToolChainManager::toolChains()) {
|
2013-02-14 15:51:59 +01:00
|
|
|
if (!tc->isAutoDetected())
|
|
|
|
continue;
|
|
|
|
if (tc->type() != QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE))
|
|
|
|
continue;
|
|
|
|
toolchains << static_cast<AndroidToolChain *>(tc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<Kit *> existingKits;
|
|
|
|
|
2013-08-23 09:21:18 +02:00
|
|
|
foreach (Kit *k, KitManager::kits()) {
|
2014-03-27 16:35:17 +01:00
|
|
|
if (DeviceTypeKitInformation::deviceTypeId(k) != Core::Id(Constants::ANDROID_DEVICE_TYPE))
|
2013-02-14 15:51:59 +01:00
|
|
|
continue;
|
|
|
|
if (!k->isAutoDetected())
|
|
|
|
continue;
|
2013-02-20 17:05:00 +01:00
|
|
|
if (k->isSdkProvided())
|
|
|
|
continue;
|
2013-02-14 15:51:59 +01:00
|
|
|
|
2013-10-23 13:24:36 +02:00
|
|
|
// Update code for 3.0 beta, which shipped with a bug for the debugger settings
|
|
|
|
ProjectExplorer::ToolChain *tc =ToolChainKitInformation::toolChain(k);
|
|
|
|
if (tc && Debugger::DebuggerKitInformation::debuggerCommand(k) != tc->suggestedDebugger()) {
|
|
|
|
Debugger::DebuggerItem debugger;
|
|
|
|
debugger.setCommand(tc->suggestedDebugger());
|
|
|
|
debugger.setEngineType(Debugger::GdbEngineType);
|
|
|
|
debugger.setDisplayName(tr("Android Debugger for %1").arg(tc->displayName()));
|
|
|
|
debugger.setAutoDetected(true);
|
|
|
|
debugger.setAbi(tc->targetAbi());
|
|
|
|
QVariant id = Debugger::DebuggerItemManager::registerDebugger(debugger);
|
|
|
|
Debugger::DebuggerKitInformation::setDebugger(k, id);
|
|
|
|
}
|
2013-02-14 15:51:59 +01:00
|
|
|
existingKits << k;
|
|
|
|
}
|
|
|
|
|
2013-08-23 09:21:18 +02:00
|
|
|
QMap<Abi::Architecture, QList<QtSupport::BaseQtVersion *> > qtVersionsForArch;
|
2013-08-29 14:11:29 +02:00
|
|
|
foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::versions()) {
|
2013-02-14 15:51:59 +01:00
|
|
|
if (qtVersion->type() != QLatin1String(Constants::ANDROIDQT))
|
|
|
|
continue;
|
2013-08-23 09:21:18 +02:00
|
|
|
QList<Abi> qtAbis = qtVersion->qtAbis();
|
2013-02-25 09:17:43 +02:00
|
|
|
if (qtAbis.empty())
|
|
|
|
continue;
|
|
|
|
qtVersionsForArch[qtAbis.first().architecture()].append(qtVersion);
|
2013-02-14 15:51:59 +01:00
|
|
|
}
|
|
|
|
|
2013-08-23 09:21:18 +02:00
|
|
|
DeviceManager *dm = DeviceManager::instance();
|
2013-10-30 17:02:28 +01:00
|
|
|
IDevice::ConstPtr device = dm->find(Core::Id(Constants::ANDROID_DEVICE_ID));
|
|
|
|
if (device.isNull()) {
|
|
|
|
// no device, means no sdk path
|
|
|
|
foreach (Kit *k, existingKits)
|
|
|
|
KitManager::deregisterKit(k);
|
|
|
|
return;
|
|
|
|
}
|
2013-02-14 15:51:59 +01:00
|
|
|
|
|
|
|
// register new kits
|
|
|
|
QList<Kit *> newKits;
|
|
|
|
foreach (AndroidToolChain *tc, toolchains) {
|
2013-10-11 11:29:06 +02:00
|
|
|
if (tc->isSecondaryToolChain())
|
2013-10-10 18:04:27 +02:00
|
|
|
continue;
|
2013-02-14 15:51:59 +01:00
|
|
|
QList<QtSupport::BaseQtVersion *> qtVersions = qtVersionsForArch.value(tc->targetAbi().architecture());
|
|
|
|
foreach (QtSupport::BaseQtVersion *qt, qtVersions) {
|
|
|
|
Kit *newKit = new Kit;
|
|
|
|
newKit->setAutoDetected(true);
|
2013-08-21 13:04:00 +02:00
|
|
|
newKit->setIconPath(Utils::FileName::fromString(QLatin1String(Constants::ANDROID_SETTINGS_CATEGORY_ICON)));
|
2013-02-14 15:51:59 +01:00
|
|
|
DeviceTypeKitInformation::setDeviceTypeId(newKit, Core::Id(Constants::ANDROID_DEVICE_TYPE));
|
|
|
|
ToolChainKitInformation::setToolChain(newKit, tc);
|
|
|
|
QtSupport::QtKitInformation::setQtVersion(newKit, qt);
|
|
|
|
DeviceKitInformation::setDevice(newKit, device);
|
2013-10-10 18:02:56 +02:00
|
|
|
|
|
|
|
Debugger::DebuggerItem debugger;
|
|
|
|
debugger.setCommand(tc->suggestedDebugger());
|
|
|
|
debugger.setEngineType(Debugger::GdbEngineType);
|
|
|
|
debugger.setDisplayName(tr("Android Debugger for %1").arg(tc->displayName()));
|
|
|
|
debugger.setAutoDetected(true);
|
|
|
|
debugger.setAbi(tc->targetAbi());
|
2013-10-18 19:27:31 +02:00
|
|
|
QVariant id = Debugger::DebuggerItemManager::registerDebugger(debugger);
|
|
|
|
Debugger::DebuggerKitInformation::setDebugger(newKit, id);
|
2013-10-10 18:02:56 +02:00
|
|
|
|
2013-02-14 15:51:59 +01:00
|
|
|
AndroidGdbServerKitInformation::setGdbSever(newKit, tc->suggestedGdbServer());
|
2013-08-01 14:43:32 +02:00
|
|
|
newKit->makeSticky();
|
2013-02-14 15:51:59 +01:00
|
|
|
newKits << newKit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = existingKits.count() - 1; i >= 0; --i) {
|
|
|
|
Kit *existingKit = existingKits.at(i);
|
|
|
|
for (int j = 0; j < newKits.count(); ++j) {
|
|
|
|
Kit *newKit = newKits.at(j);
|
|
|
|
if (equalKits(existingKit, newKit)) {
|
|
|
|
// Kit is already registered, nothing to do
|
|
|
|
newKits.removeAt(j);
|
2013-08-29 14:42:07 +02:00
|
|
|
existingKits.at(i)->makeSticky();
|
2013-02-14 15:51:59 +01:00
|
|
|
existingKits.removeAt(i);
|
|
|
|
KitManager::deleteKit(newKit);
|
|
|
|
j = newKits.count();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-28 13:34:24 +02:00
|
|
|
foreach (Kit *k, existingKits) {
|
|
|
|
ProjectExplorer::ToolChain *tc = ToolChainKitInformation::toolChain(k);
|
2013-10-08 16:32:00 +02:00
|
|
|
QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(k);
|
|
|
|
if (tc && tc->type() == QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE)
|
|
|
|
&& qtVersion && qtVersion->type() == QLatin1String(Constants::ANDROIDQT)) {
|
2013-08-28 13:34:24 +02:00
|
|
|
k->makeUnSticky();
|
|
|
|
k->setAutoDetected(false);
|
|
|
|
} else {
|
|
|
|
KitManager::deregisterKit(k);
|
|
|
|
}
|
|
|
|
}
|
2013-02-14 15:51:59 +01:00
|
|
|
|
2013-02-27 13:08:54 +01:00
|
|
|
foreach (Kit *kit, newKits) {
|
|
|
|
AndroidToolChain *tc = static_cast<AndroidToolChain *>(ToolChainKitInformation::toolChain(kit));
|
2013-08-01 12:49:47 +02:00
|
|
|
AndroidQtVersion *qt = static_cast<AndroidQtVersion *>(QtSupport::QtKitInformation::qtVersion(kit));
|
2013-02-27 13:08:54 +01:00
|
|
|
kit->setDisplayName(tr("Android for %1 (GCC %2, Qt %3)")
|
2013-08-01 12:49:47 +02:00
|
|
|
.arg(qt->targetArch())
|
2013-02-27 13:08:54 +01:00
|
|
|
.arg(tc->ndkToolChainVersion())
|
|
|
|
.arg(qt->qtVersionString()));
|
2013-08-21 12:48:46 +02:00
|
|
|
KitManager::registerKit(kit);
|
2013-02-27 13:08:54 +01:00
|
|
|
}
|
2013-02-14 15:51:59 +01:00
|
|
|
}
|
|
|
|
|
2013-02-24 18:04:36 +04:00
|
|
|
/**
|
|
|
|
* Workaround for '????????????' serial numbers
|
|
|
|
* @return ("-d") for buggy devices, ("-s", <serial no>) for normal
|
|
|
|
*/
|
|
|
|
QStringList AndroidDeviceInfo::adbSelector(const QString &serialNumber)
|
|
|
|
{
|
|
|
|
if (serialNumber.startsWith(QLatin1String("????")))
|
|
|
|
return QStringList() << QLatin1String("-d");
|
|
|
|
return QStringList() << QLatin1String("-s") << serialNumber;
|
|
|
|
}
|
|
|
|
|
2014-03-07 13:44:20 +01:00
|
|
|
const AndroidConfig &AndroidConfigurations::currentConfig()
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
return m_instance->m_config; // ensure that m_instance is initialized
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidConfigurations *AndroidConfigurations::instance()
|
|
|
|
{
|
|
|
|
return m_instance;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfigurations::save()
|
|
|
|
{
|
2013-09-20 23:17:22 +02:00
|
|
|
QSettings *settings = Core::ICore::settings();
|
2012-04-18 20:30:57 +03:00
|
|
|
settings->beginGroup(SettingsGroup);
|
|
|
|
m_config.save(*settings);
|
|
|
|
settings->endGroup();
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidConfigurations::AndroidConfigurations(QObject *parent)
|
|
|
|
: QObject(parent)
|
|
|
|
{
|
|
|
|
load();
|
2013-09-10 19:19:31 +02:00
|
|
|
|
|
|
|
connect(ProjectExplorer::SessionManager::instance(), SIGNAL(projectRemoved(ProjectExplorer::Project*)),
|
|
|
|
this, SLOT(clearDefaultDevices(ProjectExplorer::Project*)));
|
2013-12-16 20:19:07 +01:00
|
|
|
|
|
|
|
m_instance = this;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-10-08 15:25:34 +02:00
|
|
|
Utils::FileName javaHomeForJavac(const QString &location)
|
|
|
|
{
|
|
|
|
QFileInfo fileInfo(location);
|
|
|
|
int tries = 5;
|
|
|
|
while (tries > 0) {
|
|
|
|
QDir dir = fileInfo.dir();
|
|
|
|
dir.cdUp();
|
|
|
|
if (QFileInfo(dir.filePath(QLatin1String("lib/tools.jar"))).exists())
|
|
|
|
return Utils::FileName::fromString(dir.path());
|
|
|
|
if (fileInfo.isSymLink())
|
|
|
|
fileInfo.setFile(fileInfo.symLinkTarget());
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
--tries;
|
|
|
|
}
|
|
|
|
return Utils::FileName();
|
|
|
|
}
|
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
void AndroidConfigurations::load()
|
|
|
|
{
|
2013-06-10 18:19:08 +02:00
|
|
|
bool saveSettings = false;
|
2013-09-20 23:17:22 +02:00
|
|
|
QSettings *settings = Core::ICore::settings();
|
2012-04-18 20:30:57 +03:00
|
|
|
settings->beginGroup(SettingsGroup);
|
2013-12-16 20:19:07 +01:00
|
|
|
m_config.load(*settings);
|
2013-04-17 11:52:16 +02:00
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
if (m_config.antLocation().isEmpty()) {
|
2013-08-23 09:21:18 +02:00
|
|
|
Environment env = Environment::systemEnvironment();
|
2013-04-17 11:52:16 +02:00
|
|
|
QString location = env.searchInPath(QLatin1String("ant"));
|
|
|
|
QFileInfo fi(location);
|
2013-06-10 18:19:08 +02:00
|
|
|
if (fi.exists() && fi.isExecutable() && !fi.isDir()) {
|
2013-12-16 20:19:07 +01:00
|
|
|
m_config.setAntLocation(FileName::fromString(location));
|
2013-06-10 18:19:08 +02:00
|
|
|
saveSettings = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
if (m_config.openJDKLocation().isEmpty()) {
|
2013-10-08 15:25:34 +02:00
|
|
|
if (HostOsInfo::isLinuxHost()) {
|
|
|
|
Environment env = Environment::systemEnvironment();
|
|
|
|
QString location = env.searchInPath(QLatin1String("javac"));
|
|
|
|
QFileInfo fi(location);
|
|
|
|
if (fi.exists() && fi.isExecutable() && !fi.isDir()) {
|
2013-12-16 20:19:07 +01:00
|
|
|
m_config.setOpenJDKLocation(javaHomeForJavac(location));
|
2013-10-08 15:25:34 +02:00
|
|
|
saveSettings = true;
|
|
|
|
}
|
|
|
|
} else if (HostOsInfo::isMacHost()) {
|
|
|
|
QString javaHome = QLatin1String("/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home");
|
|
|
|
if (QFileInfo(javaHome).exists())
|
2013-12-16 20:19:07 +01:00
|
|
|
m_config.setOpenJDKLocation(Utils::FileName::fromString(javaHome));
|
2013-08-23 09:21:18 +02:00
|
|
|
} else if (HostOsInfo::isWindowsHost()) {
|
2013-06-10 18:19:08 +02:00
|
|
|
QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Javasoft\\Java Development Kit"), QSettings::NativeFormat);
|
|
|
|
QStringList allVersions = settings.childGroups();
|
|
|
|
QString javaHome;
|
|
|
|
int major = -1;
|
|
|
|
int minor = -1;
|
|
|
|
foreach (const QString &version, allVersions) {
|
|
|
|
QStringList parts = version.split(QLatin1String("."));
|
|
|
|
if (parts.size() != 2) // not interested in 1.7.0_u21
|
|
|
|
continue;
|
|
|
|
bool okMajor, okMinor;
|
|
|
|
int tmpMajor = parts.at(0).toInt(&okMajor);
|
|
|
|
int tmpMinor = parts.at(1).toInt(&okMinor);
|
|
|
|
if (!okMajor || !okMinor)
|
|
|
|
continue;
|
|
|
|
if (tmpMajor > major
|
|
|
|
|| (tmpMajor == major
|
|
|
|
&& tmpMinor > minor)) {
|
|
|
|
settings.beginGroup(version);
|
|
|
|
QString tmpJavaHome = settings.value(QLatin1String("JavaHome")).toString();
|
|
|
|
settings.endGroup();
|
|
|
|
if (!QFileInfo(tmpJavaHome).exists())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
major = tmpMajor;
|
|
|
|
minor = tmpMinor;
|
|
|
|
javaHome = tmpJavaHome;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!javaHome.isEmpty()) {
|
2013-12-16 20:19:07 +01:00
|
|
|
m_config.setOpenJDKLocation(FileName::fromString(javaHome));
|
2013-06-10 18:19:08 +02:00
|
|
|
saveSettings = true;
|
|
|
|
}
|
|
|
|
}
|
2013-04-17 11:52:16 +02:00
|
|
|
}
|
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
settings->endGroup();
|
2013-06-10 18:19:08 +02:00
|
|
|
|
|
|
|
if (saveSettings)
|
|
|
|
save();
|
2013-03-27 15:49:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfigurations::updateAndroidDevice()
|
|
|
|
{
|
2013-08-23 09:21:18 +02:00
|
|
|
DeviceManager * const devMgr = DeviceManager::instance();
|
2013-12-16 20:19:07 +01:00
|
|
|
if (m_instance->m_config.adbToolPath().toFileInfo().exists())
|
2013-08-23 09:21:18 +02:00
|
|
|
devMgr->addDevice(IDevice::Ptr(new Internal::AndroidDevice));
|
2013-04-10 11:05:33 +02:00
|
|
|
else if (devMgr->find(Constants::ANDROID_DEVICE_ID))
|
|
|
|
devMgr->removeDevice(Core::Id(Constants::ANDROID_DEVICE_ID));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
AndroidConfigurations *AndroidConfigurations::m_instance = 0;
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
} // namespace Android
|