androidconfigurations.cpp 45.8 KB
Newer Older
BogDan Vatra's avatar
BogDan Vatra committed
1 2
/**************************************************************************
**
3
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
BogDan Vatra's avatar
BogDan Vatra committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
BogDan Vatra's avatar
BogDan Vatra committed
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** 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.
BogDan Vatra's avatar
BogDan Vatra committed
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22 23 24 25
** 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
BogDan Vatra's avatar
BogDan Vatra committed
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
BogDan Vatra's avatar
BogDan Vatra committed
29 30 31

#include "androidconfigurations.h"
#include "androidconstants.h"
Daniel Teske's avatar
Daniel Teske committed
32 33 34
#include "androidtoolchain.h"
#include "androiddevice.h"
#include "androidgdbserverkitinformation.h"
35
#include "androidqtversion.h"
36
#include "androiddevicedialog.h"
37
#include "avddialog.h"
BogDan Vatra's avatar
BogDan Vatra committed
38 39

#include <coreplugin/icore.h>
40
#include <coreplugin/messagemanager.h>
41
#include <utils/hostosinfo.h>
BogDan Vatra's avatar
BogDan Vatra committed
42
#include <utils/persistentsettings.h>
Daniel Teske's avatar
Daniel Teske committed
43 44 45 46
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/devicesupport/devicemanager.h>
#include <projectexplorer/toolchainmanager.h>
47
#include <projectexplorer/session.h>
48
#include <debugger/debuggeritemmanager.h>
Daniel Teske's avatar
Daniel Teske committed
49 50 51 52
#include <debugger/debuggerkitinformation.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtversionmanager.h>
Daniel Teske's avatar
Daniel Teske committed
53
#include <utils/environment.h>
Orgad Shaneh's avatar
Orgad Shaneh committed
54
#include <utils/sleep.h>
BogDan Vatra's avatar
BogDan Vatra committed
55 56 57 58 59 60 61 62

#include <QDateTime>
#include <QSettings>
#include <QStringList>
#include <QProcess>
#include <QFileInfo>
#include <QDirIterator>
#include <QMetaObject>
63
#include <QApplication>
BogDan Vatra's avatar
BogDan Vatra committed
64 65 66 67

#include <QStringListModel>
#include <QMessageBox>

hjk's avatar
hjk committed
68
using namespace ProjectExplorer;
BogDan Vatra's avatar
BogDan Vatra committed
69 70 71 72 73 74 75 76 77 78 79 80 81
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");
Daniel Teske's avatar
Daniel Teske committed
82
    const QLatin1String AutomaticKitCreationKey("AutomatiKitCreation");
83
    const QLatin1String MakeExtraSearchDirectory("MakeExtraSearchDirectory");
84
    const QLatin1String DefaultDevice("DefaultDevice");
BogDan Vatra's avatar
BogDan Vatra committed
85
    const QLatin1String PartitionSizeKey("PartitionSize");
86
    const QLatin1String ToolchainHostKey("ToolchainHost");
BogDan Vatra's avatar
BogDan Vatra committed
87 88
    const QLatin1String ArmToolchainPrefix("arm-linux-androideabi");
    const QLatin1String X86ToolchainPrefix("x86");
BogDan Vatra's avatar
BogDan Vatra committed
89
    const QLatin1String MipsToolchainPrefix("mipsel-linux-android");
BogDan Vatra's avatar
BogDan Vatra committed
90
    const QLatin1String ArmToolsPrefix("arm-linux-androideabi");
BogDan Vatra's avatar
BogDan Vatra committed
91
    const QLatin1String X86ToolsPrefix("i686-linux-android");
BogDan Vatra's avatar
BogDan Vatra committed
92
    const QLatin1String MipsToolsPrefix("mipsel-linux-android");
BogDan Vatra's avatar
BogDan Vatra committed
93 94 95 96 97
    const QLatin1String Unknown("unknown");
    const QLatin1String keytoolName("keytool");
    const QLatin1String jarsignerName("jarsigner");
    const QLatin1String changeTimeStamp("ChangeTimeStamp");

98
    static QString sdkSettingsFileName()
BogDan Vatra's avatar
BogDan Vatra committed
99
    {
100 101
        return QFileInfo(Core::ICore::settings(QSettings::SystemScope)->fileName()).absolutePath()
                + QLatin1String("/qtcreator/android.xml");
BogDan Vatra's avatar
BogDan Vatra committed
102 103
    }

104
    bool androidDevicesLessThan(const AndroidDeviceInfo &dev1, const AndroidDeviceInfo &dev2)
BogDan Vatra's avatar
BogDan Vatra committed
105
    {
Daniel Teske's avatar
Compile  
Daniel Teske committed
106 107
        if (dev1.serialNumber.contains(QLatin1String("????")) == dev2.serialNumber.contains(QLatin1String("????")))
            return !dev1.serialNumber.contains(QLatin1String("????"));
108 109
        if (dev1.type != dev2.type)
            return dev1.type == AndroidDeviceInfo::Hardware;
110 111
        if (dev1.sdk != dev2.sdk)
            return dev1.sdk < dev2.sdk;
112

113
        return dev1.serialNumber < dev2.serialNumber;
BogDan Vatra's avatar
BogDan Vatra committed
114
    }
115 116 117 118 119 120 121 122 123 124 125 126 127

    static QStringList cleanAndroidABIs(const QStringList &abis)
    {
        QStringList res;
        foreach (const QString &abi, abis) {
            int index = abi.lastIndexOf(QLatin1Char('/'));
            if (index == -1)
                res << abi;
            else
                res << abi.mid(index + 1);
        }
        return res;
    }
BogDan Vatra's avatar
BogDan Vatra committed
128 129
}

Daniel Teske's avatar
Daniel Teske committed
130 131 132 133 134
//////////////////////////////////
// AndroidConfig
//////////////////////////////////

Abi::Architecture AndroidConfig::architectureForToolChainPrefix(const QString& toolchainprefix)
135 136 137 138 139
{
    if (toolchainprefix == ArmToolchainPrefix)
        return Abi::ArmArchitecture;
    if (toolchainprefix == X86ToolchainPrefix)
        return Abi::X86Architecture;
BogDan Vatra's avatar
BogDan Vatra committed
140 141
    if (toolchainprefix == MipsToolchainPrefix)
        return Abi::MipsArchitecture;
142 143 144
    return Abi::UnknownArchitecture;
}

Daniel Teske's avatar
Daniel Teske committed
145
QLatin1String AndroidConfig::toolchainPrefix(Abi::Architecture architecture)
BogDan Vatra's avatar
BogDan Vatra committed
146 147
{
    switch (architecture) {
hjk's avatar
hjk committed
148
    case Abi::ArmArchitecture:
BogDan Vatra's avatar
BogDan Vatra committed
149
        return ArmToolchainPrefix;
hjk's avatar
hjk committed
150
    case Abi::X86Architecture:
BogDan Vatra's avatar
BogDan Vatra committed
151
        return X86ToolchainPrefix;
BogDan Vatra's avatar
BogDan Vatra committed
152 153
    case Abi::MipsArchitecture:
        return MipsToolchainPrefix;
BogDan Vatra's avatar
BogDan Vatra committed
154 155 156 157 158
    default:
        return Unknown;
    }
}

Daniel Teske's avatar
Daniel Teske committed
159
QLatin1String AndroidConfig::toolsPrefix(Abi::Architecture architecture)
BogDan Vatra's avatar
BogDan Vatra committed
160 161
{
    switch (architecture) {
hjk's avatar
hjk committed
162
    case Abi::ArmArchitecture:
BogDan Vatra's avatar
BogDan Vatra committed
163
        return ArmToolsPrefix;
hjk's avatar
hjk committed
164
    case Abi::X86Architecture:
BogDan Vatra's avatar
BogDan Vatra committed
165
        return X86ToolsPrefix;
BogDan Vatra's avatar
BogDan Vatra committed
166 167
    case Abi::MipsArchitecture:
        return MipsToolsPrefix;
BogDan Vatra's avatar
BogDan Vatra committed
168 169 170 171 172
    default:
        return Unknown;
    }
}

Daniel Teske's avatar
Daniel Teske committed
173
void AndroidConfig::load(const QSettings &settings)
BogDan Vatra's avatar
BogDan Vatra committed
174 175
{
    // user settings
Daniel Teske's avatar
Daniel Teske committed
176 177 178 179 180 181 182 183
    m_partitionSize = settings.value(PartitionSizeKey, 1024).toInt();
    m_sdkLocation = FileName::fromString(settings.value(SDKLocationKey).toString());
    m_ndkLocation = FileName::fromString(settings.value(NDKLocationKey).toString());
    m_antLocation = FileName::fromString(settings.value(AntLocationKey).toString());
    m_openJDKLocation = FileName::fromString(settings.value(OpenJDKLocationKey).toString());
    m_keystoreLocation = FileName::fromString(settings.value(KeystoreLocationKey).toString());
    m_toolchainHost = settings.value(ToolchainHostKey).toString();
    m_automaticKitCreation = settings.value(AutomaticKitCreationKey, true).toBool();
184
    QString extraDirectory = settings.value(MakeExtraSearchDirectory).toString();
Daniel Teske's avatar
Daniel Teske committed
185
    m_makeExtraSearchDirectories.clear();
186
    if (!extraDirectory.isEmpty())
Daniel Teske's avatar
Daniel Teske committed
187
        m_makeExtraSearchDirectories << extraDirectory;
BogDan Vatra's avatar
BogDan Vatra committed
188 189

    PersistentSettingsReader reader;
190 191
    if (reader.load(FileName::fromString(sdkSettingsFileName()))
            && settings.value(changeTimeStamp).toInt() != QFileInfo(sdkSettingsFileName()).lastModified().toMSecsSinceEpoch() / 1000) {
BogDan Vatra's avatar
BogDan Vatra committed
192
        // persisten settings
Daniel Teske's avatar
Daniel Teske committed
193 194 195 196 197 198
        m_sdkLocation = FileName::fromString(reader.restoreValue(SDKLocationKey).toString());
        m_ndkLocation = FileName::fromString(reader.restoreValue(NDKLocationKey).toString());
        m_antLocation = FileName::fromString(reader.restoreValue(AntLocationKey).toString());
        m_openJDKLocation = FileName::fromString(reader.restoreValue(OpenJDKLocationKey).toString());
        m_keystoreLocation = FileName::fromString(reader.restoreValue(KeystoreLocationKey).toString());
        m_toolchainHost = reader.restoreValue(ToolchainHostKey).toString();
Daniel Teske's avatar
Daniel Teske committed
199 200
        QVariant v = reader.restoreValue(AutomaticKitCreationKey);
        if (v.isValid())
Daniel Teske's avatar
Daniel Teske committed
201
            m_automaticKitCreation = v.toBool();
202
        QString extraDirectory = reader.restoreValue(MakeExtraSearchDirectory).toString();
Daniel Teske's avatar
Daniel Teske committed
203
        m_makeExtraSearchDirectories.clear();
204
        if (!extraDirectory.isEmpty())
Daniel Teske's avatar
Daniel Teske committed
205
            m_makeExtraSearchDirectories << extraDirectory;
BogDan Vatra's avatar
BogDan Vatra committed
206 207
        // persistent settings
    }
Daniel Teske's avatar
Daniel Teske committed
208 209
    m_availableSdkPlatformsUpToDate = false;
    m_NdkInformationUpToDate = false;
BogDan Vatra's avatar
BogDan Vatra committed
210 211 212
}

AndroidConfig::AndroidConfig()
Daniel Teske's avatar
Daniel Teske committed
213 214
    : m_availableSdkPlatformsUpToDate(false),
      m_NdkInformationUpToDate(false)
BogDan Vatra's avatar
BogDan Vatra committed
215
{
Daniel Teske's avatar
Daniel Teske committed
216

BogDan Vatra's avatar
BogDan Vatra committed
217 218 219 220
}

void AndroidConfig::save(QSettings &settings) const
{
221
    QFileInfo fileInfo(sdkSettingsFileName());
BogDan Vatra's avatar
BogDan Vatra committed
222 223 224 225
    if (fileInfo.exists())
        settings.setValue(changeTimeStamp, fileInfo.lastModified().toMSecsSinceEpoch() / 1000);

    // user settings
Daniel Teske's avatar
Daniel Teske committed
226 227 228 229 230 231 232 233
    settings.setValue(SDKLocationKey, m_sdkLocation.toString());
    settings.setValue(NDKLocationKey, m_ndkLocation.toString());
    settings.setValue(AntLocationKey, m_antLocation.toString());
    settings.setValue(OpenJDKLocationKey, m_openJDKLocation.toString());
    settings.setValue(KeystoreLocationKey, m_keystoreLocation.toString());
    settings.setValue(PartitionSizeKey, m_partitionSize);
    settings.setValue(AutomaticKitCreationKey, m_automaticKitCreation);
    settings.setValue(ToolchainHostKey, m_toolchainHost);
234
    settings.setValue(MakeExtraSearchDirectory,
Daniel Teske's avatar
Daniel Teske committed
235 236
                      m_makeExtraSearchDirectories.isEmpty() ? QString()
                                                             : m_makeExtraSearchDirectories.at(0));
BogDan Vatra's avatar
BogDan Vatra committed
237 238
}

Daniel Teske's avatar
Daniel Teske committed
239
void AndroidConfig::updateNdkInformation() const
BogDan Vatra's avatar
BogDan Vatra committed
240
{
Daniel Teske's avatar
Daniel Teske committed
241 242
    if (m_NdkInformationUpToDate)
        return;
243
    m_availableNdkPlatforms.clear();
Daniel Teske's avatar
Daniel Teske committed
244
    FileName path = ndkLocation();
BogDan Vatra's avatar
BogDan Vatra committed
245
    QDirIterator it(path.appendPath(QLatin1String("platforms")).toString(), QStringList() << QLatin1String("android-*"), QDir::Dirs);
BogDan Vatra's avatar
BogDan Vatra committed
246 247
    while (it.hasNext()) {
        const QString &fileName = it.next();
248
        m_availableNdkPlatforms.push_back(fileName.mid(fileName.lastIndexOf(QLatin1Char('-')) + 1).toInt());
BogDan Vatra's avatar
BogDan Vatra committed
249
    }
250
    qSort(m_availableNdkPlatforms.begin(), m_availableNdkPlatforms.end(), qGreater<int>());
Daniel Teske's avatar
Daniel Teske committed
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266

    // 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;
    }

Daniel Teske's avatar
Daniel Teske committed
267
    path = ndkLocation();
Daniel Teske's avatar
Daniel Teske committed
268 269 270 271 272 273 274
    QDirIterator jt(path.appendPath(QLatin1String("prebuilt")).toString(), hostPatterns, QDir::Dirs);
    if (jt.hasNext()) {
        jt.next();
        m_toolchainHost = jt.fileName();
    }

    m_NdkInformationUpToDate = true;
BogDan Vatra's avatar
BogDan Vatra committed
275 276
}

277 278 279 280 281 282 283 284 285
bool AndroidConfig::sortSdkPlatformByApiLevel(const SdkPlatform &a, const SdkPlatform &b)
{
    if (a.apiLevel != b.apiLevel)
        return a.apiLevel > b.apiLevel;
    if (a.name != b.name)
        return a.name < b.name;
    return false;
}

Daniel Teske's avatar
Daniel Teske committed
286
void AndroidConfig::updateAvailableSdkPlatforms() const
BogDan Vatra's avatar
BogDan Vatra committed
287
{
Daniel Teske's avatar
Daniel Teske committed
288 289
    if (m_availableSdkPlatformsUpToDate)
        return;
290 291
    m_availableSdkPlatforms.clear();

BogDan Vatra's avatar
BogDan Vatra committed
292
    QProcess proc;
293
    proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
294
    proc.start(androidToolPath().toString(), QStringList() << QLatin1String("list") << QLatin1String("target")); // list avaialbe AVDs
295
    if (!proc.waitForFinished(5000)) {
BogDan Vatra's avatar
BogDan Vatra committed
296
        proc.terminate();
297
        return;
BogDan Vatra's avatar
BogDan Vatra committed
298
    }
299 300

    SdkPlatform platform;
301
    while (proc.canReadLine()) {
302
        const QString line = QString::fromLocal8Bit(proc.readLine().trimmed());
303 304 305 306 307 308 309 310
        if (line.startsWith(QLatin1String("id:")) && line.contains(QLatin1String("android-"))) {
            int index = line.indexOf(QLatin1String("\"android-"));
            if (index == -1)
                continue;
            QString androidTarget = line.mid(index + 1, line.length() - index - 2);
            platform.apiLevel = androidTarget.mid(androidTarget.lastIndexOf(QLatin1Char('-')) + 1).toInt();
        } else if (line.startsWith(QLatin1String("Name:"))) {
            platform.name = line.mid(6);
311 312
        } else if (line.startsWith(QLatin1String("Tag/ABIs :"))) {
            platform.abis = cleanAndroidABIs(line.mid(10).trimmed().split(QLatin1String(", ")));
313
        } else if (line.startsWith(QLatin1String("ABIs"))) {
314
            platform.abis = cleanAndroidABIs(line.mid(6).trimmed().split(QLatin1String(", ")));
315 316 317 318 319 320 321 322
        } else if (line.startsWith(QLatin1String("---")) || line.startsWith(QLatin1String("==="))) {
            if (platform.apiLevel == -1)
                continue;
            auto it = qLowerBound(m_availableSdkPlatforms.begin(), m_availableSdkPlatforms.end(),
                                  platform, sortSdkPlatformByApiLevel);
            m_availableSdkPlatforms.insert(it, platform);
            platform = SdkPlatform();
        }
BogDan Vatra's avatar
BogDan Vatra committed
323
    }
324 325 326 327 328 329 330

    if (platform.apiLevel != -1) {
        auto it = qLowerBound(m_availableSdkPlatforms.begin(), m_availableSdkPlatforms.end(),
                              platform, sortSdkPlatformByApiLevel);
        m_availableSdkPlatforms.insert(it, platform);
    }

Daniel Teske's avatar
Daniel Teske committed
331
    m_availableSdkPlatformsUpToDate = true;
332 333
}

334 335 336 337 338 339 340 341 342
QStringList AndroidConfig::apiLevelNamesFor(const QList<SdkPlatform> &platforms)
{
    QStringList results;
    foreach (const SdkPlatform &platform, platforms)
        results << QLatin1String("android-") + QString::number(platform.apiLevel);
    return results;
}

QList<SdkPlatform> AndroidConfig::sdkTargets(int minApiLevel) const
343
{
Daniel Teske's avatar
Daniel Teske committed
344
    updateAvailableSdkPlatforms();
345
    QList<SdkPlatform> result;
346
    for (int i = 0; i < m_availableSdkPlatforms.size(); ++i) {
347 348
        if (m_availableSdkPlatforms.at(i).apiLevel >= minApiLevel)
            result << m_availableSdkPlatforms.at(i);
349 350 351 352
        else
            break;
    }
    return result;
BogDan Vatra's avatar
BogDan Vatra committed
353 354
}

Daniel Teske's avatar
Daniel Teske committed
355
FileName AndroidConfig::adbToolPath() const
BogDan Vatra's avatar
BogDan Vatra committed
356
{
Daniel Teske's avatar
Daniel Teske committed
357
    Utils::FileName path = m_sdkLocation;
358
    return path.appendPath(QLatin1String("platform-tools/adb" QTC_HOST_EXE_SUFFIX));
BogDan Vatra's avatar
BogDan Vatra committed
359 360
}

Daniel Teske's avatar
Daniel Teske committed
361
Utils::Environment AndroidConfig::androidToolEnvironment() const
362 363
{
    Utils::Environment env = Utils::Environment::systemEnvironment();
Daniel Teske's avatar
Daniel Teske committed
364 365
    if (!m_openJDKLocation.isEmpty())
        env.set(QLatin1String("JAVA_HOME"), m_openJDKLocation.toUserOutput());
366 367 368
    return env;
}

Daniel Teske's avatar
Daniel Teske committed
369
FileName AndroidConfig::androidToolPath() const
BogDan Vatra's avatar
BogDan Vatra committed
370
{
371 372 373
    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.
Daniel Teske's avatar
Daniel Teske committed
374
        FileName path = m_sdkLocation;
375
        path.appendPath(QLatin1String("tools/android" QTC_HOST_EXE_SUFFIX));
376 377
        if (path.toFileInfo().exists())
            return path;
Daniel Teske's avatar
Daniel Teske committed
378
        path = m_sdkLocation;
379
        return path.appendPath(QLatin1String("tools/android" ANDROID_BAT_SUFFIX));
380
    } else {
Daniel Teske's avatar
Daniel Teske committed
381
        FileName path = m_sdkLocation;
382 383
        return path.appendPath(QLatin1String("tools/android"));
    }
BogDan Vatra's avatar
BogDan Vatra committed
384 385
}

Daniel Teske's avatar
Daniel Teske committed
386
FileName AndroidConfig::antToolPath() const
BogDan Vatra's avatar
BogDan Vatra committed
387
{
Daniel Teske's avatar
Daniel Teske committed
388 389
    if (!m_antLocation.isEmpty())
        return m_antLocation;
BogDan Vatra's avatar
BogDan Vatra committed
390
    else
391
        return FileName::fromLatin1("ant");
BogDan Vatra's avatar
BogDan Vatra committed
392 393
}

Daniel Teske's avatar
Daniel Teske committed
394
FileName AndroidConfig::emulatorToolPath() const
BogDan Vatra's avatar
BogDan Vatra committed
395
{
Daniel Teske's avatar
Daniel Teske committed
396
    FileName path = m_sdkLocation;
397
    return path.appendPath(QLatin1String("tools/emulator" QTC_HOST_EXE_SUFFIX));
BogDan Vatra's avatar
BogDan Vatra committed
398 399
}

Daniel Teske's avatar
Daniel Teske committed
400
FileName AndroidConfig::toolPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
BogDan Vatra's avatar
BogDan Vatra committed
401
{
Daniel Teske's avatar
Daniel Teske committed
402
    FileName path = m_ndkLocation;
Tobias Hunger's avatar
Tobias Hunger committed
403
    return path.appendPath(QString::fromLatin1("toolchains/%1-%2/prebuilt/%3/bin/%4")
BogDan Vatra's avatar
BogDan Vatra committed
404
            .arg(toolchainPrefix(architecture))
405
            .arg(ndkToolChainVersion)
Daniel Teske's avatar
Daniel Teske committed
406
            .arg(toolchainHost())
Tobias Hunger's avatar
Tobias Hunger committed
407
            .arg(toolsPrefix(architecture)));
BogDan Vatra's avatar
BogDan Vatra committed
408 409
}

Daniel Teske's avatar
Daniel Teske committed
410
FileName AndroidConfig::stripPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
BogDan Vatra's avatar
BogDan Vatra committed
411
{
412
    return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-strip" QTC_HOST_EXE_SUFFIX));
BogDan Vatra's avatar
BogDan Vatra committed
413 414
}

Daniel Teske's avatar
Daniel Teske committed
415
FileName AndroidConfig::readelfPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
BogDan Vatra's avatar
BogDan Vatra committed
416
{
417
    return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-readelf" QTC_HOST_EXE_SUFFIX));
BogDan Vatra's avatar
BogDan Vatra committed
418 419
}

Daniel Teske's avatar
Daniel Teske committed
420
FileName AndroidConfig::gccPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
421
{
422
    return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-gcc" QTC_HOST_EXE_SUFFIX));
423 424
}

Daniel Teske's avatar
Daniel Teske committed
425
FileName AndroidConfig::gdbPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
BogDan Vatra's avatar
BogDan Vatra committed
426
{
427
    return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-gdb" QTC_HOST_EXE_SUFFIX));
BogDan Vatra's avatar
BogDan Vatra committed
428 429
}

Daniel Teske's avatar
Daniel Teske committed
430
FileName AndroidConfig::openJDKBinPath() const
BogDan Vatra's avatar
BogDan Vatra committed
431
{
Daniel Teske's avatar
Daniel Teske committed
432
    FileName path = m_openJDKLocation;
Tobias Hunger's avatar
Tobias Hunger committed
433 434 435
    if (!path.isEmpty())
        return path.appendPath(QLatin1String("bin"));
    return path;
BogDan Vatra's avatar
BogDan Vatra committed
436 437
}

Daniel Teske's avatar
Daniel Teske committed
438
FileName AndroidConfig::keytoolPath() const
BogDan Vatra's avatar
BogDan Vatra committed
439
{
Tobias Hunger's avatar
Tobias Hunger committed
440
    return openJDKBinPath().appendPath(keytoolName);
BogDan Vatra's avatar
BogDan Vatra committed
441 442
}

Daniel Teske's avatar
Daniel Teske committed
443
FileName AndroidConfig::jarsignerPath() const
BogDan Vatra's avatar
BogDan Vatra committed
444
{
Tobias Hunger's avatar
Tobias Hunger committed
445
    return openJDKBinPath().appendPath(jarsignerName);
BogDan Vatra's avatar
BogDan Vatra committed
446 447
}

Daniel Teske's avatar
Daniel Teske committed
448
FileName AndroidConfig::zipalignPath() const
449
{
Daniel Teske's avatar
Daniel Teske committed
450
    FileName path = m_sdkLocation;
451
    return path.appendPath(QLatin1String("tools/zipalign" QTC_HOST_EXE_SUFFIX));
452 453
}

Daniel Teske's avatar
Daniel Teske committed
454
QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(QString *error) const
BogDan Vatra's avatar
BogDan Vatra committed
455
{
456
    QVector<AndroidDeviceInfo> devices;
BogDan Vatra's avatar
BogDan Vatra committed
457
    QProcess adbProc;
Tobias Hunger's avatar
Tobias Hunger committed
458
    adbProc.start(adbToolPath().toString(), QStringList() << QLatin1String("devices"));
459
    if (!adbProc.waitForFinished(5000)) {
460
        adbProc.kill();
461
        if (error)
Daniel Teske's avatar
Daniel Teske committed
462 463 464
            *error = QApplication::translate("AndroidConfiguration",
                                             "Could not run: %1")
                .arg(adbToolPath().toString() + QLatin1String(" devices"));
BogDan Vatra's avatar
BogDan Vatra committed
465 466 467
        return devices;
    }
    QList<QByteArray> adbDevs = adbProc.readAll().trimmed().split('\n');
BogDan Vatra's avatar
BogDan Vatra committed
468 469 470 471 472 473
    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
474 475 476

    // workaround for '????????????' serial numbers:
    // can use "adb -d" when only one usb device attached
BogDan Vatra's avatar
BogDan Vatra committed
477
    foreach (const QByteArray &device, adbDevs) {
478 479
        const QString serialNo = QString::fromLatin1(device.left(device.indexOf('\t')).trimmed());
        const QString deviceType = QString::fromLatin1(device.mid(device.indexOf('\t'))).trimmed();
480 481
        if (isBootToQt(serialNo))
            continue;
482
        AndroidDeviceInfo dev;
483
        dev.serialNumber = serialNo;
484
        dev.type = serialNo.startsWith(QLatin1String("emulator")) ? AndroidDeviceInfo::Emulator : AndroidDeviceInfo::Hardware;
BogDan Vatra's avatar
BogDan Vatra committed
485
        dev.sdk = getSDKVersion(dev.serialNumber);
486
        dev.cpuAbi = getAbis(dev.serialNumber);
Daniel Teske's avatar
Daniel Teske committed
487 488 489 490 491 492
        if (deviceType == QLatin1String("unauthorized"))
            dev.state = AndroidDeviceInfo::UnAuthorizedState;
        else if (deviceType == QLatin1String("offline"))
            dev.state = AndroidDeviceInfo::OfflineState;
        else
            dev.state = AndroidDeviceInfo::OkState;
BogDan Vatra's avatar
BogDan Vatra committed
493 494
        devices.push_back(dev);
    }
495

BogDan Vatra's avatar
BogDan Vatra committed
496
    qSort(devices.begin(), devices.end(), androidDevicesLessThan);
497
    if (devices.isEmpty() && error)
Daniel Teske's avatar
Daniel Teske committed
498 499 500
        *error = QApplication::translate("AndroidConfiguration",
                                         "No devices found in output of: %1")
            .arg(adbToolPath().toString() + QLatin1String(" devices"));
BogDan Vatra's avatar
BogDan Vatra committed
501 502 503
    return devices;
}

Daniel Teske's avatar
Daniel Teske committed
504
QString AndroidConfig::createAVD(QWidget *parent, int minApiLevel, QString targetArch) const
BogDan Vatra's avatar
BogDan Vatra committed
505
{
506 507
    AvdDialog d(minApiLevel, targetArch, this, parent);
    if (d.exec() != QDialog::Accepted || !d.isValid())
508
        return QString();
509
    QString error;
510 511
    QString avd = createAVD(d.target(), d.name(), d.abi(), d.sdcardSize(), &error);

512 513 514 515 516 517
    if (!error.isEmpty()) {
        QMessageBox::critical(parent, QApplication::translate("AndroidConfig", "Error Creating AVD"),
                              error);
    }

    return avd;
BogDan Vatra's avatar
BogDan Vatra committed
518 519
}

520
QString AndroidConfig::createAVD(const QString &target, const QString &name, const QString &abi, int sdcardSize, QString *error) const
BogDan Vatra's avatar
BogDan Vatra committed
521 522
{
    QProcess proc;
523
    proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
524
    proc.start(androidToolPath().toString(),
BogDan Vatra's avatar
BogDan Vatra committed
525
               QStringList() << QLatin1String("create") << QLatin1String("avd")
526
               << QLatin1String("-t") << target
BogDan Vatra's avatar
BogDan Vatra committed
527
               << QLatin1String("-n") << name
528
               << QLatin1String("-b") << abi
BogDan Vatra's avatar
BogDan Vatra committed
529 530
               << QLatin1String("-c") << QString::fromLatin1("%1M").arg(sdcardSize));
    if (!proc.waitForStarted())
531
        return QString();
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552

    proc.write(QByteArray("yes\n")); // yes to "Do you wish to create a custom hardware profile"

    QByteArray question;
    while (true) {
        proc.waitForReadyRead(500);
        question += proc.readAllStandardOutput();
        if (question.endsWith(QByteArray("]:"))) {
            // truncate to last line
            int index = question.lastIndexOf(QByteArray("\n"));
            if (index != -1)
                question = question.mid(index);
            if (question.contains("hw.gpu.enabled"))
                proc.write(QByteArray("yes\n"));
            else
                proc.write(QByteArray("\n"));
            question.clear();
        }

        if (proc.state() != QProcess::Running)
            break;
BogDan Vatra's avatar
BogDan Vatra committed
553
    }
554 555 556

    proc.waitForFinished();

557 558 559 560 561
    QString errorOutput = QString::fromLocal8Bit(proc.readAllStandardError());
    // The exit code is always 0, so we need to check stderr
    // For now assume that any output at all indicates a error
    if (!errorOutput.isEmpty()) {
        *error = errorOutput;
562
        return QString();
563 564
    }

565
    return name;
BogDan Vatra's avatar
BogDan Vatra committed
566 567
}

Daniel Teske's avatar
Daniel Teske committed
568
bool AndroidConfig::removeAVD(const QString &name) const
BogDan Vatra's avatar
BogDan Vatra committed
569 570
{
    QProcess proc;
571
    proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
572
    proc.start(androidToolPath().toString(),
BogDan Vatra's avatar
BogDan Vatra committed
573 574
               QStringList() << QLatin1String("delete") << QLatin1String("avd")
               << QLatin1String("-n") << name);
575
    if (!proc.waitForFinished(5000)) {
BogDan Vatra's avatar
BogDan Vatra committed
576 577 578 579 580 581
        proc.terminate();
        return false;
    }
    return !proc.exitCode();
}

Daniel Teske's avatar
Daniel Teske committed
582
QVector<AndroidDeviceInfo> AndroidConfig::androidVirtualDevices() const
BogDan Vatra's avatar
BogDan Vatra committed
583
{
584
    QVector<AndroidDeviceInfo> devices;
BogDan Vatra's avatar
BogDan Vatra committed
585
    QProcess proc;
586
    proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
587
    proc.start(androidToolPath().toString(),
BogDan Vatra's avatar
BogDan Vatra committed
588
               QStringList() << QLatin1String("list") << QLatin1String("avd")); // list available AVDs
589
    if (!proc.waitForFinished(5000)) {
BogDan Vatra's avatar
BogDan Vatra committed
590 591 592 593
        proc.terminate();
        return devices;
    }
    QList<QByteArray> avds = proc.readAll().trimmed().split('\n');
BogDan Vatra's avatar
BogDan Vatra committed
594 595 596 597 598 599 600
    if (avds.empty())
        return devices;

    while (avds.first().startsWith("* daemon"))
        avds.removeFirst(); // remove the daemon logs
    avds.removeFirst(); // remove "List of devices attached" header line

601
    AndroidDeviceInfo dev;
BogDan Vatra's avatar
BogDan Vatra committed
602 603 604 605 606 607 608 609 610 611 612 613 614
    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();
615 616 617
            if (line.contains(QLatin1String("Tag/ABI:")))
                dev.cpuAbi = QStringList() << line.mid(line.lastIndexOf(QLatin1Char('/')) +1);
            else if (line.contains(QLatin1String("ABI:")))
618
                dev.cpuAbi = QStringList() << line.mid(line.lastIndexOf(QLatin1Char(' '))).trimmed();
BogDan Vatra's avatar
BogDan Vatra committed
619
        }
620 621 622
        // armeabi-v7a devices can also run armeabi code
        if (dev.cpuAbi == QStringList(QLatin1String("armeabi-v7a")))
            dev.cpuAbi << QLatin1String("armeabi");
Daniel Teske's avatar
Daniel Teske committed
623
        dev.state = AndroidDeviceInfo::OkState;
624
        dev.type = AndroidDeviceInfo::Emulator;
BogDan Vatra's avatar
BogDan Vatra committed
625 626 627 628 629 630 631
        devices.push_back(dev);
    }
    qSort(devices.begin(), devices.end(), androidDevicesLessThan);

    return devices;
}

Daniel Teske's avatar
Daniel Teske committed
632
QString AndroidConfig::startAVD(const QString &name, int apiLevel, QString cpuAbi) const
633
{
634
    if (!findAvd(apiLevel, cpuAbi).isEmpty() || startAVDAsync(name))
635 636 637
        return waitForAvd(apiLevel, cpuAbi);
    return QString();
}
BogDan Vatra's avatar
BogDan Vatra committed
638

Daniel Teske's avatar
Daniel Teske committed
639
bool AndroidConfig::startAVDAsync(const QString &avdName) const
640 641
{
    QProcess *avdProcess = new QProcess();
Daniel Teske's avatar
Daniel Teske committed
642
    avdProcess->connect(avdProcess, SIGNAL(finished(int)), avdProcess, SLOT(deleteLater()));
BogDan Vatra's avatar
BogDan Vatra committed
643 644

    // start the emulator
Orgad Shaneh's avatar
Orgad Shaneh committed
645
    avdProcess->start(emulatorToolPath().toString(),
Daniel Teske's avatar
Daniel Teske committed
646
                        QStringList() << QLatin1String("-partition-size") << QString::number(partitionSize())
BogDan Vatra's avatar
BogDan Vatra committed
647
                        << QLatin1String("-avd") << avdName);
Orgad Shaneh's avatar
Orgad Shaneh committed
648 649
    if (!avdProcess->waitForStarted(-1)) {
        delete avdProcess;
650
        return false;
BogDan Vatra's avatar
BogDan Vatra committed
651
    }
652 653 654
    return true;
}

Daniel Teske's avatar
Daniel Teske committed
655
QString AndroidConfig::findAvd(int apiLevel, const QString &cpuAbi) const
656 657 658 659 660 661 662 663 664
{
    QVector<AndroidDeviceInfo> devices = connectedDevices();
    foreach (AndroidDeviceInfo device, devices) {
        if (!device.serialNumber.startsWith(QLatin1String("emulator")))
            continue;
        if (!device.cpuAbi.contains(cpuAbi))
            continue;
        if (device.sdk != apiLevel)
            continue;
665
        return device.serialNumber;
666
    }
667
    return QString();
668 669
}

Daniel Teske's avatar
Daniel Teske committed
670
bool AndroidConfig::isConnected(const QString &serialNumber) const
671
{
Daniel Teske's avatar
Daniel Teske committed
672 673 674 675 676 677 678
    QVector<AndroidDeviceInfo> devices = connectedDevices();
    foreach (AndroidDeviceInfo device, devices) {
        if (device.serialNumber == serialNumber)
            return true;
    }
    return false;
}
679

Daniel Teske's avatar
Daniel Teske committed
680
bool AndroidConfig::waitForBooted(const QString &serialNumber, const QFutureInterface<bool> &fi) const
Daniel Teske's avatar
Daniel Teske committed
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
{
    // found a serial number, now wait until it's done booting...
    for (int i = 0; i < 60; ++i) {
        if (fi.isCanceled())
            return false;
        if (hasFinishedBooting(serialNumber)) {
            return true;
        } else {
            Utils::sleep(2000);
            if (!isConnected(serialNumber)) // device was disconnected
                return false;
        }
    }
    return false;
}

Daniel Teske's avatar
Daniel Teske committed
697
QString AndroidConfig::waitForAvd(int apiLevel, const QString &cpuAbi, const QFutureInterface<bool> &fi) const
Daniel Teske's avatar
Daniel Teske committed
698 699 700
{
    // we cannot use adb -e wait-for-device, since that doesn't work if a emulator is already running
    // 60 rounds of 2s sleeping, two minutes for the avd to start
701
    QString serialNumber;
Daniel Teske's avatar
Daniel Teske committed
702 703
    for (int i = 0; i < 60; ++i) {
        if (fi.isCanceled())
Orgad Shaneh's avatar
Orgad Shaneh committed
704
            return QString();
Daniel Teske's avatar
Daniel Teske committed
705 706 707 708
        serialNumber = findAvd(apiLevel, cpuAbi);
        if (!serialNumber.isEmpty())
            return waitForBooted(serialNumber, fi) ?  serialNumber : QString();
        Utils::sleep(2000);
BogDan Vatra's avatar
BogDan Vatra committed
709 710 711 712
    }
    return QString();
}

Daniel Teske's avatar
Daniel Teske committed
713
bool AndroidConfig::isBootToQt(const QString &device) const
714 715 716 717 718 719 720 721
{
    // workaround for '????????????' serial numbers
    QStringList arguments = AndroidDeviceInfo::adbSelector(device);
    arguments << QLatin1String("shell")
              << QLatin1String("ls -l /system/bin/appcontroller || ls -l /usr/bin/appcontroller && echo Boot2Qt");

    QProcess adbProc;
    adbProc.start(adbToolPath().toString(), arguments);
722
    if (!adbProc.waitForFinished(5000)) {
723
        adbProc.kill();
724
        return false;
725 726 727 728
    }
    return adbProc.readAll().contains("Boot2Qt");
}

Daniel Teske's avatar
Daniel Teske committed
729
int AndroidConfig::getSDKVersion(const QString &device) const
BogDan Vatra's avatar
BogDan Vatra committed
730
{
731 732 733 734
    // workaround for '????????????' serial numbers
    QStringList arguments = AndroidDeviceInfo::adbSelector(device);
    arguments << QLatin1String("shell") << QLatin1String("getprop")
              << QLatin1String("ro.build.version.sdk");
BogDan Vatra's avatar
BogDan Vatra committed
735 736

    QProcess adbProc;
737
    adbProc.start(adbToolPath().toString(), arguments);
738
    if (!adbProc.waitForFinished(5000)) {
739
        adbProc.kill();
BogDan Vatra's avatar
BogDan Vatra committed
740 741 742 743 744
        return -1;
    }
    return adbProc.readAll().trimmed().toInt();
}

745 746 747 748 749
//!
//! \brief AndroidConfigurations::getProductModel
//! \param device serial number
//! \return the produce model of the device or if that cannot be read the serial number
//!
Daniel Teske's avatar
Daniel Teske committed
750
QString AndroidConfig::getProductModel(const QString &device) const
751
{
752 753
    if (m_serialNumberToDeviceName.contains(device))
        return m_serialNumberToDeviceName.value(device);
754 755 756 757 758 759 760
    // workaround for '????????????' serial numbers
    QStringList arguments = AndroidDeviceInfo::adbSelector(device);
    arguments << QLatin1String("shell") << QLatin1String("getprop")
              << QLatin1String("ro.product.model");

    QProcess adbProc;
    adbProc.start(adbToolPath().toString(), arguments);
761
    if (!adbProc.waitForFinished(5000)) {
762 763 764 765 766 767
        adbProc.kill();
        return device;
    }
    QString model = QString::fromLocal8Bit(adbProc.readAll().trimmed());
    if (model.isEmpty())
        return device;
768 769
    if (!device.startsWith(QLatin1String("????")))
        m_serialNumberToDeviceName.insert(device, model);
770 771 772
    return model;
}

Daniel Teske's avatar
Daniel Teske committed
773
bool AndroidConfig::hasFinishedBooting(const QString &device) const
774 775 776 777 778 779 780
{
    QStringList arguments = AndroidDeviceInfo::adbSelector(device);
    arguments << QLatin1String("shell") << QLatin1String("getprop")
              << QLatin1String("init.svc.bootanim");

    QProcess adbProc;
    adbProc.start(adbToolPath().toString(), arguments);
781
    if (!adbProc.waitForFinished(5000)) {
782 783 784 785 786 787 788 789 790
        adbProc.kill();
        return false;
    }
    QString value = QString::fromLocal8Bit(adbProc.readAll().trimmed());
    if (value == QLatin1String("stopped"))
        return true;
    return false;
}

Daniel Teske's avatar
Daniel Teske committed
791
QStringList AndroidConfig::getAbis(const QString &device) const
792 793
{
    QStringList result;
794
    for (int i = 1; i < 6; ++i) {
795 796 797 798 799 800 801 802 803
        QStringList arguments = AndroidDeviceInfo::adbSelector(device);
        arguments << QLatin1String("shell") << QLatin1String("getprop");
        if (i == 1)
            arguments << QLatin1String("ro.product.cpu.abi");
        else
            arguments << QString::fromLatin1("ro.product.cpu.abi%1").arg(i);

        QProcess adbProc;
        adbProc.start(adbToolPath().toString(), arguments);
804
        if (!adbProc.waitForFinished(5000)) {
805 806 807 808 809 810 811 812 813 814 815
            adbProc.kill();
            return result;
        }
        QString abi = QString::fromLocal8Bit(adbProc.readAll().trimmed());
        if (abi.isEmpty())
            break;
        result << abi;
    }
    return result;
}

816
SdkPlatform AndroidConfig::highestAndroidSdk() const
817
{
Daniel Teske's avatar
Daniel Teske committed
818
    updateAvailableSdkPlatforms();
819
    if (m_availableSdkPlatforms.isEmpty())
820 821
        return SdkPlatform();
    return m_availableSdkPlatforms.first();
822 823
}

Daniel Teske's avatar
Daniel Teske committed
824
QString AndroidConfig::bestNdkPlatformMatch(const QString &targetAPI) const
BogDan Vatra's avatar
BogDan Vatra committed
825
{
Daniel Teske's avatar
Daniel Teske committed
826
    updateNdkInformation();
BogDan Vatra's avatar
BogDan Vatra committed
827
    int target = targetAPI.mid(targetAPI.lastIndexOf(QLatin1Char('-')) + 1).toInt();
828
    foreach (int apiLevel, m_availableNdkPlatforms) {
BogDan Vatra's avatar
BogDan Vatra committed
829 830 831 832 833 834
        if (apiLevel <= target)
            return QString::fromLatin1("android-%1").arg(apiLevel);
    }
    return QLatin1String("android-8");
}

Daniel Teske's avatar
Daniel Teske committed
835
FileName AndroidConfig::sdkLocation() const
836
{
Daniel Teske's avatar
Daniel Teske committed
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
    return m_sdkLocation;
}

void AndroidConfig::setSdkLocation(const FileName &sdkLocation)
{
    m_sdkLocation = sdkLocation;
    m_availableSdkPlatformsUpToDate = false;
}

FileName AndroidConfig::ndkLocation() const
{
    return m_ndkLocation;
}

void AndroidConfig::setNdkLocation(const FileName &ndkLocation)
{
    m_ndkLocation = ndkLocation;
    m_NdkInformationUpToDate = false;
}

FileName AndroidConfig::antLocation() const
{
    return m_antLocation;
}

void AndroidConfig::setAntLocation(const FileName &antLocation)
{
    m_antLocation = antLocation;
}

FileName AndroidConfig::openJDKLocation() const
{
    return m_openJDKLocation;
}

void AndroidConfig::setOpenJDKLocation(const FileName &openJDKLocation)
{
    m_openJDKLocation = openJDKLocation;
    m_availableSdkPlatformsUpToDate = false;
}

FileName AndroidConfig::keystoreLocation() const
{
    return m_keystoreLocation;
}

void AndroidConfig::setKeystoreLocation(const FileName &keystoreLocation)
{
    m_keystoreLocation = keystoreLocation;
}

QString AndroidConfig::toolchainHost() const
{
    updateNdkInformation();
    return m_toolchainHost;
}

QStringList AndroidConfig::makeExtraSearchDirectories() const
{
    return m_makeExtraSearchDirectories;
}

unsigned AndroidConfig::partitionSize() const
{
    return m_partitionSize;
}

void AndroidConfig::setPartitionSize(unsigned partitionSize)
{
    m_partitionSize = partitionSize;
}

bool AndroidConfig::automaticKitCreation() const
{
    return m_automaticKitCreation;
}

void AndroidConfig::setAutomaticKitCreation(bool b)
{
    m_automaticKitCreation = b;
}

///////////////////////////////////
// AndroidConfigurations
///////////////////////////////////
void AndroidConfigurations::setConfig(const AndroidConfig &devConfigs)
{
    m_instance->m_config = devConfigs;

    m_instance->save();
    m_instance->updateAndroidDevice();
928 929
    m_instance->updateToolChainList();
    m_instance->updateAutomaticKitList();
Daniel Teske's avatar
Daniel Teske committed
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963