androidconfigurations.cpp 44.9 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"
BogDan Vatra's avatar
BogDan Vatra committed
35
#include "ui_addnewavddialog.h"
36
#include "androidqtversion.h"
37
#include "androiddevicedialog.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 63 64 65 66

#include <QDateTime>
#include <QSettings>
#include <QStringList>
#include <QProcess>
#include <QFileInfo>
#include <QDirIterator>
#include <QMetaObject>

#include <QStringListModel>
#include <QMessageBox>

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

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

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

112
        return dev1.serialNumber < dev2.serialNumber;
BogDan Vatra's avatar
BogDan Vatra committed
113 114 115
    }
}

Daniel Teske's avatar
Daniel Teske committed
116 117 118 119 120
//////////////////////////////////
// AndroidConfig
//////////////////////////////////

Abi::Architecture AndroidConfig::architectureForToolChainPrefix(const QString& toolchainprefix)
121 122 123 124 125
{
    if (toolchainprefix == ArmToolchainPrefix)
        return Abi::ArmArchitecture;
    if (toolchainprefix == X86ToolchainPrefix)
        return Abi::X86Architecture;
BogDan Vatra's avatar
BogDan Vatra committed
126 127
    if (toolchainprefix == MipsToolchainPrefix)
        return Abi::MipsArchitecture;
128 129 130
    return Abi::UnknownArchitecture;
}

Daniel Teske's avatar
Daniel Teske committed
131
QLatin1String AndroidConfig::toolchainPrefix(Abi::Architecture architecture)
BogDan Vatra's avatar
BogDan Vatra committed
132 133
{
    switch (architecture) {
hjk's avatar
hjk committed
134
    case Abi::ArmArchitecture:
BogDan Vatra's avatar
BogDan Vatra committed
135
        return ArmToolchainPrefix;
hjk's avatar
hjk committed
136
    case Abi::X86Architecture:
BogDan Vatra's avatar
BogDan Vatra committed
137
        return X86ToolchainPrefix;
BogDan Vatra's avatar
BogDan Vatra committed
138 139
    case Abi::MipsArchitecture:
        return MipsToolchainPrefix;
BogDan Vatra's avatar
BogDan Vatra committed
140 141 142 143 144
    default:
        return Unknown;
    }
}

Daniel Teske's avatar
Daniel Teske committed
145
QLatin1String AndroidConfig::toolsPrefix(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 ArmToolsPrefix;
hjk's avatar
hjk committed
150
    case Abi::X86Architecture:
BogDan Vatra's avatar
BogDan Vatra committed
151
        return X86ToolsPrefix;
BogDan Vatra's avatar
BogDan Vatra committed
152 153
    case Abi::MipsArchitecture:
        return MipsToolsPrefix;
BogDan Vatra's avatar
BogDan Vatra committed
154 155 156 157 158
    default:
        return Unknown;
    }
}

Daniel Teske's avatar
Daniel Teske committed
159
void AndroidConfig::load(const QSettings &settings)
BogDan Vatra's avatar
BogDan Vatra committed
160 161
{
    // user settings
Daniel Teske's avatar
Daniel Teske committed
162 163 164 165 166 167 168 169
    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();
170
    QString extraDirectory = settings.value(MakeExtraSearchDirectory).toString();
Daniel Teske's avatar
Daniel Teske committed
171
    m_makeExtraSearchDirectories.clear();
172
    if (!extraDirectory.isEmpty())
Daniel Teske's avatar
Daniel Teske committed
173
        m_makeExtraSearchDirectories << extraDirectory;
BogDan Vatra's avatar
BogDan Vatra committed
174 175

    PersistentSettingsReader reader;
176 177
    if (reader.load(FileName::fromString(sdkSettingsFileName()))
            && settings.value(changeTimeStamp).toInt() != QFileInfo(sdkSettingsFileName()).lastModified().toMSecsSinceEpoch() / 1000) {
BogDan Vatra's avatar
BogDan Vatra committed
178
        // persisten settings
Daniel Teske's avatar
Daniel Teske committed
179 180 181 182 183 184
        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
185 186
        QVariant v = reader.restoreValue(AutomaticKitCreationKey);
        if (v.isValid())
Daniel Teske's avatar
Daniel Teske committed
187
            m_automaticKitCreation = v.toBool();
188
        QString extraDirectory = reader.restoreValue(MakeExtraSearchDirectory).toString();
Daniel Teske's avatar
Daniel Teske committed
189
        m_makeExtraSearchDirectories.clear();
190
        if (!extraDirectory.isEmpty())
Daniel Teske's avatar
Daniel Teske committed
191
            m_makeExtraSearchDirectories << extraDirectory;
BogDan Vatra's avatar
BogDan Vatra committed
192 193
        // persistent settings
    }
Daniel Teske's avatar
Daniel Teske committed
194 195
    m_availableSdkPlatformsUpToDate = false;
    m_NdkInformationUpToDate = false;
BogDan Vatra's avatar
BogDan Vatra committed
196 197 198
}

AndroidConfig::AndroidConfig()
Daniel Teske's avatar
Daniel Teske committed
199 200
    : m_availableSdkPlatformsUpToDate(false),
      m_NdkInformationUpToDate(false)
BogDan Vatra's avatar
BogDan Vatra committed
201
{
Daniel Teske's avatar
Daniel Teske committed
202

BogDan Vatra's avatar
BogDan Vatra committed
203 204 205 206
}

void AndroidConfig::save(QSettings &settings) const
{
207
    QFileInfo fileInfo(sdkSettingsFileName());
BogDan Vatra's avatar
BogDan Vatra committed
208 209 210 211
    if (fileInfo.exists())
        settings.setValue(changeTimeStamp, fileInfo.lastModified().toMSecsSinceEpoch() / 1000);

    // user settings
Daniel Teske's avatar
Daniel Teske committed
212 213 214 215 216 217 218 219
    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);
220
    settings.setValue(MakeExtraSearchDirectory,
Daniel Teske's avatar
Daniel Teske committed
221 222
                      m_makeExtraSearchDirectories.isEmpty() ? QString()
                                                             : m_makeExtraSearchDirectories.at(0));
BogDan Vatra's avatar
BogDan Vatra committed
223 224
}

Daniel Teske's avatar
Daniel Teske committed
225
void AndroidConfig::updateNdkInformation() const
BogDan Vatra's avatar
BogDan Vatra committed
226
{
Daniel Teske's avatar
Daniel Teske committed
227 228
    if (m_NdkInformationUpToDate)
        return;
229
    m_availableNdkPlatforms.clear();
Daniel Teske's avatar
Daniel Teske committed
230
    FileName path = ndkLocation();
BogDan Vatra's avatar
BogDan Vatra committed
231
    QDirIterator it(path.appendPath(QLatin1String("platforms")).toString(), QStringList() << QLatin1String("android-*"), QDir::Dirs);
BogDan Vatra's avatar
BogDan Vatra committed
232 233
    while (it.hasNext()) {
        const QString &fileName = it.next();
234
        m_availableNdkPlatforms.push_back(fileName.mid(fileName.lastIndexOf(QLatin1Char('-')) + 1).toInt());
BogDan Vatra's avatar
BogDan Vatra committed
235
    }
236
    qSort(m_availableNdkPlatforms.begin(), m_availableNdkPlatforms.end(), qGreater<int>());
Daniel Teske's avatar
Daniel Teske committed
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252

    // 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
253
    path = ndkLocation();
Daniel Teske's avatar
Daniel Teske committed
254 255 256 257 258 259 260
    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
261 262
}

Daniel Teske's avatar
Daniel Teske committed
263
void AndroidConfig::updateAvailableSdkPlatforms() const
BogDan Vatra's avatar
BogDan Vatra committed
264
{
Daniel Teske's avatar
Daniel Teske committed
265 266
    if (m_availableSdkPlatformsUpToDate)
        return;
267 268
    m_availableSdkPlatforms.clear();

BogDan Vatra's avatar
BogDan Vatra committed
269
    QProcess proc;
270
    proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
271
    proc.start(androidToolPath().toString(), QStringList() << QLatin1String("list") << QLatin1String("target")); // list avaialbe AVDs
272
    if (!proc.waitForFinished(5000)) {
BogDan Vatra's avatar
BogDan Vatra committed
273
        proc.terminate();
274
        return;
BogDan Vatra's avatar
BogDan Vatra committed
275
    }
276
    while (proc.canReadLine()) {
277
        const QString line = QString::fromLocal8Bit(proc.readLine().trimmed());
BogDan Vatra's avatar
BogDan Vatra committed
278 279 280
        int index = line.indexOf(QLatin1String("\"android-"));
        if (index == -1)
            continue;
281 282 283 284
        QString androidTarget = line.mid(index + 1, line.length() - index - 2);
        int apiLevel = androidTarget.mid(androidTarget.lastIndexOf(QLatin1Char('-')) + 1).toInt();
        QVector<int>::iterator it = qLowerBound(m_availableSdkPlatforms.begin(), m_availableSdkPlatforms.end(), apiLevel, qGreater<int>());
        m_availableSdkPlatforms.insert(it, apiLevel);
BogDan Vatra's avatar
BogDan Vatra committed
285
    }
Daniel Teske's avatar
Daniel Teske committed
286
    m_availableSdkPlatformsUpToDate = true;
287 288
}

Daniel Teske's avatar
Daniel Teske committed
289
QStringList AndroidConfig::sdkTargets(int minApiLevel) const
290
{
Daniel Teske's avatar
Daniel Teske committed
291
    updateAvailableSdkPlatforms();
292 293 294 295 296 297 298 299
    QStringList result;
    for (int i = 0; i < m_availableSdkPlatforms.size(); ++i) {
        if (m_availableSdkPlatforms.at(i) >= minApiLevel)
            result << QLatin1String("android-") + QString::number(m_availableSdkPlatforms.at(i));
        else
            break;
    }
    return result;
BogDan Vatra's avatar
BogDan Vatra committed
300 301
}

Daniel Teske's avatar
Daniel Teske committed
302
FileName AndroidConfig::adbToolPath() const
BogDan Vatra's avatar
BogDan Vatra committed
303
{
Daniel Teske's avatar
Daniel Teske committed
304
    Utils::FileName path = m_sdkLocation;
305
    return path.appendPath(QLatin1String("platform-tools/adb" QTC_HOST_EXE_SUFFIX));
BogDan Vatra's avatar
BogDan Vatra committed
306 307
}

Daniel Teske's avatar
Daniel Teske committed
308
Utils::Environment AndroidConfig::androidToolEnvironment() const
309 310
{
    Utils::Environment env = Utils::Environment::systemEnvironment();
Daniel Teske's avatar
Daniel Teske committed
311 312
    if (!m_openJDKLocation.isEmpty())
        env.set(QLatin1String("JAVA_HOME"), m_openJDKLocation.toUserOutput());
313 314 315
    return env;
}

Daniel Teske's avatar
Daniel Teske committed
316
FileName AndroidConfig::androidToolPath() const
BogDan Vatra's avatar
BogDan Vatra committed
317
{
318 319 320
    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
321
        FileName path = m_sdkLocation;
322
        path.appendPath(QLatin1String("tools/android" QTC_HOST_EXE_SUFFIX));
323 324
        if (path.toFileInfo().exists())
            return path;
Daniel Teske's avatar
Daniel Teske committed
325
        path = m_sdkLocation;
326
        return path.appendPath(QLatin1String("tools/android" ANDROID_BAT_SUFFIX));
327
    } else {
Daniel Teske's avatar
Daniel Teske committed
328
        FileName path = m_sdkLocation;
329 330
        return path.appendPath(QLatin1String("tools/android"));
    }
BogDan Vatra's avatar
BogDan Vatra committed
331 332
}

Daniel Teske's avatar
Daniel Teske committed
333
FileName AndroidConfig::antToolPath() const
BogDan Vatra's avatar
BogDan Vatra committed
334
{
Daniel Teske's avatar
Daniel Teske committed
335 336
    if (!m_antLocation.isEmpty())
        return m_antLocation;
BogDan Vatra's avatar
BogDan Vatra committed
337
    else
338
        return FileName::fromLatin1("ant");
BogDan Vatra's avatar
BogDan Vatra committed
339 340
}

Daniel Teske's avatar
Daniel Teske committed
341
FileName AndroidConfig::emulatorToolPath() const
BogDan Vatra's avatar
BogDan Vatra committed
342
{
Daniel Teske's avatar
Daniel Teske committed
343
    FileName path = m_sdkLocation;
344
    return path.appendPath(QLatin1String("tools/emulator" QTC_HOST_EXE_SUFFIX));
BogDan Vatra's avatar
BogDan Vatra committed
345 346
}

Daniel Teske's avatar
Daniel Teske committed
347
FileName AndroidConfig::toolPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
BogDan Vatra's avatar
BogDan Vatra committed
348
{
Daniel Teske's avatar
Daniel Teske committed
349
    FileName path = m_ndkLocation;
Tobias Hunger's avatar
Tobias Hunger committed
350
    return path.appendPath(QString::fromLatin1("toolchains/%1-%2/prebuilt/%3/bin/%4")
BogDan Vatra's avatar
BogDan Vatra committed
351
            .arg(toolchainPrefix(architecture))
352
            .arg(ndkToolChainVersion)
Daniel Teske's avatar
Daniel Teske committed
353
            .arg(toolchainHost())
Tobias Hunger's avatar
Tobias Hunger committed
354
            .arg(toolsPrefix(architecture)));
BogDan Vatra's avatar
BogDan Vatra committed
355 356
}

Daniel Teske's avatar
Daniel Teske committed
357
FileName AndroidConfig::stripPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
BogDan Vatra's avatar
BogDan Vatra committed
358
{
359
    return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-strip" QTC_HOST_EXE_SUFFIX));
BogDan Vatra's avatar
BogDan Vatra committed
360 361
}

Daniel Teske's avatar
Daniel Teske committed
362
FileName AndroidConfig::readelfPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
BogDan Vatra's avatar
BogDan Vatra committed
363
{
364
    return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-readelf" QTC_HOST_EXE_SUFFIX));
BogDan Vatra's avatar
BogDan Vatra committed
365 366
}

Daniel Teske's avatar
Daniel Teske committed
367
FileName AndroidConfig::gccPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
368
{
369
    return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-gcc" QTC_HOST_EXE_SUFFIX));
370 371
}

Daniel Teske's avatar
Daniel Teske committed
372
FileName AndroidConfig::gdbPath(Abi::Architecture architecture, const QString &ndkToolChainVersion) const
BogDan Vatra's avatar
BogDan Vatra committed
373
{
374
    return toolPath(architecture, ndkToolChainVersion).appendString(QLatin1String("-gdb" QTC_HOST_EXE_SUFFIX));
BogDan Vatra's avatar
BogDan Vatra committed
375 376
}

Daniel Teske's avatar
Daniel Teske committed
377
FileName AndroidConfig::openJDKBinPath() const
BogDan Vatra's avatar
BogDan Vatra committed
378
{
Daniel Teske's avatar
Daniel Teske committed
379
    FileName path = m_openJDKLocation;
Tobias Hunger's avatar
Tobias Hunger committed
380 381 382
    if (!path.isEmpty())
        return path.appendPath(QLatin1String("bin"));
    return path;
BogDan Vatra's avatar
BogDan Vatra committed
383 384
}

Daniel Teske's avatar
Daniel Teske committed
385
FileName AndroidConfig::keytoolPath() const
BogDan Vatra's avatar
BogDan Vatra committed
386
{
Tobias Hunger's avatar
Tobias Hunger committed
387
    return openJDKBinPath().appendPath(keytoolName);
BogDan Vatra's avatar
BogDan Vatra committed
388 389
}

Daniel Teske's avatar
Daniel Teske committed
390
FileName AndroidConfig::jarsignerPath() const
BogDan Vatra's avatar
BogDan Vatra committed
391
{
Tobias Hunger's avatar
Tobias Hunger committed
392
    return openJDKBinPath().appendPath(jarsignerName);
BogDan Vatra's avatar
BogDan Vatra committed
393 394
}

Daniel Teske's avatar
Daniel Teske committed
395
FileName AndroidConfig::zipalignPath() const
396
{
Daniel Teske's avatar
Daniel Teske committed
397
    FileName path = m_sdkLocation;
398
    return path.appendPath(QLatin1String("tools/zipalign" QTC_HOST_EXE_SUFFIX));
399 400
}

Daniel Teske's avatar
Daniel Teske committed
401
QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(QString *error) const
BogDan Vatra's avatar
BogDan Vatra committed
402
{
403
    QVector<AndroidDeviceInfo> devices;
BogDan Vatra's avatar
BogDan Vatra committed
404
    QProcess adbProc;
Tobias Hunger's avatar
Tobias Hunger committed
405
    adbProc.start(adbToolPath().toString(), QStringList() << QLatin1String("devices"));
406
    if (!adbProc.waitForFinished(5000)) {
407
        adbProc.kill();
408
        if (error)
Daniel Teske's avatar
Daniel Teske committed
409 410 411
            *error = QApplication::translate("AndroidConfiguration",
                                             "Could not run: %1")
                .arg(adbToolPath().toString() + QLatin1String(" devices"));
BogDan Vatra's avatar
BogDan Vatra committed
412 413 414
        return devices;
    }
    QList<QByteArray> adbDevs = adbProc.readAll().trimmed().split('\n');
BogDan Vatra's avatar
BogDan Vatra committed
415 416 417 418 419 420
    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
421 422 423

    // workaround for '????????????' serial numbers:
    // can use "adb -d" when only one usb device attached
BogDan Vatra's avatar
BogDan Vatra committed
424
    foreach (const QByteArray &device, adbDevs) {
425 426
        const QString serialNo = QString::fromLatin1(device.left(device.indexOf('\t')).trimmed());
        const QString deviceType = QString::fromLatin1(device.mid(device.indexOf('\t'))).trimmed();
427 428
        if (isBootToQt(serialNo))
            continue;
429
        AndroidDeviceInfo dev;
430
        dev.serialNumber = serialNo;
431
        dev.type = serialNo.startsWith(QLatin1String("emulator")) ? AndroidDeviceInfo::Emulator : AndroidDeviceInfo::Hardware;
BogDan Vatra's avatar
BogDan Vatra committed
432
        dev.sdk = getSDKVersion(dev.serialNumber);
433
        dev.cpuAbi = getAbis(dev.serialNumber);
Daniel Teske's avatar
Daniel Teske committed
434 435 436 437 438 439
        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
440 441
        devices.push_back(dev);
    }
442

BogDan Vatra's avatar
BogDan Vatra committed
443
    qSort(devices.begin(), devices.end(), androidDevicesLessThan);
444
    if (devices.isEmpty() && error)
Daniel Teske's avatar
Daniel Teske committed
445 446 447
        *error = QApplication::translate("AndroidConfiguration",
                                         "No devices found in output of: %1")
            .arg(adbToolPath().toString() + QLatin1String(" devices"));
BogDan Vatra's avatar
BogDan Vatra committed
448 449 450
    return devices;
}

Daniel Teske's avatar
Daniel Teske committed
451
QString AndroidConfig::createAVD(QWidget *parent, int minApiLevel, QString targetArch) const
BogDan Vatra's avatar
BogDan Vatra committed
452
{
453
    QDialog d(parent);
BogDan Vatra's avatar
BogDan Vatra committed
454 455
    Ui::AddNewAVDDialog avdDialog;
    avdDialog.setupUi(&d);
456 457
    // NOTE: adb list targets does actually include information on which abis are supported per apilevel
    // we aren't using that information here
458
    avdDialog.targetComboBox->addItems(sdkTargets(minApiLevel));
459 460 461 462 463 464 465 466 467 468

    if (targetArch.isEmpty())
        avdDialog.abiComboBox->addItems(QStringList()
                                        << QLatin1String("armeabi-v7a")
                                        << QLatin1String("armeabi")
                                        << QLatin1String("x86")
                                        << QLatin1String("mips"));
    else
        avdDialog.abiComboBox->addItems(QStringList(targetArch));

469
    if (!avdDialog.targetComboBox->count()) {
470
        QMessageBox::critical(parent, QApplication::translate("AndroidConfig", "Error Creating AVD"),
Daniel Teske's avatar
Daniel Teske committed
471 472
                              QApplication::translate("AndroidConfig", "Cannot create a new AVD. No sufficiently recent Android SDK available.\n"
                                                      "Please install an SDK of at least API version %1.").
Friedemann Kleint's avatar
Friedemann Kleint committed
473
                              arg(minApiLevel));
474
        return QString();
BogDan Vatra's avatar
BogDan Vatra committed
475 476 477 478 479 480
    }

    QRegExp rx(QLatin1String("\\S+"));
    QRegExpValidator v(rx, 0);
    avdDialog.nameLineEdit->setValidator(&v);
    if (d.exec() != QDialog::Accepted)
481
        return QString();
Daniel Teske's avatar
Daniel Teske committed
482 483
    return createAVD(avdDialog.targetComboBox->currentText(), avdDialog.nameLineEdit->text(),
                     avdDialog.abiComboBox->currentText(), avdDialog.sizeSpinBox->value());
BogDan Vatra's avatar
BogDan Vatra committed
484 485
}

Daniel Teske's avatar
Daniel Teske committed
486
QString AndroidConfig::createAVD(const QString &target, const QString &name, const QString &abi, int sdcardSize) const
BogDan Vatra's avatar
BogDan Vatra committed
487 488
{
    QProcess proc;
489
    proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
490
    proc.start(androidToolPath().toString(),
BogDan Vatra's avatar
BogDan Vatra committed
491
               QStringList() << QLatin1String("create") << QLatin1String("avd")
492
               << QLatin1String("-t") << target
BogDan Vatra's avatar
BogDan Vatra committed
493
               << QLatin1String("-n") << name
494
               << QLatin1String("-b") << abi
BogDan Vatra's avatar
BogDan Vatra committed
495 496
               << QLatin1String("-c") << QString::fromLatin1("%1M").arg(sdcardSize));
    if (!proc.waitForStarted())
497
        return QString();
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518

    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
519
    }
520

521 522
    Core::MessageManager::write(QString::fromLocal8Bit(question), Core::MessageManager::Flash);

523 524
    proc.waitForFinished();

525 526 527
    if (proc.exitCode()) // error!
        return QString();
    return name;
BogDan Vatra's avatar
BogDan Vatra committed
528 529
}

Daniel Teske's avatar
Daniel Teske committed
530
bool AndroidConfig::removeAVD(const QString &name) const
BogDan Vatra's avatar
BogDan Vatra committed
531 532
{
    QProcess proc;
533
    proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
534
    proc.start(androidToolPath().toString(),
BogDan Vatra's avatar
BogDan Vatra committed
535 536
               QStringList() << QLatin1String("delete") << QLatin1String("avd")
               << QLatin1String("-n") << name);
537
    if (!proc.waitForFinished(5000)) {
BogDan Vatra's avatar
BogDan Vatra committed
538 539 540 541 542 543
        proc.terminate();
        return false;
    }
    return !proc.exitCode();
}

Daniel Teske's avatar
Daniel Teske committed
544
QVector<AndroidDeviceInfo> AndroidConfig::androidVirtualDevices() const
BogDan Vatra's avatar
BogDan Vatra committed
545
{
546
    QVector<AndroidDeviceInfo> devices;
BogDan Vatra's avatar
BogDan Vatra committed
547
    QProcess proc;
548
    proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
549
    proc.start(androidToolPath().toString(),
BogDan Vatra's avatar
BogDan Vatra committed
550
               QStringList() << QLatin1String("list") << QLatin1String("avd")); // list available AVDs
551
    if (!proc.waitForFinished(5000)) {
BogDan Vatra's avatar
BogDan Vatra committed
552 553 554 555
        proc.terminate();
        return devices;
    }
    QList<QByteArray> avds = proc.readAll().trimmed().split('\n');
BogDan Vatra's avatar
BogDan Vatra committed
556 557 558 559 560 561 562
    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

563
    AndroidDeviceInfo dev;
BogDan Vatra's avatar
BogDan Vatra committed
564 565 566 567 568 569 570 571 572 573 574 575 576
    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();
577 578 579
            if (line.contains(QLatin1String("Tag/ABI:")))
                dev.cpuAbi = QStringList() << line.mid(line.lastIndexOf(QLatin1Char('/')) +1);
            else if (line.contains(QLatin1String("ABI:")))
580
                dev.cpuAbi = QStringList() << line.mid(line.lastIndexOf(QLatin1Char(' '))).trimmed();
BogDan Vatra's avatar
BogDan Vatra committed
581
        }
582 583 584
        // 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
585
        dev.state = AndroidDeviceInfo::OkState;
586
        dev.type = AndroidDeviceInfo::Emulator;
BogDan Vatra's avatar
BogDan Vatra committed
587 588 589 590 591 592 593
        devices.push_back(dev);
    }
    qSort(devices.begin(), devices.end(), androidDevicesLessThan);

    return devices;
}

Daniel Teske's avatar
Daniel Teske committed
594
QString AndroidConfig::startAVD(const QString &name, int apiLevel, QString cpuAbi) const
595
{
596
    if (!findAvd(apiLevel, cpuAbi).isEmpty() || startAVDAsync(name))
597 598 599
        return waitForAvd(apiLevel, cpuAbi);
    return QString();
}
BogDan Vatra's avatar
BogDan Vatra committed
600

Daniel Teske's avatar
Daniel Teske committed
601
bool AndroidConfig::startAVDAsync(const QString &avdName) const
602 603
{
    QProcess *avdProcess = new QProcess();
Daniel Teske's avatar
Daniel Teske committed
604
    avdProcess->connect(avdProcess, SIGNAL(finished(int)), avdProcess, SLOT(deleteLater()));
BogDan Vatra's avatar
BogDan Vatra committed
605 606

    // start the emulator
Orgad Shaneh's avatar
Orgad Shaneh committed
607
    avdProcess->start(emulatorToolPath().toString(),
Daniel Teske's avatar
Daniel Teske committed
608
                        QStringList() << QLatin1String("-partition-size") << QString::number(partitionSize())
BogDan Vatra's avatar
BogDan Vatra committed
609
                        << QLatin1String("-avd") << avdName);
Orgad Shaneh's avatar
Orgad Shaneh committed
610 611
    if (!avdProcess->waitForStarted(-1)) {
        delete avdProcess;
612
        return false;
BogDan Vatra's avatar
BogDan Vatra committed
613
    }
614 615 616
    return true;
}

Daniel Teske's avatar
Daniel Teske committed
617
QString AndroidConfig::findAvd(int apiLevel, const QString &cpuAbi) const
618 619 620 621 622 623 624 625 626
{
    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;
627
        return device.serialNumber;
628
    }
629
    return QString();
630 631
}

Daniel Teske's avatar
Daniel Teske committed
632
bool AndroidConfig::isConnected(const QString &serialNumber) const
633
{
Daniel Teske's avatar
Daniel Teske committed
634 635 636 637 638 639 640
    QVector<AndroidDeviceInfo> devices = connectedDevices();
    foreach (AndroidDeviceInfo device, devices) {
        if (device.serialNumber == serialNumber)
            return true;
    }
    return false;
}
641

Daniel Teske's avatar
Daniel Teske committed
642
bool AndroidConfig::waitForBooted(const QString &serialNumber, const QFutureInterface<bool> &fi) const
Daniel Teske's avatar
Daniel Teske committed
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
{
    // 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
659
QString AndroidConfig::waitForAvd(int apiLevel, const QString &cpuAbi, const QFutureInterface<bool> &fi) const
Daniel Teske's avatar
Daniel Teske committed
660 661 662
{
    // 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
663
    QString serialNumber;
Daniel Teske's avatar
Daniel Teske committed
664 665
    for (int i = 0; i < 60; ++i) {
        if (fi.isCanceled())
Orgad Shaneh's avatar
Orgad Shaneh committed
666
            return QString();
Daniel Teske's avatar
Daniel Teske committed
667 668 669 670
        serialNumber = findAvd(apiLevel, cpuAbi);
        if (!serialNumber.isEmpty())
            return waitForBooted(serialNumber, fi) ?  serialNumber : QString();
        Utils::sleep(2000);
BogDan Vatra's avatar
BogDan Vatra committed
671 672 673 674
    }
    return QString();
}

Daniel Teske's avatar
Daniel Teske committed
675
bool AndroidConfig::isBootToQt(const QString &device) const
676 677 678 679 680 681 682 683
{
    // 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);
684
    if (!adbProc.waitForFinished(5000)) {
685
        adbProc.kill();
686
        return false;
687 688 689 690
    }
    return adbProc.readAll().contains("Boot2Qt");
}

Daniel Teske's avatar
Daniel Teske committed
691
int AndroidConfig::getSDKVersion(const QString &device) const
BogDan Vatra's avatar
BogDan Vatra committed
692
{
693 694 695 696
    // 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
697 698

    QProcess adbProc;
699
    adbProc.start(adbToolPath().toString(), arguments);
700
    if (!adbProc.waitForFinished(5000)) {
701
        adbProc.kill();
BogDan Vatra's avatar
BogDan Vatra committed
702 703 704 705 706
        return -1;
    }
    return adbProc.readAll().trimmed().toInt();
}

707 708 709 710 711
//!
//! \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
712
QString AndroidConfig::getProductModel(const QString &device) const
713
{
714 715
    if (m_serialNumberToDeviceName.contains(device))
        return m_serialNumberToDeviceName.value(device);
716 717 718 719 720 721 722
    // 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);
723
    if (!adbProc.waitForFinished(5000)) {
724 725 726 727 728 729
        adbProc.kill();
        return device;
    }
    QString model = QString::fromLocal8Bit(adbProc.readAll().trimmed());
    if (model.isEmpty())
        return device;
730 731
    if (!device.startsWith(QLatin1String("????")))
        m_serialNumberToDeviceName.insert(device, model);
732 733 734
    return model;
}

Daniel Teske's avatar
Daniel Teske committed
735
bool AndroidConfig::hasFinishedBooting(const QString &device) const
736 737 738 739 740 741 742
{
    QStringList arguments = AndroidDeviceInfo::adbSelector(device);
    arguments << QLatin1String("shell") << QLatin1String("getprop")
              << QLatin1String("init.svc.bootanim");

    QProcess adbProc;
    adbProc.start(adbToolPath().toString(), arguments);
743
    if (!adbProc.waitForFinished(5000)) {
744 745 746 747 748 749 750 751 752
        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
753
QStringList AndroidConfig::getAbis(const QString &device) const
754 755
{
    QStringList result;
756
    for (int i = 1; i < 6; ++i) {
757 758 759 760 761 762 763 764 765
        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);
766
        if (!adbProc.waitForFinished(5000)) {
767 768 769 770 771 772 773 774 775 776 777
            adbProc.kill();
            return result;
        }
        QString abi = QString::fromLocal8Bit(adbProc.readAll().trimmed());
        if (abi.isEmpty())
            break;
        result << abi;
    }
    return result;
}

Daniel Teske's avatar
Daniel Teske committed
778
QString AndroidConfig::highestAndroidSdk() const
779
{
Daniel Teske's avatar
Daniel Teske committed
780
    updateAvailableSdkPlatforms();
781
    if (m_availableSdkPlatforms.isEmpty())
782
        return QString();
783
    return QLatin1String("android-") + QString::number(m_availableSdkPlatforms.first());
784 785
}

Daniel Teske's avatar
Daniel Teske committed
786
QString AndroidConfig::bestNdkPlatformMatch(const QString &targetAPI) const
BogDan Vatra's avatar
BogDan Vatra committed
787
{
Daniel Teske's avatar
Daniel Teske committed
788
    updateNdkInformation();
BogDan Vatra's avatar
BogDan Vatra committed
789
    int target = targetAPI.mid(targetAPI.lastIndexOf(QLatin1Char('-')) + 1).toInt();
790
    foreach (int apiLevel, m_availableNdkPlatforms) {
BogDan Vatra's avatar
BogDan Vatra committed
791 792 793 794 795 796
        if (apiLevel <= target)
            return QString::fromLatin1("android-%1").arg(apiLevel);
    }
    return QLatin1String("android-8");
}

Daniel Teske's avatar
Daniel Teske committed
797
FileName AndroidConfig::sdkLocation() const
798
{
Daniel Teske's avatar
Daniel Teske committed
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 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
    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();
890 891
    m_instance->updateToolChainList();
    m_instance->updateAutomaticKitList();
Daniel Teske's avatar
Daniel Teske committed
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 928 929 930 931 932 933 934 935 936 937 938 939 940 941
    emit m_instance->updated();
}

AndroidDeviceInfo AndroidConfigurations::showDeviceDialog(ProjectExplorer::Project *project, int apiLevel, const QString &abi)
{
    QString serialNumber = defaultDevice(project, abi);
    if (!serialNumber.isEmpty()) {
        // search for that device
        foreach (const AndroidDeviceInfo &info, AndroidConfigurations::currentConfig().connectedDevices())
            if (info.serialNumber == serialNumber
                    && info.sdk >= apiLevel)
                return info;

        foreach (const AndroidDeviceInfo &info, AndroidConfigurations::currentConfig().androidVirtualDevices())
            if (info.serialNumber == serialNumber
                    && info.sdk >= apiLevel)
                return info;
    }

    AndroidDeviceDialog dialog(apiLevel, abi, Core::ICore::mainWindow());
    if (dialog.exec() == QDialog::Accepted) {
        AndroidDeviceInfo info = dialog.device();
        if (dialog.saveDeviceSelection()) {
            if (!info.serialNumber.isEmpty())
                AndroidConfigurations::setDefaultDevice(project, abi, info.serialNumber);
        }
        return info;
    }
    return AndroidDeviceInfo();
}

void AndroidConfigurations::clearDefaultDevices(ProjectExplorer::Project *project)
{
    if (m_instance->m_defaultDeviceForAbi.contains(project))
        m_instance->m_defaultDeviceForAbi.remove(project);
}

void AndroidConfigurations::setDefaultDevice(ProjectExplorer::Project *project, const QString &abi, const QString &serialNumber)
{
    m_instance->m_defaultDeviceForAbi[project][abi] = serialNumber;
}

QString AndroidConfigurations::defaultDevice(Project *project, const QString &abi)
{
    if (!m_instance->m_defaultDeviceForAbi.contains(project))
        return QString();
    const QMap<QString, QString> &map = m_instance->m_defaultDeviceForAbi.value(project);
    if (!map.contains(abi))
        return QString();
    return map.value(abi);
942 943
}

944
static bool equalKits(Kit *a, Kit *b)
Daniel Teske's avatar
Daniel Teske committed
945 946 947 948 949
{
    return ToolChainKitInformation::toolChain(a) == ToolChainKitInformation::toolChain(b)
            && QtSupport::QtKitInformation::qtVersion(a) == QtSupport::QtKitInformation::qtVersion(b);
}