androidconfigurations.cpp 45.4 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();
482 483 484 485 486 487 488 489 490 491
    QString error;
    QString avd = createAVD(avdDialog.targetComboBox->currentText(), avdDialog.nameLineEdit->text(),
                            avdDialog.abiComboBox->currentText(), avdDialog.sizeSpinBox->value(),
                            &error);
    if (!error.isEmpty()) {
        QMessageBox::critical(parent, QApplication::translate("AndroidConfig", "Error Creating AVD"),
                              error);
    }

    return avd;
BogDan Vatra's avatar
BogDan Vatra committed
492 493
}

494
QString AndroidConfig::createAVD(const QString &target, const QString &name, const QString &abi, int sdcardSize, QString *error) const
BogDan Vatra's avatar
BogDan Vatra committed
495 496
{
    QProcess proc;
497
    proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
498
    proc.start(androidToolPath().toString(),
BogDan Vatra's avatar
BogDan Vatra committed
499
               QStringList() << QLatin1String("create") << QLatin1String("avd")
500
               << QLatin1String("-t") << target
BogDan Vatra's avatar
BogDan Vatra committed
501
               << QLatin1String("-n") << name
502
               << QLatin1String("-b") << abi
BogDan Vatra's avatar
BogDan Vatra committed
503 504
               << QLatin1String("-c") << QString::fromLatin1("%1M").arg(sdcardSize));
    if (!proc.waitForStarted())
505
        return QString();
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526

    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
527
    }
528 529 530

    proc.waitForFinished();

531 532 533 534 535
    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;
536
        return QString();
537 538
    }

539
    return name;
BogDan Vatra's avatar
BogDan Vatra committed
540 541
}

Daniel Teske's avatar
Daniel Teske committed
542
bool AndroidConfig::removeAVD(const QString &name) const
BogDan Vatra's avatar
BogDan Vatra committed
543 544
{
    QProcess proc;
545
    proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
546
    proc.start(androidToolPath().toString(),
BogDan Vatra's avatar
BogDan Vatra committed
547 548
               QStringList() << QLatin1String("delete") << QLatin1String("avd")
               << QLatin1String("-n") << name);
549
    if (!proc.waitForFinished(5000)) {
BogDan Vatra's avatar
BogDan Vatra committed
550 551 552 553 554 555
        proc.terminate();
        return false;
    }
    return !proc.exitCode();
}

Daniel Teske's avatar
Daniel Teske committed
556
QVector<AndroidDeviceInfo> AndroidConfig::androidVirtualDevices() const
BogDan Vatra's avatar
BogDan Vatra committed
557
{
558
    QVector<AndroidDeviceInfo> devices;
BogDan Vatra's avatar
BogDan Vatra committed
559
    QProcess proc;
560
    proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
561
    proc.start(androidToolPath().toString(),
BogDan Vatra's avatar
BogDan Vatra committed
562
               QStringList() << QLatin1String("list") << QLatin1String("avd")); // list available AVDs
563
    if (!proc.waitForFinished(5000)) {
BogDan Vatra's avatar
BogDan Vatra committed
564 565 566 567
        proc.terminate();
        return devices;
    }
    QList<QByteArray> avds = proc.readAll().trimmed().split('\n');
BogDan Vatra's avatar
BogDan Vatra committed
568 569 570 571 572 573 574
    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

575
    AndroidDeviceInfo dev;
BogDan Vatra's avatar
BogDan Vatra committed
576 577 578 579 580 581 582 583 584 585 586 587 588
    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();
589 590 591
            if (line.contains(QLatin1String("Tag/ABI:")))
                dev.cpuAbi = QStringList() << line.mid(line.lastIndexOf(QLatin1Char('/')) +1);
            else if (line.contains(QLatin1String("ABI:")))
592
                dev.cpuAbi = QStringList() << line.mid(line.lastIndexOf(QLatin1Char(' '))).trimmed();
BogDan Vatra's avatar
BogDan Vatra committed
593
        }
594 595 596
        // 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
597
        dev.state = AndroidDeviceInfo::OkState;
598
        dev.type = AndroidDeviceInfo::Emulator;
BogDan Vatra's avatar
BogDan Vatra committed
599 600 601 602 603 604 605
        devices.push_back(dev);
    }
    qSort(devices.begin(), devices.end(), androidDevicesLessThan);

    return devices;
}

Daniel Teske's avatar
Daniel Teske committed
606
QString AndroidConfig::startAVD(const QString &name, int apiLevel, QString cpuAbi) const
607
{
608
    if (!findAvd(apiLevel, cpuAbi).isEmpty() || startAVDAsync(name))
609 610 611
        return waitForAvd(apiLevel, cpuAbi);
    return QString();
}
BogDan Vatra's avatar
BogDan Vatra committed
612

Daniel Teske's avatar
Daniel Teske committed
613
bool AndroidConfig::startAVDAsync(const QString &avdName) const
614 615
{
    QProcess *avdProcess = new QProcess();
Daniel Teske's avatar
Daniel Teske committed
616
    avdProcess->connect(avdProcess, SIGNAL(finished(int)), avdProcess, SLOT(deleteLater()));
BogDan Vatra's avatar
BogDan Vatra committed
617 618

    // start the emulator
Orgad Shaneh's avatar
Orgad Shaneh committed
619
    avdProcess->start(emulatorToolPath().toString(),
Daniel Teske's avatar
Daniel Teske committed
620
                        QStringList() << QLatin1String("-partition-size") << QString::number(partitionSize())
BogDan Vatra's avatar
BogDan Vatra committed
621
                        << QLatin1String("-avd") << avdName);
Orgad Shaneh's avatar
Orgad Shaneh committed
622 623
    if (!avdProcess->waitForStarted(-1)) {
        delete avdProcess;
624
        return false;
BogDan Vatra's avatar
BogDan Vatra committed
625
    }
626 627 628
    return true;
}

Daniel Teske's avatar
Daniel Teske committed
629
QString AndroidConfig::findAvd(int apiLevel, const QString &cpuAbi) const
630 631 632 633 634 635 636 637 638
{
    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;
639
        return device.serialNumber;
640
    }
641
    return QString();
642 643
}

Daniel Teske's avatar
Daniel Teske committed
644
bool AndroidConfig::isConnected(const QString &serialNumber) const
645
{
Daniel Teske's avatar
Daniel Teske committed
646 647 648 649 650 651 652
    QVector<AndroidDeviceInfo> devices = connectedDevices();
    foreach (AndroidDeviceInfo device, devices) {
        if (device.serialNumber == serialNumber)
            return true;
    }
    return false;
}
653

Daniel Teske's avatar
Daniel Teske committed
654
bool AndroidConfig::waitForBooted(const QString &serialNumber, const QFutureInterface<bool> &fi) const
Daniel Teske's avatar
Daniel Teske committed
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
{
    // 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
671
QString AndroidConfig::waitForAvd(int apiLevel, const QString &cpuAbi, const QFutureInterface<bool> &fi) const
Daniel Teske's avatar
Daniel Teske committed
672 673 674
{
    // 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
675
    QString serialNumber;
Daniel Teske's avatar
Daniel Teske committed
676 677
    for (int i = 0; i < 60; ++i) {
        if (fi.isCanceled())
Orgad Shaneh's avatar
Orgad Shaneh committed
678
            return QString();
Daniel Teske's avatar
Daniel Teske committed
679 680 681 682
        serialNumber = findAvd(apiLevel, cpuAbi);
        if (!serialNumber.isEmpty())
            return waitForBooted(serialNumber, fi) ?  serialNumber : QString();
        Utils::sleep(2000);
BogDan Vatra's avatar
BogDan Vatra committed
683 684 685 686
    }
    return QString();
}

Daniel Teske's avatar
Daniel Teske committed
687
bool AndroidConfig::isBootToQt(const QString &device) const
688 689 690 691 692 693 694 695
{
    // 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);
696
    if (!adbProc.waitForFinished(5000)) {
697
        adbProc.kill();
698
        return false;
699 700 701 702
    }
    return adbProc.readAll().contains("Boot2Qt");
}

Daniel Teske's avatar
Daniel Teske committed
703
int AndroidConfig::getSDKVersion(const QString &device) const
BogDan Vatra's avatar
BogDan Vatra committed
704
{
705 706 707 708
    // 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
709 710

    QProcess adbProc;
711
    adbProc.start(adbToolPath().toString(), arguments);
712
    if (!adbProc.waitForFinished(5000)) {
713
        adbProc.kill();
BogDan Vatra's avatar
BogDan Vatra committed
714 715 716 717 718
        return -1;
    }
    return adbProc.readAll().trimmed().toInt();
}

719 720 721 722 723
//!
//! \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
724
QString AndroidConfig::getProductModel(const QString &device) const
725
{
726 727
    if (m_serialNumberToDeviceName.contains(device))
        return m_serialNumberToDeviceName.value(device);
728 729 730 731 732 733 734
    // 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);
735
    if (!adbProc.waitForFinished(5000)) {
736 737 738 739 740 741
        adbProc.kill();
        return device;
    }
    QString model = QString::fromLocal8Bit(adbProc.readAll().trimmed());
    if (model.isEmpty())
        return device;
742 743
    if (!device.startsWith(QLatin1String("????")))
        m_serialNumberToDeviceName.insert(device, model);
744 745 746
    return model;
}

Daniel Teske's avatar
Daniel Teske committed
747
bool AndroidConfig::hasFinishedBooting(const QString &device) const
748 749 750 751 752 753 754
{
    QStringList arguments = AndroidDeviceInfo::adbSelector(device);
    arguments << QLatin1String("shell") << QLatin1String("getprop")
              << QLatin1String("init.svc.bootanim");

    QProcess adbProc;
    adbProc.start(adbToolPath().toString(), arguments);
755
    if (!adbProc.waitForFinished(5000)) {
756 757 758 759 760 761 762 763 764
        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
765
QStringList AndroidConfig::getAbis(const QString &device) const
766 767
{
    QStringList result;
768
    for (int i = 1; i < 6; ++i) {
769 770 771 772 773 774 775 776 777
        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);
778
        if (!adbProc.waitForFinished(5000)) {
779 780 781 782 783 784 785 786 787 788 789
            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
790
QString AndroidConfig::highestAndroidSdk() const
791
{
Daniel Teske's avatar
Daniel Teske committed
792
    updateAvailableSdkPlatforms();
793
    if (m_availableSdkPlatforms.isEmpty())
794
        return QString();
795
    return QLatin1String("android-") + QString::number(m_availableSdkPlatforms.first());
796 797
}

Daniel Teske's avatar
Daniel Teske committed
798
QString AndroidConfig::bestNdkPlatformMatch(const QString &targetAPI) const
BogDan Vatra's avatar
BogDan Vatra committed
799
{
Daniel Teske's avatar
Daniel Teske committed
800
    updateNdkInformation();
BogDan Vatra's avatar
BogDan Vatra committed
801
    int target = targetAPI.mid(targetAPI.lastIndexOf(QLatin1Char('-')) + 1).toInt();
802
    foreach (int apiLevel, m_availableNdkPlatforms) {
BogDan Vatra's avatar
BogDan Vatra committed
803 804 805 806 807 808
        if (apiLevel <= target)
            return QString::fromLatin1("android-%1").arg(apiLevel);
    }
    return QLatin1String("android-8");
}

Daniel Teske's avatar
Daniel Teske committed
809
FileName AndroidConfig::sdkLocation() const
810
{
Daniel Teske's avatar
Daniel Teske committed
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 890 891 892 893 894 895 896 897 898 899 900 901
    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();
902 903
    m_instance->updateToolChainList();
    m_instance->updateAutomaticKitList();
Daniel Teske's avatar
Daniel Teske committed
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 942 943 944 945 946 947 948 949 950 951 952 953
    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);
954 955
}