2012-04-18 20:30:57 +03:00
|
|
|
/**************************************************************************
|
|
|
|
**
|
2013-01-28 17:12:19 +01:00
|
|
|
** Copyright (c) 2013 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"
|
2012-04-18 20:30:57 +03:00
|
|
|
#include "ui_addnewavddialog.h"
|
|
|
|
|
|
|
|
#include <coreplugin/icore.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>
|
|
|
|
#include <debugger/debuggerkitinformation.h>
|
|
|
|
#include <qtsupport/baseqtversion.h>
|
|
|
|
#include <qtsupport/qtkitinformation.h>
|
|
|
|
#include <qtsupport/qtversionmanager.h>
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
#include <QDateTime>
|
|
|
|
#include <QSettings>
|
|
|
|
#include <QStringList>
|
|
|
|
#include <QProcess>
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QDirIterator>
|
|
|
|
#include <QMetaObject>
|
|
|
|
|
|
|
|
#include <QStringListModel>
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
#include <iostream>
|
|
|
|
#include <windows.h>
|
|
|
|
#define sleep(_n) Sleep(1000 * (_n))
|
2012-04-26 12:56:02 +02:00
|
|
|
#else
|
|
|
|
#include <unistd.h>
|
2012-04-18 20:30:57 +03:00
|
|
|
#endif
|
|
|
|
|
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");
|
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
|
|
|
{
|
|
|
|
return dev1.sdk < dev2.sdk;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-25 16:49:22 +01:00
|
|
|
Abi::Architecture AndroidConfigurations::architectureForToolChainPrefix(const QString& toolchainprefix)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
QLatin1String AndroidConfigurations::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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
QLatin1String AndroidConfigurations::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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidConfig::AndroidConfig(const QSettings &settings)
|
|
|
|
{
|
|
|
|
// user settings
|
|
|
|
partitionSize = settings.value(PartitionSizeKey, 1024).toInt();
|
2012-08-09 01:56:51 +02:00
|
|
|
sdkLocation = FileName::fromString(settings.value(SDKLocationKey).toString());
|
|
|
|
ndkLocation = FileName::fromString(settings.value(NDKLocationKey).toString());
|
|
|
|
antLocation = FileName::fromString(settings.value(AntLocationKey).toString());
|
|
|
|
openJDKLocation = FileName::fromString(settings.value(OpenJDKLocationKey).toString());
|
|
|
|
keystoreLocation = FileName::fromString(settings.value(KeystoreLocationKey).toString());
|
2013-04-04 01:29:47 -07:00
|
|
|
toolchainHost = settings.value(ToolchainHostKey).toString();
|
2013-02-14 15:51:59 +01:00
|
|
|
automaticKitCreation = settings.value(AutomaticKitCreationKey, true).toBool();
|
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
|
2012-08-09 01:56:51 +02:00
|
|
|
sdkLocation = FileName::fromString(reader.restoreValue(SDKLocationKey).toString());
|
|
|
|
ndkLocation = FileName::fromString(reader.restoreValue(NDKLocationKey).toString());
|
|
|
|
antLocation = FileName::fromString(reader.restoreValue(AntLocationKey).toString());
|
|
|
|
openJDKLocation = FileName::fromString(reader.restoreValue(OpenJDKLocationKey).toString());
|
|
|
|
keystoreLocation = FileName::fromString(reader.restoreValue(KeystoreLocationKey).toString());
|
2013-04-04 01:29:47 -07:00
|
|
|
toolchainHost = reader.restoreValue(ToolchainHostKey).toString();
|
2013-02-14 15:51:59 +01:00
|
|
|
QVariant v = reader.restoreValue(AutomaticKitCreationKey);
|
|
|
|
if (v.isValid())
|
|
|
|
automaticKitCreation = v.toBool();
|
2012-04-18 20:30:57 +03:00
|
|
|
// persistent settings
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidConfig::AndroidConfig()
|
|
|
|
{
|
|
|
|
partitionSize = 1024;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2012-04-24 15:49:09 +02:00
|
|
|
settings.setValue(SDKLocationKey, sdkLocation.toString());
|
|
|
|
settings.setValue(NDKLocationKey, ndkLocation.toString());
|
|
|
|
settings.setValue(AntLocationKey, antLocation.toString());
|
|
|
|
settings.setValue(OpenJDKLocationKey, openJDKLocation.toString());
|
|
|
|
settings.setValue(KeystoreLocationKey, keystoreLocation.toString());
|
2012-04-18 20:30:57 +03:00
|
|
|
settings.setValue(PartitionSizeKey, partitionSize);
|
2013-02-14 15:51:59 +01:00
|
|
|
settings.setValue(AutomaticKitCreationKey, automaticKitCreation);
|
2013-04-04 01:29:47 -07:00
|
|
|
settings.setValue(ToolchainHostKey, toolchainHost);
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfigurations::setConfig(const AndroidConfig &devConfigs)
|
|
|
|
{
|
|
|
|
m_config = devConfigs;
|
2013-04-04 01:29:47 -07:00
|
|
|
|
|
|
|
if (m_config.toolchainHost.isEmpty())
|
|
|
|
detectToolchainHost();
|
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
save();
|
|
|
|
updateAvailablePlatforms();
|
2013-02-14 15:51:59 +01:00
|
|
|
updateAutomaticKitList();
|
2012-04-18 20:30:57 +03:00
|
|
|
emit updated();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfigurations::updateAvailablePlatforms()
|
|
|
|
{
|
|
|
|
m_availablePlatforms.clear();
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName path = m_config.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();
|
|
|
|
m_availablePlatforms.push_back(fileName.mid(fileName.lastIndexOf(QLatin1Char('-')) + 1).toInt());
|
|
|
|
}
|
|
|
|
qSort(m_availablePlatforms.begin(), m_availablePlatforms.end(), qGreater<int>());
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList AndroidConfigurations::sdkTargets(int minApiLevel) const
|
|
|
|
{
|
|
|
|
QStringList targets;
|
|
|
|
QProcess proc;
|
2012-04-24 15:49:09 +02:00
|
|
|
proc.start(androidToolPath().toString(), QStringList() << QLatin1String("list") << QLatin1String("target")); // list avaialbe AVDs
|
2012-04-18 20:30:57 +03:00
|
|
|
if (!proc.waitForFinished(-1)) {
|
|
|
|
proc.terminate();
|
|
|
|
return targets;
|
|
|
|
}
|
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());
|
2012-04-18 20:30:57 +03:00
|
|
|
int index = line.indexOf(QLatin1String("\"android-"));
|
|
|
|
if (index == -1)
|
|
|
|
continue;
|
|
|
|
QString apiLevel = line.mid(index + 1, line.length() - index - 2);
|
|
|
|
if (apiLevel.mid(apiLevel.lastIndexOf(QLatin1Char('-')) + 1).toInt() >= minApiLevel)
|
|
|
|
targets.push_back(apiLevel);
|
|
|
|
}
|
|
|
|
return targets;
|
|
|
|
}
|
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName AndroidConfigurations::adbToolPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName path = m_config.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
|
|
|
}
|
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName AndroidConfigurations::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.
|
|
|
|
FileName path = m_config.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;
|
|
|
|
path = m_config.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 {
|
|
|
|
FileName path = m_config.sdkLocation;
|
|
|
|
return path.appendPath(QLatin1String("tools/android"));
|
|
|
|
}
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName AndroidConfigurations::antToolPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2012-04-24 15:49:09 +02:00
|
|
|
if (!m_config.antLocation.isEmpty())
|
2012-04-18 20:30:57 +03:00
|
|
|
return m_config.antLocation;
|
|
|
|
else
|
2012-08-09 01:56:51 +02:00
|
|
|
return FileName::fromString(QLatin1String("ant"));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName AndroidConfigurations::emulatorToolPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName path = m_config.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-01-25 16:49:22 +01:00
|
|
|
FileName AndroidConfigurations::toolPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName path = m_config.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-04-04 01:29:47 -07:00
|
|
|
.arg(m_config.toolchainHost)
|
2012-04-24 15:49:09 +02:00
|
|
|
.arg(toolsPrefix(architecture)));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-01-25 16:49:22 +01:00
|
|
|
FileName AndroidConfigurations::stripPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-01-25 16:49:22 +01:00
|
|
|
return toolPath(architecture, ndkToolChainVersion).append(QLatin1String("-strip" QTC_HOST_EXE_SUFFIX));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-01-25 16:49:22 +01:00
|
|
|
FileName AndroidConfigurations::readelfPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-01-25 16:49:22 +01:00
|
|
|
return toolPath(architecture, ndkToolChainVersion).append(QLatin1String("-readelf" QTC_HOST_EXE_SUFFIX));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2013-04-04 01:29:47 -07:00
|
|
|
FileName AndroidConfigurations::gccPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
|
|
|
|
{
|
|
|
|
return toolPath(architecture, ndkToolChainVersion).append(QLatin1String("-gcc" QTC_HOST_EXE_SUFFIX));
|
|
|
|
}
|
|
|
|
|
2013-01-25 16:49:22 +01:00
|
|
|
FileName AndroidConfigurations::gdbPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2013-01-25 16:49:22 +01:00
|
|
|
return toolPath(architecture, ndkToolChainVersion).append(QLatin1String("-gdb" QTC_HOST_EXE_SUFFIX));
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName AndroidConfigurations::openJDKPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
|
|
|
return m_config.openJDKLocation;
|
|
|
|
}
|
|
|
|
|
2013-04-04 01:29:47 -07:00
|
|
|
void AndroidConfigurations::detectToolchainHost()
|
|
|
|
{
|
|
|
|
QStringList hostPatterns;
|
|
|
|
switch (HostOsInfo::hostOs()) {
|
|
|
|
case HostOsInfo::HostOsLinux:
|
|
|
|
hostPatterns << QLatin1String("linux*");
|
|
|
|
break;
|
|
|
|
case HostOsInfo::HostOsWindows:
|
|
|
|
hostPatterns << QLatin1String("windows*");
|
|
|
|
break;
|
|
|
|
case HostOsInfo::HostOsMac:
|
|
|
|
hostPatterns << QLatin1String("darwin*");
|
|
|
|
break;
|
|
|
|
default: /* unknown host */ return;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileName path = m_config.ndkLocation;
|
|
|
|
QDirIterator it(path.appendPath(QLatin1String("prebuilt")).toString(), hostPatterns, QDir::Dirs);
|
|
|
|
if (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
m_config.toolchainHost = it.fileName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName AndroidConfigurations::openJDKBinPath() const
|
2012-04-18 20:30:57 +03:00
|
|
|
{
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName path = m_config.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
|
|
|
}
|
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName AndroidConfigurations::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
|
|
|
}
|
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName AndroidConfigurations::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
|
|
|
}
|
|
|
|
|
2012-08-09 01:56:51 +02:00
|
|
|
FileName AndroidConfigurations::zipalignPath() const
|
2012-06-23 13:18:01 +03:00
|
|
|
{
|
|
|
|
Utils::FileName path = m_config.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
|
|
|
}
|
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
QString AndroidConfigurations::getDeployDeviceSerialNumber(int *apiLevel) const
|
|
|
|
{
|
2012-07-03 16:57:44 +03:00
|
|
|
QVector<AndroidDeviceInfo> devices = connectedDevices();
|
2012-04-18 20:30:57 +03:00
|
|
|
|
2012-07-03 16:57:44 +03:00
|
|
|
foreach (AndroidDeviceInfo device, devices) {
|
2012-04-18 20:30:57 +03:00
|
|
|
if (device.sdk >= *apiLevel) {
|
|
|
|
*apiLevel = device.sdk;
|
|
|
|
return device.serialNumber;
|
|
|
|
}
|
2012-04-24 15:49:09 +02:00
|
|
|
}
|
2012-04-18 20:30:57 +03:00
|
|
|
return startAVD(apiLevel);
|
|
|
|
}
|
|
|
|
|
2012-07-03 16:57:44 +03:00
|
|
|
QVector<AndroidDeviceInfo> AndroidConfigurations::connectedDevices(int apiLevel) 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"));
|
2012-04-18 20:30:57 +03:00
|
|
|
if (!adbProc.waitForFinished(-1)) {
|
2012-12-10 23:43:21 +00:00
|
|
|
adbProc.kill();
|
2012-04-18 20:30:57 +03:00
|
|
|
return devices;
|
|
|
|
}
|
|
|
|
QList<QByteArray> adbDevs = adbProc.readAll().trimmed().split('\n');
|
|
|
|
adbDevs.removeFirst();
|
2012-07-03 16:57:44 +03:00
|
|
|
AndroidDeviceInfo dev;
|
2013-02-24 18:04:36 +04:00
|
|
|
|
|
|
|
// workaround for '????????????' serial numbers:
|
|
|
|
// can use "adb -d" when only one usb device attached
|
|
|
|
int usbDevicesNum = 0;
|
|
|
|
QStringList serialNumbers;
|
2012-04-18 20:30:57 +03:00
|
|
|
foreach (const QByteArray &device, adbDevs) {
|
2013-02-24 18:04:36 +04:00
|
|
|
const QString serialNo = QString::fromLatin1(device.left(device.indexOf('\t')).trimmed());;
|
|
|
|
if (!serialNo.startsWith(QLatin1String("emulator")))
|
|
|
|
++usbDevicesNum;
|
|
|
|
serialNumbers << serialNo;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (const QString &serialNo, serialNumbers) {
|
|
|
|
if (serialNo.contains(QLatin1String("????")) && usbDevicesNum > 1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
dev.serialNumber = serialNo;
|
2012-04-18 20:30:57 +03:00
|
|
|
dev.sdk = getSDKVersion(dev.serialNumber);
|
|
|
|
if (apiLevel != -1 && dev.sdk != apiLevel)
|
|
|
|
continue;
|
|
|
|
devices.push_back(dev);
|
|
|
|
}
|
|
|
|
qSort(devices.begin(), devices.end(), androidDevicesLessThan);
|
|
|
|
return devices;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AndroidConfigurations::createAVD(int minApiLevel) const
|
|
|
|
{
|
|
|
|
QDialog d;
|
|
|
|
Ui::AddNewAVDDialog avdDialog;
|
|
|
|
avdDialog.setupUi(&d);
|
|
|
|
QStringListModel model(sdkTargets(minApiLevel));
|
|
|
|
avdDialog.targetComboBox->setModel(&model);
|
|
|
|
if (!model.rowCount()) {
|
2012-08-01 15:25:05 +02:00
|
|
|
QMessageBox::critical(0, tr("Error Creating AVD"),
|
2012-09-28 16:13:16 +02:00
|
|
|
tr("Cannot create a new AVD. No sufficiently recent Android SDK available.\n"
|
2012-08-01 15:25:05 +02:00
|
|
|
"Please install an SDK of at least API version %1.").
|
2012-05-25 16:21:19 +02:00
|
|
|
arg(minApiLevel));
|
2012-04-18 20:30:57 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRegExp rx(QLatin1String("\\S+"));
|
|
|
|
QRegExpValidator v(rx, 0);
|
|
|
|
avdDialog.nameLineEdit->setValidator(&v);
|
|
|
|
if (d.exec() != QDialog::Accepted)
|
|
|
|
return false;
|
|
|
|
return createAVD(avdDialog.targetComboBox->currentText(), avdDialog.nameLineEdit->text(), avdDialog.sizeSpinBox->value());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AndroidConfigurations::createAVD(const QString &target, const QString &name, int sdcardSize ) const
|
|
|
|
{
|
|
|
|
QProcess proc;
|
2012-04-24 15:49:09 +02:00
|
|
|
proc.start(androidToolPath().toString(),
|
2012-04-18 20:30:57 +03:00
|
|
|
QStringList() << QLatin1String("create") << QLatin1String("avd")
|
|
|
|
<< QLatin1String("-a") << QLatin1String("-t") << target
|
|
|
|
<< QLatin1String("-n") << name
|
|
|
|
<< QLatin1String("-c") << QString::fromLatin1("%1M").arg(sdcardSize));
|
|
|
|
if (!proc.waitForStarted())
|
|
|
|
return false;
|
|
|
|
proc.write(QByteArray("no\n"));
|
|
|
|
if (!proc.waitForFinished(-1)) {
|
|
|
|
proc.terminate();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return !proc.exitCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AndroidConfigurations::removeAVD(const QString &name) const
|
|
|
|
{
|
|
|
|
QProcess proc;
|
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);
|
|
|
|
if (!proc.waitForFinished(-1)) {
|
|
|
|
proc.terminate();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return !proc.exitCode();
|
|
|
|
}
|
|
|
|
|
2012-07-03 16:57:44 +03:00
|
|
|
QVector<AndroidDeviceInfo> AndroidConfigurations::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;
|
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
|
|
|
|
if (!proc.waitForFinished(-1)) {
|
|
|
|
proc.terminate();
|
|
|
|
return devices;
|
|
|
|
}
|
|
|
|
QList<QByteArray> avds = proc.readAll().trimmed().split('\n');
|
|
|
|
avds.removeFirst();
|
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();
|
|
|
|
if (line.contains(QLatin1String("ABI:")))
|
|
|
|
dev.cpuABI = line.mid(line.lastIndexOf(QLatin1Char(' '))).trimmed();
|
|
|
|
}
|
|
|
|
devices.push_back(dev);
|
|
|
|
}
|
|
|
|
qSort(devices.begin(), devices.end(), androidDevicesLessThan);
|
|
|
|
|
|
|
|
return devices;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidConfigurations::startAVD(int *apiLevel, const QString &name) const
|
|
|
|
{
|
2012-10-24 10:03:11 +02:00
|
|
|
QProcess *avdProcess = new QProcess();
|
|
|
|
connect(this, SIGNAL(destroyed()), avdProcess, SLOT(deleteLater()));
|
|
|
|
connect(avdProcess, SIGNAL(finished(int)), avdProcess, SLOT(deleteLater()));
|
2012-04-18 20:30:57 +03:00
|
|
|
|
|
|
|
QString avdName = name;
|
2012-07-03 16:57:44 +03:00
|
|
|
QVector<AndroidDeviceInfo> devices;
|
2012-04-18 20:30:57 +03:00
|
|
|
bool createAVDOnce = false;
|
|
|
|
while (true) {
|
|
|
|
if (avdName.isEmpty()) {
|
|
|
|
devices = androidVirtualDevices();
|
2012-10-24 10:03:11 +02:00
|
|
|
foreach (const AndroidDeviceInfo &device, devices)
|
2012-04-18 20:30:57 +03:00
|
|
|
if (device.sdk >= *apiLevel) { // take first emulator how supports this package
|
|
|
|
*apiLevel = device.sdk;
|
|
|
|
avdName = device.serialNumber;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if no emulators found try to create one once
|
|
|
|
if (avdName.isEmpty() && !createAVDOnce) {
|
|
|
|
createAVDOnce = true;
|
|
|
|
QMetaObject::invokeMethod(const_cast<QObject*>(static_cast<const QObject*>(this)), "createAVD", Qt::AutoConnection,
|
|
|
|
Q_ARG(int, *apiLevel));
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (avdName.isEmpty())// stop here if no emulators found
|
|
|
|
return avdName;
|
|
|
|
|
|
|
|
// start the emulator
|
2012-10-24 10:03:11 +02:00
|
|
|
avdProcess->start(emulatorToolPath().toString(),
|
2012-04-18 20:30:57 +03:00
|
|
|
QStringList() << QLatin1String("-partition-size") << QString::number(config().partitionSize)
|
|
|
|
<< QLatin1String("-avd") << avdName);
|
2012-10-24 10:03:11 +02:00
|
|
|
if (!avdProcess->waitForStarted(-1)) {
|
|
|
|
delete avdProcess;
|
2012-04-18 20:30:57 +03:00
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
// wait until the emulator is online
|
|
|
|
QProcess proc;
|
2012-04-24 15:49:09 +02:00
|
|
|
proc.start(adbToolPath().toString(), QStringList() << QLatin1String("-e") << QLatin1String("wait-for-device"));
|
2012-10-24 10:03:11 +02:00
|
|
|
while (!proc.waitForFinished(500)) {
|
|
|
|
if (avdProcess->waitForFinished(0)) {
|
2012-12-10 23:43:21 +00:00
|
|
|
proc.kill();
|
2012-10-24 10:03:11 +02:00
|
|
|
proc.waitForFinished(-1);
|
|
|
|
return QString();
|
|
|
|
}
|
2012-04-18 20:30:57 +03:00
|
|
|
}
|
|
|
|
sleep(5);// wait for pm to start
|
|
|
|
|
|
|
|
// workaround for stupid adb bug
|
2012-04-24 15:49:09 +02:00
|
|
|
proc.start(adbToolPath().toString(), QStringList() << QLatin1String("devices"));
|
2012-04-18 20:30:57 +03:00
|
|
|
if (!proc.waitForFinished(-1)) {
|
2012-12-10 23:43:21 +00:00
|
|
|
proc.kill();
|
2012-04-18 20:30:57 +03:00
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
// get connected devices
|
|
|
|
devices = connectedDevices(*apiLevel);
|
2012-07-03 16:57:44 +03:00
|
|
|
foreach (AndroidDeviceInfo device, devices)
|
2012-04-18 20:30:57 +03:00
|
|
|
if (device.sdk == *apiLevel)
|
|
|
|
return device.serialNumber;
|
|
|
|
// this should not happen, but ...
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
int AndroidConfigurations::getSDKVersion(const QString &device) const
|
|
|
|
{
|
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);
|
2012-04-18 20:30:57 +03:00
|
|
|
if (!adbProc.waitForFinished(-1)) {
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AndroidConfigurations::bestMatch(const QString &targetAPI) const
|
|
|
|
{
|
|
|
|
int target = targetAPI.mid(targetAPI.lastIndexOf(QLatin1Char('-')) + 1).toInt();
|
|
|
|
foreach (int apiLevel, m_availablePlatforms) {
|
|
|
|
if (apiLevel <= target)
|
|
|
|
return QString::fromLatin1("android-%1").arg(apiLevel);
|
|
|
|
}
|
|
|
|
return QLatin1String("android-8");
|
|
|
|
}
|
|
|
|
|
2013-02-14 15:51:59 +01:00
|
|
|
bool equalKits(Kit *a, Kit *b)
|
|
|
|
{
|
|
|
|
return ToolChainKitInformation::toolChain(a) == ToolChainKitInformation::toolChain(b)
|
|
|
|
&& QtSupport::QtKitInformation::qtVersion(a) == QtSupport::QtKitInformation::qtVersion(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfigurations::updateAutomaticKitList()
|
|
|
|
{
|
|
|
|
QList<AndroidToolChain *> toolchains;
|
|
|
|
if (AndroidConfigurations::instance().config().automaticKitCreation) {
|
|
|
|
// having a empty toolchains list will remove all autodetected kits for android
|
|
|
|
// exactly what we want in that case
|
|
|
|
foreach (ProjectExplorer::ToolChain *tc, ProjectExplorer::ToolChainManager::instance()->toolChains()) {
|
|
|
|
if (!tc->isAutoDetected())
|
|
|
|
continue;
|
|
|
|
if (tc->type() != QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE))
|
|
|
|
continue;
|
|
|
|
toolchains << static_cast<AndroidToolChain *>(tc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<Kit *> existingKits;
|
|
|
|
|
|
|
|
foreach (ProjectExplorer::Kit *k, ProjectExplorer::KitManager::instance()->kits()) {
|
|
|
|
if (ProjectExplorer::DeviceKitInformation::deviceId(k) != Core::Id(Constants::ANDROID_DEVICE_ID))
|
|
|
|
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
|
|
|
|
|
|
|
existingKits << k;
|
|
|
|
}
|
|
|
|
|
|
|
|
QMap<ProjectExplorer::Abi::Architecture, QList<QtSupport::BaseQtVersion *> > qtVersionsForArch;
|
|
|
|
foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::instance()->versions()) {
|
|
|
|
if (qtVersion->type() != QLatin1String(Constants::ANDROIDQT))
|
|
|
|
continue;
|
2013-02-25 09:17:43 +02:00
|
|
|
QList<ProjectExplorer::Abi> qtAbis = qtVersion->qtAbis();
|
|
|
|
if (qtAbis.empty())
|
|
|
|
continue;
|
|
|
|
qtVersionsForArch[qtAbis.first().architecture()].append(qtVersion);
|
2013-02-14 15:51:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ProjectExplorer::DeviceManager *dm = ProjectExplorer::DeviceManager::instance();
|
|
|
|
IDevice::ConstPtr device = dm->find(Core::Id(Constants::ANDROID_DEVICE_ID)); // should always exist
|
|
|
|
|
|
|
|
// register new kits
|
|
|
|
QList<Kit *> newKits;
|
|
|
|
foreach (AndroidToolChain *tc, toolchains) {
|
|
|
|
QList<QtSupport::BaseQtVersion *> qtVersions = qtVersionsForArch.value(tc->targetAbi().architecture());
|
|
|
|
foreach (QtSupport::BaseQtVersion *qt, qtVersions) {
|
|
|
|
Kit *newKit = new Kit;
|
|
|
|
newKit->setAutoDetected(true);
|
2013-02-20 17:05:00 +01:00
|
|
|
newKit->setIconPath(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);
|
|
|
|
Debugger::DebuggerKitInformation::DebuggerItem item;
|
|
|
|
item.engineType = Debugger::GdbEngineType;
|
|
|
|
item.binary = tc->suggestedDebugger();
|
|
|
|
Debugger::DebuggerKitInformation::setDebuggerItem(newKit, item);
|
|
|
|
AndroidGdbServerKitInformation::setGdbSever(newKit, tc->suggestedGdbServer());
|
|
|
|
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);
|
|
|
|
existingKits.removeAt(i);
|
|
|
|
KitManager::deleteKit(newKit);
|
|
|
|
j = newKits.count();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (Kit *k, existingKits)
|
|
|
|
KitManager::instance()->deregisterKit(k);
|
|
|
|
|
2013-02-27 13:08:54 +01:00
|
|
|
foreach (Kit *kit, newKits) {
|
|
|
|
AndroidToolChain *tc = static_cast<AndroidToolChain *>(ToolChainKitInformation::toolChain(kit));
|
|
|
|
QString arch = ProjectExplorer::Abi::toString(tc->targetAbi().architecture());
|
|
|
|
QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(kit);
|
|
|
|
kit->setDisplayName(tr("Android for %1 (GCC %2, Qt %3)")
|
|
|
|
.arg(arch)
|
|
|
|
.arg(tc->ndkToolChainVersion())
|
|
|
|
.arg(qt->qtVersionString()));
|
2013-02-14 15:51:59 +01:00
|
|
|
KitManager::instance()->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;
|
|
|
|
}
|
|
|
|
|
2012-04-18 20:30:57 +03:00
|
|
|
AndroidConfigurations &AndroidConfigurations::instance(QObject *parent)
|
|
|
|
{
|
|
|
|
if (m_instance == 0)
|
|
|
|
m_instance = new AndroidConfigurations(parent);
|
|
|
|
return *m_instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfigurations::save()
|
|
|
|
{
|
|
|
|
QSettings *settings = Core::ICore::instance()->settings();
|
|
|
|
settings->beginGroup(SettingsGroup);
|
|
|
|
m_config.save(*settings);
|
|
|
|
settings->endGroup();
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidConfigurations::AndroidConfigurations(QObject *parent)
|
|
|
|
: QObject(parent)
|
|
|
|
{
|
|
|
|
load();
|
|
|
|
updateAvailablePlatforms();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AndroidConfigurations::load()
|
|
|
|
{
|
|
|
|
QSettings *settings = Core::ICore::instance()->settings();
|
|
|
|
settings->beginGroup(SettingsGroup);
|
|
|
|
m_config = AndroidConfig(*settings);
|
|
|
|
settings->endGroup();
|
|
|
|
}
|
|
|
|
|
|
|
|
AndroidConfigurations *AndroidConfigurations::m_instance = 0;
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
} // namespace Android
|