2016-01-15 14:57:40 +01:00
|
|
|
/****************************************************************************
|
2012-04-18 20:30:57 +03:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2012-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
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2012-04-18 20:30:57 +03:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2012-04-18 20:30:57 +03:00
|
|
|
**
|
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"
|
2017-03-30 14:43:13 +02:00
|
|
|
#include "androidmanager.h"
|
2013-08-01 12:49:47 +02:00
|
|
|
#include "androidqtversion.h"
|
2013-09-10 19:19:31 +02:00
|
|
|
#include "androiddevicedialog.h"
|
2017-03-30 14:47:34 +02:00
|
|
|
#include "androidsdkmanager.h"
|
2017-03-30 14:43:13 +02:00
|
|
|
#include "androidtoolmanager.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>
|
2013-02-14 15:51:59 +01:00
|
|
|
#include <projectexplorer/kitmanager.h>
|
|
|
|
#include <projectexplorer/kitinformation.h>
|
|
|
|
#include <projectexplorer/devicesupport/devicemanager.h>
|
2016-04-29 23:06:26 +02:00
|
|
|
#include <projectexplorer/project.h>
|
2013-02-14 15:51:59 +01:00
|
|
|
#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>
|
2015-02-26 15:29:28 +01:00
|
|
|
#include <debugger/debuggeritem.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>
|
2014-06-16 18:25:52 +04:00
|
|
|
#include <utils/algorithm.h>
|
2013-04-17 11:52:16 +02:00
|
|
|
#include <utils/environment.h>
|
2016-04-29 23:06:26 +02:00
|
|
|
#include <utils/hostosinfo.h>
|
|
|
|
#include <utils/persistentsettings.h>
|
2016-04-29 16:52:58 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2016-02-05 15:06:15 +01:00
|
|
|
#include <utils/runextensions.h>
|
2016-04-29 16:52:58 +02:00
|
|
|
#include <utils/synchronousprocess.h>
|
2017-10-10 09:58:19 +02:00
|
|
|
#include <utils/environment.h>
|
2012-04-18 20:30:57 +03:00
|
|
|
|
2016-04-29 23:06:26 +02:00
|
|
|
#include <QApplication>
|
|
|
|
#include <QDirIterator>
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QHostAddress>
|
2017-05-05 12:26:23 +02:00
|
|
|
#include <QLoggingCategory>
|
2016-04-29 23:06:26 +02:00
|
|
|
#include <QProcess>
|
2017-05-05 12:26:23 +02:00
|
|
|
#include <QRegularExpression>
|
2012-04-18 20:30:57 +03:00
|
|
|
#include <QSettings>
|
|
|
|
#include <QStringList>
|
2015-04-23 16:25:44 +02:00
|
|
|
#include <QTcpSocket>
|
2016-09-20 11:22:05 +03:00
|
|
|
#include <QThread>
|
2012-04-18 20:30:57 +03:00
|
|
|
|
2014-06-19 14:16:45 +02:00
|
|
|
#include <functional>
|
2017-08-08 14:27:54 +02:00
|
|
|
#include <memory>
|
2014-06-19 14:16:45 +02:00
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
using namespace ProjectExplorer;
|
2012-04-18 20:30:57 +03:00
|
|
|
using namespace Utils;
|
|
|
|
|
2017-05-05 12:26:23 +02:00
|
|
|
namespace {
|
|
|
|
Q_LOGGING_CATEGORY(avdConfigLog, "qtc.android.androidconfig")
|
|
|
|
}
|
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
namespace Android {
|
2014-06-25 15:42:11 +02:00
|
|
|
using namespace Internal;
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
namespace {
|
2017-08-08 14:27:54 +02:00
|
|
|
const char jdkSettingsPath[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit";
|
2017-04-12 14:08:17 +02:00
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String SettingsGroup("AndroidConfigurations");
|
|
|
|
const QLatin1String SDKLocationKey("SDKLocation");
|
2017-09-27 15:26:59 +02:00
|
|
|
const QLatin1String SDKManagerToolArgsKey("SDKManagerToolArgs");
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String NDKLocationKey("NDKLocation");
|
|
|
|
const QLatin1String OpenJDKLocationKey("OpenJDKLocation");
|
|
|
|
const QLatin1String KeystoreLocationKey("KeystoreLocation");
|
2013-02-14 15:51:59 +01:00
|
|
|
const QLatin1String AutomaticKitCreationKey("AutomatiKitCreation");
|
2018-02-09 17:20:22 +01:00
|
|
|
const QLatin1String DeviceQmlsceneCommandKey("DeviceQmlsceneCommand");
|
2013-05-16 15:49:24 +02:00
|
|
|
const QLatin1String MakeExtraSearchDirectory("MakeExtraSearchDirectory");
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String PartitionSizeKey("PartitionSize");
|
2013-04-04 01:29:47 -07:00
|
|
|
const QLatin1String ToolchainHostKey("ToolchainHost");
|
2014-11-18 18:37:05 +01:00
|
|
|
|
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");
|
2017-05-24 14:14:39 -07:00
|
|
|
const QLatin1String Mips64ToolchainPrefix("mips64el-linux-android");
|
2014-11-18 18:37:05 +01:00
|
|
|
const QLatin1String AArch64ToolchainPrefix("aarch64-linux-android");
|
|
|
|
const QLatin1String X86_64ToolchainPrefix("x86_64");
|
|
|
|
|
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");
|
2017-05-24 14:14:39 -07:00
|
|
|
const QLatin1String Mips64ToolsPrefix("mips64el-linux-android");
|
2014-11-18 18:37:05 +01:00
|
|
|
const QLatin1String AArch64ToolsPrefix("aarch64-linux-android");
|
|
|
|
const QLatin1String X86_64ToolsPrefix("x86_64-linux-android");
|
|
|
|
|
|
|
|
const QLatin1String ArmToolsDisplayName("arm");
|
|
|
|
const QLatin1String X86ToolsDisplayName("i686");
|
|
|
|
const QLatin1String MipsToolsDisplayName("mipsel");
|
2017-05-24 14:14:39 -07:00
|
|
|
const QLatin1String Mips64ToolsDisplayName("mips64el");
|
2014-11-18 18:37:05 +01:00
|
|
|
const QLatin1String AArch64ToolsDisplayName("aarch64");
|
|
|
|
const QLatin1String X86_64ToolsDisplayName("x86_64");
|
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
const QLatin1String Unknown("unknown");
|
|
|
|
const QLatin1String keytoolName("keytool");
|
|
|
|
const QLatin1String changeTimeStamp("ChangeTimeStamp");
|
|
|
|
|
2017-03-30 14:47:34 +02:00
|
|
|
const QLatin1String sdkToolsVersionKey("Pkg.Revision");
|
2017-05-05 12:26:23 +02:00
|
|
|
const QLatin1String ndkRevisionKey("Pkg.Revision");
|
2017-03-30 14:47:34 +02:00
|
|
|
|
2018-02-09 17:20:22 +01:00
|
|
|
const QLatin1String defaultQmlScene("org.qtproject.example.qmlscene/"
|
|
|
|
"org.qtproject.qt5.android.bindings.QtActivity");
|
|
|
|
|
2012-12-07 19:52:47 +02:00
|
|
|
static QString sdkSettingsFileName()
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2018-01-10 17:29:27 +01:00
|
|
|
return Core::ICore::installerResourcePath() + "/android.xml";
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2014-10-31 16:09:34 +01:00
|
|
|
static bool is32BitUserSpace()
|
|
|
|
{
|
|
|
|
// Do the exact same check as android's emulator is doing:
|
2015-02-03 23:50:37 +02:00
|
|
|
if (HostOsInfo::isLinuxHost()) {
|
2014-10-31 16:09:34 +01:00
|
|
|
if (QSysInfo::WordSize == 32 ) {
|
2015-02-03 23:50:37 +02:00
|
|
|
Environment env = Environment::systemEnvironment();
|
2014-10-31 16:09:34 +01:00
|
|
|
QString executable = env.searchInPath(QLatin1String("file")).toString();
|
|
|
|
QString shell = env.value(QLatin1String("SHELL"));
|
|
|
|
if (executable.isEmpty() || shell.isEmpty())
|
|
|
|
return true; // we can't detect, but creator is 32bit so assume 32bit
|
|
|
|
|
2016-04-29 16:52:58 +02:00
|
|
|
SynchronousProcess proc;
|
2014-10-31 16:09:34 +01:00
|
|
|
proc.setProcessChannelMode(QProcess::MergedChannels);
|
2016-04-29 16:52:58 +02:00
|
|
|
proc.setTimeoutS(30);
|
2017-02-07 16:59:21 +01:00
|
|
|
SynchronousProcessResponse response = proc.runBlocking(executable, QStringList(shell));
|
2016-04-29 16:52:58 +02:00
|
|
|
if (response.result != SynchronousProcessResponse::Finished)
|
2014-10-31 16:09:34 +01:00
|
|
|
return true;
|
2016-04-29 16:52:58 +02:00
|
|
|
return !response.allOutput().contains("x86-64");
|
2014-10-31 16:09:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
//////////////////////////////////
|
|
|
|
// AndroidConfig
|
|
|
|
//////////////////////////////////
|
|
|
|
|
2014-11-18 18:37:05 +01:00
|
|
|
Abi AndroidConfig::abiForToolChainPrefix(const QString &toolchainPrefix)
|
|
|
|
{
|
|
|
|
Abi::Architecture arch = Abi::UnknownArchitecture;
|
|
|
|
unsigned char wordWidth = 32;
|
|
|
|
if (toolchainPrefix == ArmToolchainPrefix) {
|
|
|
|
arch = Abi::ArmArchitecture;
|
|
|
|
} else if (toolchainPrefix == X86ToolchainPrefix) {
|
|
|
|
arch = Abi::X86Architecture;
|
|
|
|
} else if (toolchainPrefix == MipsToolchainPrefix) {
|
|
|
|
arch = Abi::MipsArchitecture;
|
|
|
|
} else if (toolchainPrefix == AArch64ToolchainPrefix) {
|
|
|
|
arch = Abi::ArmArchitecture;
|
|
|
|
wordWidth = 64;
|
|
|
|
} else if (toolchainPrefix == X86_64ToolchainPrefix) {
|
|
|
|
arch = Abi::X86Architecture;
|
|
|
|
wordWidth = 64;
|
2017-05-24 14:14:39 -07:00
|
|
|
} else if (toolchainPrefix == Mips64ToolchainPrefix) {
|
|
|
|
arch = Abi::MipsArchitecture;
|
|
|
|
wordWidth = 64;
|
2014-11-18 18:37:05 +01:00
|
|
|
}
|
|
|
|
|
2016-04-29 23:06:26 +02:00
|
|
|
return Abi(arch, Abi::LinuxOS, Abi::AndroidLinuxFlavor, Abi::ElfFormat, wordWidth);
|
2013-01-25 16:49:22 +01:00
|
|
|
}
|
|
|
|
|
2014-11-18 18:37:05 +01:00
|
|
|
QLatin1String AndroidConfig::toolchainPrefix(const Abi &abi)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2014-11-18 18:37:05 +01:00
|
|
|
switch (abi.architecture()) {
|
2012-08-09 01:56:51 +02:00
|
|
|
case Abi::ArmArchitecture:
|
2014-11-18 18:37:05 +01:00
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return AArch64ToolchainPrefix;
|
2012-04-18 20:30:57 +03:00
|
|
|
return ArmToolchainPrefix;
|
2012-08-09 01:56:51 +02:00
|
|
|
case Abi::X86Architecture:
|
2014-11-18 18:37:05 +01:00
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return X86_64ToolchainPrefix;
|
2012-04-18 20:30:57 +03:00
|
|
|
return X86ToolchainPrefix;
|
2013-02-16 18:05:11 +02:00
|
|
|
case Abi::MipsArchitecture:
|
2017-05-24 14:14:39 -07:00
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return Mips64ToolchainPrefix;
|
2013-02-16 18:05:11 +02:00
|
|
|
return MipsToolchainPrefix;
|
2012-04-18 20:30:57 +03:00
|
|
|
default:
|
|
|
|
return Unknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-18 18:37:05 +01:00
|
|
|
QLatin1String AndroidConfig::toolsPrefix(const Abi &abi)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2014-11-18 18:37:05 +01:00
|
|
|
switch (abi.architecture()) {
|
2012-08-09 01:56:51 +02:00
|
|
|
case Abi::ArmArchitecture:
|
2014-11-18 18:37:05 +01:00
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return AArch64ToolsPrefix;
|
2012-04-18 20:30:57 +03:00
|
|
|
return ArmToolsPrefix;
|
2012-08-09 01:56:51 +02:00
|
|
|
case Abi::X86Architecture:
|
2014-11-18 18:37:05 +01:00
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return X86_64ToolsPrefix;
|
2012-04-18 20:30:57 +03:00
|
|
|
return X86ToolsPrefix;
|
2013-02-16 18:05:11 +02:00
|
|
|
case Abi::MipsArchitecture:
|
2017-05-24 14:14:39 -07:00
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return Mips64ToolsPrefix;
|
2013-02-16 18:05:11 +02:00
|
|
|
return MipsToolsPrefix;
|
2012-04-18 20:30:57 +03:00
|
|
|
default:
|
|
|
|
return Unknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-18 18:37:05 +01:00
|
|
|
QLatin1String AndroidConfig::displayName(const Abi &abi)
|
|
|
|
{
|
|
|
|
switch (abi.architecture()) {
|
|
|
|
case Abi::ArmArchitecture:
|
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return AArch64ToolsDisplayName;
|
|
|
|
return ArmToolsDisplayName;
|
|
|
|
case Abi::X86Architecture:
|
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return X86_64ToolsDisplayName;
|
|
|
|
return X86ToolsDisplayName;
|
|
|
|
case Abi::MipsArchitecture:
|
2017-05-24 14:14:39 -07:00
|
|
|
if (abi.wordWidth() == 64)
|
|
|
|
return Mips64ToolsDisplayName;
|
2014-11-18 18:37:05 +01:00
|
|
|
return MipsToolsDisplayName;
|
|
|
|
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());
|
2017-09-27 15:26:59 +02:00
|
|
|
m_sdkManagerToolArgs = settings.value(SDKManagerToolArgsKey).toStringList();
|
2013-12-16 20:19:07 +01:00
|
|
|
m_ndkLocation = FileName::fromString(settings.value(NDKLocationKey).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();
|
2018-02-09 17:20:22 +01:00
|
|
|
m_deviceQmlsceneCommand = settings.value(DeviceQmlsceneCommandKey, defaultQmlScene).toString();
|
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
|
2014-12-16 15:50:02 +01:00
|
|
|
m_sdkLocation = FileName::fromString(reader.restoreValue(SDKLocationKey, m_sdkLocation.toString()).toString());
|
2017-09-27 15:26:59 +02:00
|
|
|
m_sdkManagerToolArgs = reader.restoreValue(SDKManagerToolArgsKey, m_sdkManagerToolArgs).toStringList();
|
2014-12-16 15:50:02 +01:00
|
|
|
m_ndkLocation = FileName::fromString(reader.restoreValue(NDKLocationKey, m_ndkLocation.toString()).toString());
|
|
|
|
m_openJDKLocation = FileName::fromString(reader.restoreValue(OpenJDKLocationKey, m_openJDKLocation.toString()).toString());
|
|
|
|
m_keystoreLocation = FileName::fromString(reader.restoreValue(KeystoreLocationKey, m_keystoreLocation.toString()).toString());
|
|
|
|
m_toolchainHost = reader.restoreValue(ToolchainHostKey, m_toolchainHost).toString();
|
|
|
|
m_automaticKitCreation = reader.restoreValue(AutomaticKitCreationKey, m_automaticKitCreation).toBool();
|
2018-02-09 17:20:22 +01:00
|
|
|
m_deviceQmlsceneCommand = reader.restoreValue(DeviceQmlsceneCommandKey, m_deviceQmlsceneCommand).toString();
|
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_NdkInformationUpToDate = false;
|
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());
|
2017-09-27 15:26:59 +02:00
|
|
|
settings.setValue(SDKManagerToolArgsKey, m_sdkManagerToolArgs);
|
2013-12-16 20:19:07 +01:00
|
|
|
settings.setValue(NDKLocationKey, m_ndkLocation.toString());
|
|
|
|
settings.setValue(OpenJDKLocationKey, m_openJDKLocation.toString());
|
|
|
|
settings.setValue(KeystoreLocationKey, m_keystoreLocation.toString());
|
|
|
|
settings.setValue(PartitionSizeKey, m_partitionSize);
|
|
|
|
settings.setValue(AutomaticKitCreationKey, m_automaticKitCreation);
|
2018-02-09 17:20:22 +01:00
|
|
|
settings.setValue(DeviceQmlsceneCommandKey, m_deviceQmlsceneCommand);
|
2013-12-16 20:19:07 +01:00
|
|
|
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();
|
2017-02-07 16:59:21 +01:00
|
|
|
QDirIterator it(path.appendPath("platforms").toString(), QStringList("android-*"), QDir::Dirs);
|
2012-04-18 20:30:57 +03:00
|
|
|
while (it.hasNext()) {
|
|
|
|
const QString &fileName = it.next();
|
2016-02-03 13:49:53 +01:00
|
|
|
m_availableNdkPlatforms.push_back(fileName.midRef(fileName.lastIndexOf(QLatin1Char('-')) + 1).toInt());
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
2014-06-16 18:25:52 +04:00
|
|
|
Utils::sort(m_availableNdkPlatforms, std::greater<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
|
|
|
}
|
|
|
|
|
2017-08-18 08:22:34 +02:00
|
|
|
QStringList AndroidConfig::apiLevelNamesFor(const SdkPlatformList &platforms)
|
2014-03-24 16:31:28 +01:00
|
|
|
{
|
2014-07-16 12:35:29 +02:00
|
|
|
return Utils::transform(platforms, AndroidConfig::apiLevelNameFor);
|
2014-03-24 16:31:28 +01:00
|
|
|
}
|
|
|
|
|
2017-08-18 08:22:34 +02:00
|
|
|
QString AndroidConfig::apiLevelNameFor(const SdkPlatform *platform)
|
2013-10-17 13:23:08 +02:00
|
|
|
{
|
2017-08-18 08:22:34 +02:00
|
|
|
return platform && platform->apiLevel() > 0 ?
|
|
|
|
QString("android-%1").arg(platform->apiLevel()) : "";
|
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
|
|
|
{
|
2015-02-03 23:50:37 +02:00
|
|
|
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
|
|
|
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));
|
2014-10-24 13:15:54 +02:00
|
|
|
if (path.exists())
|
2012-08-23 15:53:58 +02:00
|
|
|
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::emulatorToolPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName path = m_sdkLocation;
|
2017-04-03 11:11:17 +02:00
|
|
|
QString relativePath = "emulator/emulator";
|
|
|
|
if (sdkToolsVersion() < QVersionNumber(25, 3, 0))
|
|
|
|
relativePath = "tools/emulator";
|
|
|
|
return path.appendPath(relativePath + QTC_HOST_EXE_SUFFIX);
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2014-11-18 18:37:05 +01:00
|
|
|
FileName AndroidConfig::toolPath(const Abi &abi, 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")
|
2014-11-18 18:37:05 +01:00
|
|
|
.arg(toolchainPrefix(abi))
|
2013-01-25 16:49:22 +01:00
|
|
|
.arg(ndkToolChainVersion)
|
2013-12-16 20:19:07 +01:00
|
|
|
.arg(toolchainHost())
|
2014-11-18 18:37:05 +01:00
|
|
|
.arg(toolsPrefix(abi)));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2017-03-30 14:47:34 +02:00
|
|
|
FileName AndroidConfig::sdkManagerToolPath() const
|
|
|
|
{
|
|
|
|
FileName sdkPath = m_sdkLocation;
|
|
|
|
QString toolPath = "tools/bin/sdkmanager";
|
|
|
|
if (HostOsInfo::isWindowsHost())
|
|
|
|
toolPath += ANDROID_BAT_SUFFIX;
|
|
|
|
sdkPath = sdkPath.appendPath(toolPath);
|
|
|
|
return sdkPath;
|
|
|
|
}
|
|
|
|
|
2017-04-03 11:11:17 +02:00
|
|
|
FileName AndroidConfig::avdManagerToolPath() const
|
|
|
|
{
|
|
|
|
FileName avdManagerPath = m_sdkLocation;
|
|
|
|
QString toolPath = "tools/bin/avdmanager";
|
|
|
|
if (HostOsInfo::isWindowsHost())
|
|
|
|
toolPath += ANDROID_BAT_SUFFIX;
|
|
|
|
avdManagerPath = avdManagerPath.appendPath(toolPath);
|
|
|
|
return avdManagerPath;
|
|
|
|
}
|
|
|
|
|
2016-12-16 00:43:14 +01:00
|
|
|
FileName AndroidConfig::gccPath(const Abi &abi, Core::Id lang,
|
2016-10-24 15:53:37 +02:00
|
|
|
const QString &ndkToolChainVersion) const
|
2013-04-04 01:29:47 -07:00
|
|
|
{
|
2016-10-24 15:53:37 +02:00
|
|
|
const QString tool
|
2016-12-16 00:43:14 +01:00
|
|
|
= HostOsInfo::withExecutableSuffix(QString::fromLatin1(lang == Core::Id(ProjectExplorer::Constants::C_LANGUAGE_ID) ? "-gcc" : "-g++"));
|
2016-10-24 15:53:37 +02:00
|
|
|
return toolPath(abi, ndkToolChainVersion).appendString(tool);
|
2013-04-04 01:29:47 -07:00
|
|
|
}
|
|
|
|
|
2014-11-18 18:37:05 +01:00
|
|
|
FileName AndroidConfig::gdbPath(const Abi &abi, const QString &ndkToolChainVersion) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2016-03-14 15:43:03 +02:00
|
|
|
const auto gdbPath = QString::fromLatin1("%1/prebuilt/%2/bin/gdb" QTC_HOST_EXE_SUFFIX).arg(m_ndkLocation.toString()).arg(toolchainHost());
|
|
|
|
if (QFile::exists(gdbPath))
|
|
|
|
return FileName::fromString(gdbPath);
|
|
|
|
|
2014-11-18 18:37:05 +01:00
|
|
|
return toolPath(abi, ndkToolChainVersion).appendString(QLatin1String("-gdb" QTC_HOST_EXE_SUFFIX));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2017-11-06 15:59:11 +01:00
|
|
|
FileName AndroidConfig::makePath() const
|
|
|
|
{
|
|
|
|
const QString makePath = QString::fromLatin1("%1/prebuilt/%2/bin/make" QTC_HOST_EXE_SUFFIX)
|
|
|
|
.arg(m_ndkLocation.toString()).arg(toolchainHost());
|
|
|
|
return FileName::fromString(makePath);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(QString *error) const
|
2015-04-10 18:08:51 +02:00
|
|
|
{
|
|
|
|
return connectedDevices(adbToolPath().toString(), error);
|
|
|
|
}
|
|
|
|
|
|
|
|
QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(const QString &adbToolPath, QString *error)
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2012-07-03 16:57:44 +03:00
|
|
|
QVector<AndroidDeviceInfo> devices;
|
2016-04-29 16:52:58 +02:00
|
|
|
SynchronousProcess adbProc;
|
|
|
|
adbProc.setTimeoutS(30);
|
2017-02-07 16:59:21 +01:00
|
|
|
SynchronousProcessResponse response = adbProc.runBlocking(adbToolPath, QStringList("devices"));
|
2016-04-29 16:52:58 +02:00
|
|
|
if (response.result != SynchronousProcessResponse::Finished) {
|
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")
|
2015-04-10 18:08:51 +02:00
|
|
|
.arg(adbToolPath + QLatin1String(" devices"));
|
2012-04-18 20:30:57 +03:00
|
|
|
return devices;
|
|
|
|
}
|
2016-06-10 11:34:18 +03:00
|
|
|
QStringList adbDevs = response.allOutput().split('\n', QString::SkipEmptyParts);
|
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
|
2016-04-29 16:52:58 +02:00
|
|
|
foreach (const QString &device, adbDevs) {
|
|
|
|
const QString serialNo = device.left(device.indexOf('\t')).trimmed();
|
|
|
|
const QString deviceType = device.mid(device.indexOf('\t')).trimmed();
|
2015-04-10 18:08:51 +02:00
|
|
|
if (isBootToQt(adbToolPath, serialNo))
|
2013-11-15 16:29:53 +01:00
|
|
|
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;
|
2015-04-10 18:08:51 +02:00
|
|
|
dev.sdk = getSDKVersion(adbToolPath, dev.serialNumber);
|
|
|
|
dev.cpuAbi = getAbis(adbToolPath, 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;
|
2015-04-23 16:25:44 +02:00
|
|
|
|
2016-05-05 17:34:22 +03:00
|
|
|
if (dev.type == AndroidDeviceInfo::Emulator) {
|
2015-04-23 16:25:44 +02:00
|
|
|
dev.avdname = getAvdName(dev.serialNumber);
|
2016-05-05 17:34:22 +03:00
|
|
|
if (dev.avdname.isEmpty())
|
|
|
|
dev.avdname = serialNo;
|
|
|
|
}
|
2015-04-23 16:25:44 +02:00
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
devices.push_back(dev);
|
|
|
|
}
|
2013-08-28 12:50:32 +02:00
|
|
|
|
2017-03-30 14:43:13 +02:00
|
|
|
Utils::sort(devices);
|
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")
|
2015-04-10 18:08:51 +02:00
|
|
|
.arg(adbToolPath + QLatin1String(" devices"));
|
2012-04-18 20:30:57 +03:00
|
|
|
return devices;
|
|
|
|
}
|
|
|
|
|
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::isBootToQt(const QString &device) const
|
2015-04-10 18:08:51 +02:00
|
|
|
{
|
|
|
|
return isBootToQt(adbToolPath().toString(), device);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AndroidConfig::isBootToQt(const QString &adbToolPath, const QString &device)
|
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");
|
|
|
|
|
2016-04-29 16:52:58 +02:00
|
|
|
SynchronousProcess adbProc;
|
|
|
|
adbProc.setTimeoutS(10);
|
2016-06-10 13:33:40 +03:00
|
|
|
SynchronousProcessResponse response = adbProc.runBlocking(adbToolPath, arguments);
|
2016-04-29 16:52:58 +02:00
|
|
|
return response.result == SynchronousProcessResponse::Finished
|
|
|
|
&& response.allOutput().contains(QLatin1String("Boot2Qt"));
|
2013-11-15 16:29:53 +01:00
|
|
|
}
|
|
|
|
|
2015-04-10 18:08:51 +02:00
|
|
|
|
|
|
|
QString AndroidConfig::getDeviceProperty(const QString &adbToolPath, const QString &device, const QString &property)
|
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);
|
2016-04-29 16:52:58 +02:00
|
|
|
arguments << QLatin1String("shell") << QLatin1String("getprop") << property;
|
2012-04-18 20:30:57 +03:00
|
|
|
|
2016-04-29 16:52:58 +02:00
|
|
|
SynchronousProcess adbProc;
|
|
|
|
adbProc.setTimeoutS(10);
|
2016-05-26 12:12:01 +02:00
|
|
|
SynchronousProcessResponse response = adbProc.runBlocking(adbToolPath, arguments);
|
2016-04-29 16:52:58 +02:00
|
|
|
if (response.result != SynchronousProcessResponse::Finished)
|
2015-04-10 16:46:30 +02:00
|
|
|
return QString();
|
|
|
|
|
2016-04-29 16:52:58 +02:00
|
|
|
return response.allOutput();
|
2015-04-10 16:46:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int AndroidConfig::getSDKVersion(const QString &device) const
|
|
|
|
{
|
2015-04-10 18:08:51 +02:00
|
|
|
return getSDKVersion(adbToolPath().toString(), device);
|
|
|
|
}
|
|
|
|
|
|
|
|
int AndroidConfig::getSDKVersion(const QString &adbToolPath, const QString &device)
|
|
|
|
{
|
|
|
|
QString tmp = getDeviceProperty(adbToolPath, device, QLatin1String("ro.build.version.sdk"));
|
2015-04-10 16:46:30 +02:00
|
|
|
if (tmp.isEmpty())
|
2012-04-18 20:30:57 +03:00
|
|
|
return -1;
|
2015-04-10 16:46:30 +02:00
|
|
|
return tmp.trimmed().toInt();
|
|
|
|
}
|
|
|
|
|
2015-04-23 16:25:44 +02:00
|
|
|
QString AndroidConfig::getAvdName(const QString &serialnumber)
|
|
|
|
{
|
|
|
|
int index = serialnumber.indexOf(QLatin1String("-"));
|
|
|
|
if (index == -1)
|
|
|
|
return QString();
|
|
|
|
bool ok;
|
2016-02-03 13:49:53 +01:00
|
|
|
int port = serialnumber.midRef(index + 1).toInt(&ok);
|
2015-04-23 16:25:44 +02:00
|
|
|
if (!ok)
|
|
|
|
return QString();
|
|
|
|
|
2016-04-29 08:54:00 +02:00
|
|
|
const QByteArray avdName = "avd name\n";
|
2015-04-23 16:25:44 +02:00
|
|
|
|
|
|
|
QTcpSocket tcpSocket;
|
|
|
|
tcpSocket.connectToHost(QHostAddress(QHostAddress::LocalHost), port);
|
2016-05-05 17:34:22 +03:00
|
|
|
if (!tcpSocket.waitForConnected(100)) // Don't wait more than 100ms for a local connection
|
|
|
|
return QString{};
|
|
|
|
|
2015-04-23 16:25:44 +02:00
|
|
|
tcpSocket.write(avdName + "exit\n");
|
2016-05-05 17:34:22 +03:00
|
|
|
tcpSocket.waitForDisconnected(500);
|
2015-04-23 16:25:44 +02:00
|
|
|
|
2016-04-29 08:54:00 +02:00
|
|
|
QByteArray name;
|
|
|
|
const QByteArrayList response = tcpSocket.readAll().split('\n');
|
|
|
|
// The input "avd name" might not be echoed as-is, but contain ASCII
|
|
|
|
// control sequences.
|
|
|
|
for (int i = response.size() - 1; i > 1; --i) {
|
2016-08-25 15:46:50 +03:00
|
|
|
if (response.at(i).startsWith("OK")) {
|
2016-04-29 08:54:00 +02:00
|
|
|
name = response.at(i - 1);
|
2016-08-25 15:46:50 +03:00
|
|
|
break;
|
|
|
|
}
|
2016-04-29 08:54:00 +02:00
|
|
|
}
|
|
|
|
return QString::fromLatin1(name).trimmed();
|
2015-04-23 16:25:44 +02:00
|
|
|
}
|
|
|
|
|
2015-04-10 16:46:30 +02:00
|
|
|
AndroidConfig::OpenGl AndroidConfig::getOpenGLEnabled(const QString &emulator) const
|
|
|
|
{
|
|
|
|
QDir dir = QDir::home();
|
|
|
|
if (!dir.cd(QLatin1String(".android")))
|
|
|
|
return OpenGl::Unknown;
|
|
|
|
if (!dir.cd(QLatin1String("avd")))
|
|
|
|
return OpenGl::Unknown;
|
|
|
|
if (!dir.cd(emulator + QLatin1String(".avd")))
|
|
|
|
return OpenGl::Unknown;
|
|
|
|
QFile file(dir.filePath(QLatin1String("config.ini")));
|
|
|
|
if (!file.exists())
|
|
|
|
return OpenGl::Unknown;
|
|
|
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
|
|
|
return OpenGl::Unknown;
|
|
|
|
while (!file.atEnd()) {
|
|
|
|
QByteArray line = file.readLine();
|
|
|
|
if (line.contains("hw.gpu.enabled") && line.contains("yes"))
|
|
|
|
return OpenGl::Enabled;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
2015-04-10 16:46:30 +02:00
|
|
|
return OpenGl::Disabled;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2015-04-10 18:08:51 +02:00
|
|
|
QString model = getDeviceProperty(adbToolPath().toString(), device, QLatin1String("ro.product.model")).trimmed();
|
2013-07-03 17:58:48 +02:00
|
|
|
if (model.isEmpty())
|
|
|
|
return device;
|
2015-04-10 16:46:30 +02:00
|
|
|
|
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
|
|
|
QStringList AndroidConfig::getAbis(const QString &device) const
|
2015-04-10 18:08:51 +02:00
|
|
|
{
|
|
|
|
return getAbis(adbToolPath().toString(), device);
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList AndroidConfig::getAbis(const QString &adbToolPath, const QString &device)
|
2013-05-03 15:10:21 +02:00
|
|
|
{
|
|
|
|
QStringList result;
|
2014-11-18 12:55:21 +01:00
|
|
|
// First try via ro.product.cpu.abilist
|
|
|
|
QStringList arguments = AndroidDeviceInfo::adbSelector(device);
|
2016-04-29 16:52:58 +02:00
|
|
|
arguments << QLatin1String("shell") << QLatin1String("getprop") << QLatin1String("ro.product.cpu.abilist");
|
|
|
|
SynchronousProcess adbProc;
|
|
|
|
adbProc.setTimeoutS(10);
|
2016-06-10 13:33:40 +03:00
|
|
|
SynchronousProcessResponse response = adbProc.runBlocking(adbToolPath, arguments);
|
2016-04-29 16:52:58 +02:00
|
|
|
if (response.result != SynchronousProcessResponse::Finished)
|
2014-11-18 12:55:21 +01:00
|
|
|
return result;
|
2016-04-29 16:52:58 +02:00
|
|
|
|
|
|
|
QString output = response.allOutput().trimmed();
|
2014-11-18 12:55:21 +01:00
|
|
|
if (!output.isEmpty()) {
|
|
|
|
QStringList result = output.split(QLatin1Char(','));
|
|
|
|
if (!result.isEmpty())
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fall back to ro.product.cpu.abi, ro.product.cpu.abi2 ...
|
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);
|
|
|
|
|
2016-04-29 16:52:58 +02:00
|
|
|
SynchronousProcess abiProc;
|
|
|
|
abiProc.setTimeoutS(10);
|
2016-06-10 13:33:40 +03:00
|
|
|
SynchronousProcessResponse abiResponse = abiProc.runBlocking(adbToolPath, arguments);
|
2016-04-29 16:52:58 +02:00
|
|
|
if (abiResponse.result != SynchronousProcessResponse::Finished)
|
2013-05-03 15:10:21 +02:00
|
|
|
return result;
|
2016-04-29 16:52:58 +02:00
|
|
|
|
|
|
|
QString abi = abiResponse.allOutput().trimmed();
|
2013-05-03 15:10:21 +02:00
|
|
|
if (abi.isEmpty())
|
|
|
|
break;
|
|
|
|
result << abi;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-07-14 19:35:48 +02:00
|
|
|
bool AndroidConfig::useNativeUiTools() const
|
|
|
|
{
|
|
|
|
const QVersionNumber version = sdkToolsVersion();
|
|
|
|
return !version.isNull() && version <= QVersionNumber(25, 3 ,0);
|
|
|
|
}
|
|
|
|
|
2014-06-25 15:41:32 +02:00
|
|
|
QString AndroidConfig::bestNdkPlatformMatch(int target) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2014-04-16 17:27:04 +02:00
|
|
|
target = std::max(9, target);
|
2014-06-25 15:41:32 +02:00
|
|
|
updateNdkInformation();
|
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);
|
|
|
|
}
|
2014-05-07 15:03:43 +03:00
|
|
|
return QLatin1String("android-9");
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-03-30 14:47:34 +02:00
|
|
|
QVersionNumber AndroidConfig::sdkToolsVersion() const
|
|
|
|
{
|
|
|
|
QVersionNumber version;
|
|
|
|
if (m_sdkLocation.exists()) {
|
|
|
|
Utils::FileName sdkToolsPropertiesPath(m_sdkLocation);
|
|
|
|
sdkToolsPropertiesPath.appendPath("tools/source.properties");
|
|
|
|
QSettings settings(sdkToolsPropertiesPath.toString(), QSettings::IniFormat);
|
|
|
|
auto versionStr = settings.value(sdkToolsVersionKey).toString();
|
|
|
|
version = QVersionNumber::fromString(versionStr);
|
|
|
|
}
|
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
2017-09-04 14:54:50 +02:00
|
|
|
QVersionNumber AndroidConfig::buildToolsVersion() const
|
|
|
|
{
|
|
|
|
QVersionNumber maxVersion;
|
|
|
|
Utils::FileName buildtoolsDir = m_sdkLocation;
|
|
|
|
buildtoolsDir.appendPath("build-tools");
|
|
|
|
QDir buildToolsDir(buildtoolsDir.toString());
|
|
|
|
for (const QFileInfo &file: buildToolsDir.entryList(QDir::Dirs|QDir::NoDotAndDotDot))
|
|
|
|
maxVersion = qMax(maxVersion, QVersionNumber::fromString(file.fileName()));
|
|
|
|
return maxVersion;
|
|
|
|
}
|
|
|
|
|
2017-09-27 15:26:59 +02:00
|
|
|
|
|
|
|
QStringList AndroidConfig::sdkManagerToolArgs() const
|
|
|
|
{
|
|
|
|
return m_sdkManagerToolArgs;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setSdkManagerToolArgs(const QStringList &args)
|
|
|
|
{
|
|
|
|
m_sdkManagerToolArgs = args;
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
FileName AndroidConfig::ndkLocation() const
|
|
|
|
{
|
|
|
|
return m_ndkLocation;
|
|
|
|
}
|
|
|
|
|
2017-05-05 12:26:23 +02:00
|
|
|
QVersionNumber AndroidConfig::ndkVersion() const
|
|
|
|
{
|
|
|
|
QVersionNumber version;
|
|
|
|
if (!m_ndkLocation.exists()) {
|
|
|
|
qCDebug(avdConfigLog) << "Can not find ndk version. Check NDK path."
|
|
|
|
<< m_ndkLocation.toString();
|
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
|
|
|
Utils::FileName ndkPropertiesPath(m_ndkLocation);
|
|
|
|
ndkPropertiesPath.appendPath("source.properties");
|
|
|
|
if (ndkPropertiesPath.exists()) {
|
|
|
|
// source.properties files exists in NDK version > 11
|
|
|
|
QSettings settings(ndkPropertiesPath.toString(), QSettings::IniFormat);
|
|
|
|
auto versionStr = settings.value(ndkRevisionKey).toString();
|
|
|
|
version = QVersionNumber::fromString(versionStr);
|
|
|
|
} else {
|
|
|
|
// No source.properties. There should be a file named RELEASE.TXT
|
|
|
|
Utils::FileName ndkReleaseTxtPath(m_ndkLocation);
|
|
|
|
ndkReleaseTxtPath.appendPath("RELEASE.TXT");
|
|
|
|
Utils::FileReader reader;
|
|
|
|
QString errorString;
|
|
|
|
if (reader.fetch(ndkReleaseTxtPath.toString(), &errorString)) {
|
|
|
|
// RELEASE.TXT contains the ndk version in either of the following formats:
|
|
|
|
// r6a
|
|
|
|
// r10e (64 bit)
|
|
|
|
QString content = QString::fromUtf8(reader.data());
|
|
|
|
QRegularExpression re("(r)(?<major>[0-9]{1,2})(?<minor>[a-z]{1,1})");
|
|
|
|
QRegularExpressionMatch match = re.match(content);
|
|
|
|
if (match.hasMatch()) {
|
|
|
|
QString major = match.captured("major");
|
|
|
|
QString minor = match.captured("minor");
|
|
|
|
// Minor version: a = 0, b = 1, c = 2 and so on.
|
|
|
|
// Int equivalent = minorVersionChar - 'a'. i.e. minorVersionChar - 97.
|
|
|
|
version = QVersionNumber::fromString(QString("%1.%2.0").arg(major)
|
|
|
|
.arg((int)minor[0].toLatin1() - 97));
|
|
|
|
} else {
|
|
|
|
qCDebug(avdConfigLog) << "Can not find ndk version. Can not parse RELEASE.TXT."
|
|
|
|
<< content;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
qCDebug(avdConfigLog) << "Can not find ndk version." << errorString;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return version;
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
void AndroidConfig::setNdkLocation(const FileName &ndkLocation)
|
|
|
|
{
|
|
|
|
m_ndkLocation = ndkLocation;
|
|
|
|
m_NdkInformationUpToDate = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileName AndroidConfig::openJDKLocation() const
|
|
|
|
{
|
|
|
|
return m_openJDKLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setOpenJDKLocation(const FileName &openJDKLocation)
|
|
|
|
{
|
|
|
|
m_openJDKLocation = openJDKLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-02-09 17:20:22 +01:00
|
|
|
QString AndroidConfig::deviceQmlsceneCommand() const
|
|
|
|
{
|
|
|
|
return m_deviceQmlsceneCommand;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfig::setDeviceQmlsceneCommand(const QString &qmlsceneCommand)
|
|
|
|
{
|
|
|
|
m_deviceQmlsceneCommand = qmlsceneCommand;
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
///////////////////////////////////
|
|
|
|
// AndroidConfigurations
|
|
|
|
///////////////////////////////////
|
|
|
|
void AndroidConfigurations::setConfig(const AndroidConfig &devConfigs)
|
|
|
|
{
|
|
|
|
m_instance->m_config = devConfigs;
|
|
|
|
|
|
|
|
m_instance->save();
|
|
|
|
m_instance->updateAndroidDevice();
|
2015-04-22 17:42:23 +02:00
|
|
|
m_instance->registerNewToolChains();
|
2014-03-11 13:05:36 +01:00
|
|
|
m_instance->updateAutomaticKitList();
|
2015-04-22 17:42:23 +02:00
|
|
|
m_instance->removeOldToolChains();
|
2013-12-16 20:19:07 +01:00
|
|
|
emit m_instance->updated();
|
|
|
|
}
|
|
|
|
|
2015-02-03 23:50:37 +02:00
|
|
|
AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(Project *project,
|
2017-09-04 15:21:16 -07:00
|
|
|
int apiLevel, const QString &abi)
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
|
|
|
QString serialNumber = defaultDevice(project, abi);
|
2017-09-04 15:21:16 -07:00
|
|
|
AndroidDeviceDialog dialog(apiLevel, abi, serialNumber, Core::ICore::mainWindow());
|
2015-12-04 10:03:45 +02:00
|
|
|
AndroidDeviceInfo info = dialog.device();
|
|
|
|
if (dialog.saveDeviceSelection() && info.isValid()) {
|
|
|
|
const QString serialNumber = info.type == AndroidDeviceInfo::Hardware ?
|
|
|
|
info.serialNumber : info.avdname;
|
|
|
|
if (!serialNumber.isEmpty())
|
|
|
|
AndroidConfigurations::setDefaultDevice(project, abi, serialNumber);
|
2013-12-16 20:19:07 +01:00
|
|
|
}
|
2015-12-04 10:03:45 +02:00
|
|
|
return info;
|
2013-12-16 20:19:07 +01:00
|
|
|
}
|
|
|
|
|
2015-02-03 23:50:37 +02:00
|
|
|
void AndroidConfigurations::clearDefaultDevices(Project *project)
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
|
|
|
if (m_instance->m_defaultDeviceForAbi.contains(project))
|
|
|
|
m_instance->m_defaultDeviceForAbi.remove(project);
|
|
|
|
}
|
|
|
|
|
2015-02-03 23:50:37 +02:00
|
|
|
void AndroidConfigurations::setDefaultDevice(Project *project, const QString &abi, const QString &serialNumber)
|
2013-12-16 20:19:07 +01:00
|
|
|
{
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2016-10-24 15:53:37 +02:00
|
|
|
static bool matchToolChain(const ToolChain *atc, const ToolChain *btc)
|
2013-02-14 15:51:59 +01:00
|
|
|
{
|
2015-04-22 17:42:23 +02:00
|
|
|
if (atc == btc)
|
|
|
|
return true;
|
2016-10-24 15:53:37 +02:00
|
|
|
|
|
|
|
if (!atc || !btc)
|
2015-04-22 17:42:23 +02:00
|
|
|
return false;
|
2016-10-24 15:53:37 +02:00
|
|
|
|
|
|
|
if (atc->typeId() != Constants::ANDROID_TOOLCHAIN_ID || btc->typeId() != Constants::ANDROID_TOOLCHAIN_ID)
|
2015-04-22 17:42:23 +02:00
|
|
|
return false;
|
2016-10-24 15:53:37 +02:00
|
|
|
|
|
|
|
auto aatc = static_cast<const AndroidToolChain *>(atc);
|
|
|
|
auto abtc = static_cast<const AndroidToolChain *>(btc);
|
|
|
|
return aatc->ndkToolChainVersion() == abtc->ndkToolChainVersion()
|
|
|
|
&& aatc->targetAbi() == abtc->targetAbi();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool matchKits(const Kit *a, const Kit *b)
|
|
|
|
{
|
|
|
|
if (QtSupport::QtKitInformation::qtVersion(a) != QtSupport::QtKitInformation::qtVersion(b))
|
|
|
|
return false;
|
|
|
|
|
2016-12-16 00:43:14 +01:00
|
|
|
return matchToolChain(ToolChainKitInformation::toolChain(a, ProjectExplorer::Constants::CXX_LANGUAGE_ID),
|
|
|
|
ToolChainKitInformation::toolChain(b, ProjectExplorer::Constants::CXX_LANGUAGE_ID))
|
|
|
|
&& matchToolChain(ToolChainKitInformation::toolChain(a, ProjectExplorer::Constants::C_LANGUAGE_ID),
|
|
|
|
ToolChainKitInformation::toolChain(b, ProjectExplorer::Constants::C_LANGUAGE_ID));
|
2013-02-14 15:51:59 +01:00
|
|
|
}
|
|
|
|
|
2015-04-22 17:42:23 +02:00
|
|
|
void AndroidConfigurations::registerNewToolChains()
|
2014-03-11 13:05:36 +01:00
|
|
|
{
|
2015-10-15 16:01:40 +02:00
|
|
|
const QList<ToolChain *> existingAndroidToolChains
|
2017-01-11 16:12:32 +01:00
|
|
|
= ToolChainManager::toolChains(Utils::equal(&ToolChain::typeId,
|
|
|
|
Core::Id(Constants::ANDROID_TOOLCHAIN_ID)));
|
2015-10-15 16:01:40 +02:00
|
|
|
const QList<ToolChain *> newToolchains
|
|
|
|
= AndroidToolChainFactory::autodetectToolChainsForNdk(AndroidConfigurations::currentConfig().ndkLocation(),
|
|
|
|
existingAndroidToolChains);
|
|
|
|
foreach (ToolChain *tc, newToolchains)
|
2017-01-11 16:14:31 +01:00
|
|
|
ToolChainManager::registerToolChain(tc);
|
2015-04-22 17:42:23 +02:00
|
|
|
}
|
2014-03-11 13:05:36 +01:00
|
|
|
|
2015-04-22 17:42:23 +02:00
|
|
|
void AndroidConfigurations::removeOldToolChains()
|
|
|
|
{
|
2017-01-11 16:12:32 +01:00
|
|
|
foreach (ToolChain *tc, ToolChainManager::toolChains(Utils::equal(&ToolChain::typeId, Core::Id(Constants::ANDROID_TOOLCHAIN_ID)))) {
|
|
|
|
if (!tc->isValid())
|
|
|
|
ToolChainManager::deregisterToolChain(tc);
|
2014-03-11 13:05:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-14 15:51:59 +01:00
|
|
|
void AndroidConfigurations::updateAutomaticKitList()
|
|
|
|
{
|
2017-05-19 09:57:51 +02:00
|
|
|
const QList<Kit *> existingKits = Utils::filtered(KitManager::kits(), [](Kit *k) {
|
|
|
|
Core::Id deviceTypeId = DeviceTypeKitInformation::deviceTypeId(k);
|
|
|
|
if (k->isAutoDetected() && !k->isSdkProvided()
|
|
|
|
&& deviceTypeId == Core::Id(Constants::ANDROID_DEVICE_TYPE)) {
|
|
|
|
if (!QtSupport::QtKitInformation::qtVersion(k))
|
|
|
|
KitManager::deregisterKit(k); // Remove autoDetected kits without Qt.
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2016-10-26 14:40:21 +02:00
|
|
|
});
|
2013-02-14 15:51:59 +01:00
|
|
|
|
2016-10-26 14:40:21 +02:00
|
|
|
// Update code for 3.0 beta, which shipped with a bug for the debugger settings
|
|
|
|
for (Kit *k : existingKits) {
|
2016-12-16 00:43:14 +01:00
|
|
|
ToolChain *tc = ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
2016-07-29 15:55:15 +02:00
|
|
|
if (tc && Debugger::DebuggerKitInformation::runnable(k).executable != tc->suggestedDebugger().toString()) {
|
2013-10-23 13:24:36 +02:00
|
|
|
Debugger::DebuggerItem debugger;
|
|
|
|
debugger.setCommand(tc->suggestedDebugger());
|
|
|
|
debugger.setEngineType(Debugger::GdbEngineType);
|
2015-03-03 16:49:59 +01:00
|
|
|
debugger.setUnexpandedDisplayName(tr("Android Debugger for %1").arg(tc->displayName()));
|
2013-10-23 13:24:36 +02:00
|
|
|
debugger.setAutoDetected(true);
|
|
|
|
debugger.setAbi(tc->targetAbi());
|
2016-04-29 19:05:08 +02:00
|
|
|
debugger.reinitializeFromFile();
|
2013-10-23 13:24:36 +02:00
|
|
|
QVariant id = Debugger::DebuggerItemManager::registerDebugger(debugger);
|
|
|
|
Debugger::DebuggerKitInformation::setDebugger(k, id);
|
|
|
|
}
|
2013-02-14 15:51:59 +01:00
|
|
|
}
|
|
|
|
|
2016-10-26 14:40:21 +02:00
|
|
|
QHash<Abi, QList<const QtSupport::BaseQtVersion *> > qtVersionsForArch;
|
|
|
|
const QList<QtSupport::BaseQtVersion *> qtVersions
|
2017-01-12 10:37:29 +01:00
|
|
|
= QtSupport::QtVersionManager::versions([](const QtSupport::BaseQtVersion *v) {
|
2016-10-26 14:40:21 +02:00
|
|
|
return v->type() == Constants::ANDROIDQT;
|
|
|
|
});
|
|
|
|
for (const QtSupport::BaseQtVersion *qtVersion : qtVersions) {
|
|
|
|
const QList<Abi> qtAbis = qtVersion->qtAbis();
|
2013-02-25 09:17:43 +02:00
|
|
|
if (qtAbis.empty())
|
|
|
|
continue;
|
2014-11-18 18:37:05 +01:00
|
|
|
qtVersionsForArch[qtAbis.first()].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
|
2016-10-26 14:40:21 +02:00
|
|
|
for (Kit *k : existingKits)
|
2013-10-30 17:02:28 +01:00
|
|
|
KitManager::deregisterKit(k);
|
|
|
|
return;
|
|
|
|
}
|
2013-02-14 15:51:59 +01:00
|
|
|
|
|
|
|
// register new kits
|
2017-01-11 16:12:32 +01:00
|
|
|
const QList<ToolChain *> tmp = ToolChainManager::toolChains([](const ToolChain *tc) {
|
2016-10-24 15:53:37 +02:00
|
|
|
return tc->isAutoDetected()
|
|
|
|
&& tc->isValid()
|
|
|
|
&& tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID
|
2017-01-11 16:12:32 +01:00
|
|
|
&& !static_cast<const AndroidToolChain *>(tc)->isSecondaryToolChain();
|
2016-10-24 15:53:37 +02:00
|
|
|
});
|
2018-05-29 10:59:27 +02:00
|
|
|
const auto toolchains = Utils::static_container_cast<AndroidToolChain *>(tmp);
|
2016-10-24 15:53:37 +02:00
|
|
|
for (AndroidToolChain *tc : toolchains) {
|
2016-12-16 00:43:14 +01:00
|
|
|
if (tc->isSecondaryToolChain() || tc->language() != Core::Id(ProjectExplorer::Constants::CXX_LANGUAGE_ID))
|
2013-10-10 18:04:27 +02:00
|
|
|
continue;
|
2016-10-24 15:53:37 +02:00
|
|
|
const QList<AndroidToolChain *> allLanguages = Utils::filtered(toolchains,
|
|
|
|
[tc](AndroidToolChain *otherTc) {
|
|
|
|
return tc->targetAbi() == otherTc->targetAbi();
|
|
|
|
});
|
2017-05-18 10:37:19 +02:00
|
|
|
|
|
|
|
auto initBasicKitData = [allLanguages, device](Kit *k, const QtSupport::BaseQtVersion *qt) {
|
|
|
|
k->setAutoDetected(true);
|
|
|
|
k->setAutoDetectionSource("AndroidConfiguration");
|
|
|
|
DeviceTypeKitInformation::setDeviceTypeId(k, Core::Id(Constants::ANDROID_DEVICE_TYPE));
|
2016-10-24 15:53:37 +02:00
|
|
|
for (AndroidToolChain *tc : allLanguages)
|
2017-05-18 10:37:19 +02:00
|
|
|
ToolChainKitInformation::setToolChain(k, tc);
|
|
|
|
QtSupport::QtKitInformation::setQtVersion(k, qt);
|
|
|
|
DeviceKitInformation::setDevice(k, device);
|
|
|
|
};
|
2013-10-10 18:02:56 +02:00
|
|
|
|
2017-05-18 10:37:19 +02:00
|
|
|
for (const QtSupport::BaseQtVersion *qt : qtVersionsForArch.value(tc->targetAbi())) {
|
|
|
|
Kit *newKit = new Kit;
|
|
|
|
initBasicKitData(newKit, qt);
|
|
|
|
Kit *existingKit = Utils::findOrDefault(existingKits, [newKit](const Kit *k) {
|
|
|
|
return matchKits(newKit, k);
|
|
|
|
});
|
2017-01-12 13:26:24 +01:00
|
|
|
if (existingKit) {
|
2017-05-18 10:37:19 +02:00
|
|
|
// Existing kit found.
|
|
|
|
// Update the existing kit with new data.
|
|
|
|
initBasicKitData(existingKit, qt);
|
2017-01-12 13:26:24 +01:00
|
|
|
KitManager::deleteKit(newKit);
|
|
|
|
newKit = existingKit;
|
|
|
|
}
|
|
|
|
|
2013-10-10 18:02:56 +02:00
|
|
|
Debugger::DebuggerItem debugger;
|
|
|
|
debugger.setCommand(tc->suggestedDebugger());
|
|
|
|
debugger.setEngineType(Debugger::GdbEngineType);
|
2015-03-03 16:49:59 +01:00
|
|
|
debugger.setUnexpandedDisplayName(tr("Android Debugger for %1").arg(tc->displayName()));
|
2013-10-10 18:02:56 +02:00
|
|
|
debugger.setAutoDetected(true);
|
|
|
|
debugger.setAbi(tc->targetAbi());
|
2016-04-29 19:05:08 +02:00
|
|
|
debugger.reinitializeFromFile();
|
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();
|
2017-02-15 10:00:52 +01:00
|
|
|
newKit->setUnexpandedDisplayName(tr("Android for %1 (GCC %2, %3)")
|
2016-10-26 14:40:21 +02:00
|
|
|
.arg(static_cast<const AndroidQtVersion *>(qt)->targetArch())
|
|
|
|
.arg(tc->ndkToolChainVersion())
|
2017-02-15 10:00:52 +01:00
|
|
|
.arg(qt->displayName()));
|
2017-01-12 13:26:24 +01:00
|
|
|
if (!existingKit)
|
|
|
|
KitManager::registerKit(newKit);
|
2013-08-28 13:34:24 +02:00
|
|
|
}
|
|
|
|
}
|
2013-02-14 15:51:59 +01:00
|
|
|
}
|
|
|
|
|
2014-10-31 16:09:34 +01:00
|
|
|
bool AndroidConfigurations::force32bitEmulator()
|
|
|
|
{
|
|
|
|
return m_instance->m_force32bit;
|
|
|
|
}
|
|
|
|
|
2017-10-10 09:58:19 +02:00
|
|
|
QProcessEnvironment AndroidConfigurations::toolsEnvironment(const AndroidConfig &config)
|
|
|
|
{
|
|
|
|
Environment env = Environment::systemEnvironment();
|
|
|
|
Utils::FileName jdkLocation = config.openJDKLocation();
|
|
|
|
if (!jdkLocation.isEmpty()) {
|
|
|
|
env.set("JAVA_HOME", jdkLocation.toUserOutput());
|
|
|
|
Utils::FileName binPath = jdkLocation;
|
|
|
|
binPath.appendPath("bin");
|
|
|
|
env.prependOrSetPath(binPath.toUserOutput());
|
|
|
|
}
|
|
|
|
return env.toProcessEnvironment();
|
|
|
|
}
|
|
|
|
|
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("????")))
|
2017-02-07 16:59:21 +01:00
|
|
|
return QStringList("-d");
|
2017-02-22 15:09:35 +01:00
|
|
|
return QStringList({"-s", serialNumber});
|
2013-02-24 18:04:36 +04:00
|
|
|
}
|
|
|
|
|
2017-03-30 14:43:13 +02:00
|
|
|
bool AndroidDeviceInfo::operator<(const AndroidDeviceInfo &other) const
|
|
|
|
{
|
|
|
|
if (serialNumber.contains("????") != other.serialNumber.contains("????"))
|
|
|
|
return !serialNumber.contains("????");
|
|
|
|
if (type != other.type)
|
|
|
|
return type == AndroidDeviceInfo::Hardware;
|
|
|
|
if (sdk != other.sdk)
|
|
|
|
return sdk < other.sdk;
|
|
|
|
if (avdname != other.avdname)
|
|
|
|
return avdname < other.avdname;
|
|
|
|
|
|
|
|
return serialNumber < other.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
|
|
|
|
}
|
|
|
|
|
2017-08-18 08:22:34 +02:00
|
|
|
AndroidSdkManager *AndroidConfigurations::sdkManager()
|
|
|
|
{
|
|
|
|
return m_instance->m_sdkManager.get();
|
|
|
|
}
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2018-01-26 14:57:01 +01:00
|
|
|
AndroidConfigurations::AndroidConfigurations()
|
|
|
|
: m_sdkManager(new AndroidSdkManager(m_config))
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
|
|
|
load();
|
2013-09-10 19:19:31 +02:00
|
|
|
|
2016-04-29 23:06:26 +02:00
|
|
|
connect(SessionManager::instance(), &SessionManager::projectRemoved,
|
|
|
|
this, &AndroidConfigurations::clearDefaultDevices);
|
2018-02-09 16:16:38 +01:00
|
|
|
connect(DeviceManager::instance(), &DeviceManager::devicesLoaded,
|
|
|
|
this, &AndroidConfigurations::updateAndroidDevice);
|
2013-12-16 20:19:07 +01:00
|
|
|
|
2014-10-31 16:09:34 +01:00
|
|
|
m_force32bit = is32BitUserSpace();
|
|
|
|
|
2013-12-16 20:19:07 +01:00
|
|
|
m_instance = this;
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2017-08-18 08:22:34 +02:00
|
|
|
AndroidConfigurations::~AndroidConfigurations()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-07-15 23:32:11 +03:00
|
|
|
static FileName javaHomeForJavac(const FileName &location)
|
2013-10-08 15:25:34 +02:00
|
|
|
{
|
2014-07-15 23:32:11 +03:00
|
|
|
QFileInfo fileInfo = location.toFileInfo();
|
2013-10-08 15:25:34 +02:00
|
|
|
int tries = 5;
|
|
|
|
while (tries > 0) {
|
|
|
|
QDir dir = fileInfo.dir();
|
|
|
|
dir.cdUp();
|
2014-10-24 10:28:28 +02:00
|
|
|
if (QFileInfo::exists(dir.filePath(QLatin1String("lib/tools.jar"))))
|
2014-07-15 23:32:11 +03:00
|
|
|
return FileName::fromString(dir.path());
|
2013-10-08 15:25:34 +02:00
|
|
|
if (fileInfo.isSymLink())
|
|
|
|
fileInfo.setFile(fileInfo.symLinkTarget());
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
--tries;
|
|
|
|
}
|
2014-07-15 23:32:11 +03:00
|
|
|
return FileName();
|
2013-10-08 15:25:34 +02:00
|
|
|
}
|
|
|
|
|
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.openJDKLocation().isEmpty()) {
|
2013-10-08 15:25:34 +02:00
|
|
|
if (HostOsInfo::isLinuxHost()) {
|
|
|
|
Environment env = Environment::systemEnvironment();
|
2014-07-15 23:32:11 +03:00
|
|
|
FileName location = env.searchInPath(QLatin1String("javac"));
|
|
|
|
QFileInfo fi = location.toFileInfo();
|
2013-10-08 15:25:34 +02:00
|
|
|
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()) {
|
2015-10-01 16:38:08 +02:00
|
|
|
QFileInfo javaHomeExec(QLatin1String("/usr/libexec/java_home"));
|
|
|
|
if (javaHomeExec.isExecutable() && !javaHomeExec.isDir()) {
|
2016-04-29 16:52:58 +02:00
|
|
|
SynchronousProcess proc;
|
|
|
|
proc.setTimeoutS(2);
|
2015-10-01 16:38:08 +02:00
|
|
|
proc.setProcessChannelMode(QProcess::MergedChannels);
|
2016-05-26 12:12:01 +02:00
|
|
|
SynchronousProcessResponse response = proc.runBlocking(javaHomeExec.absoluteFilePath(), QStringList());
|
2016-04-29 16:52:58 +02:00
|
|
|
if (response.result == SynchronousProcessResponse::Finished) {
|
|
|
|
const QString &javaHome = response.allOutput().trimmed();
|
2015-10-01 16:38:08 +02:00
|
|
|
if (!javaHome.isEmpty() && QFileInfo::exists(javaHome))
|
|
|
|
m_config.setOpenJDKLocation(FileName::fromString(javaHome));
|
|
|
|
}
|
|
|
|
}
|
2013-08-23 09:21:18 +02:00
|
|
|
} else if (HostOsInfo::isWindowsHost()) {
|
2017-08-08 14:27:54 +02:00
|
|
|
QStringList allVersions;
|
|
|
|
std::unique_ptr<QSettings> settings(new QSettings(jdkSettingsPath,
|
|
|
|
QSettings::NativeFormat));
|
|
|
|
allVersions = settings->childGroups();
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
if (allVersions.isEmpty()) {
|
|
|
|
settings.reset(new QSettings(jdkSettingsPath, QSettings::Registry64Format));
|
|
|
|
allVersions = settings->childGroups();
|
|
|
|
}
|
2018-04-25 13:24:28 +02:00
|
|
|
#endif // Q_OS_WIN
|
|
|
|
|
2013-06-10 18:19:08 +02:00
|
|
|
QString javaHome;
|
|
|
|
int major = -1;
|
|
|
|
int minor = -1;
|
|
|
|
foreach (const QString &version, allVersions) {
|
2014-08-29 14:00:18 +02:00
|
|
|
QStringList parts = version.split(QLatin1Char('.'));
|
2013-06-10 18:19:08 +02:00
|
|
|
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)) {
|
2017-08-08 14:27:54 +02:00
|
|
|
settings->beginGroup(version);
|
|
|
|
QString tmpJavaHome = settings->value(QLatin1String("JavaHome")).toString();
|
|
|
|
settings->endGroup();
|
2014-10-24 10:28:28 +02:00
|
|
|
if (!QFileInfo::exists(tmpJavaHome))
|
2013-06-10 18:19:08 +02:00
|
|
|
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();
|
2014-10-24 13:15:54 +02:00
|
|
|
if (m_instance->m_config.adbToolPath().exists())
|
2015-02-03 23:50:37 +02:00
|
|
|
devMgr->addDevice(IDevice::Ptr(new 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 Android
|