androidmanager.cpp 52.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

Tobias Hunger's avatar
Tobias Hunger committed
30
#include "androidmanager.h"
BogDan Vatra's avatar
BogDan Vatra committed
31 32 33 34 35 36
#include "androiddeployconfiguration.h"
#include "androidconfigurations.h"
#include "androidrunconfiguration.h"
#include "androiddeploystep.h"
#include "androidglobal.h"
#include "androidpackagecreationstep.h"
37
#include "androidtoolchain.h"
38
#include "androiddeployqtstep.h"
BogDan Vatra's avatar
BogDan Vatra committed
39

40
#include <coreplugin/documentmanager.h>
41
#include <coreplugin/messagemanager.h>
Tobias Hunger's avatar
Tobias Hunger committed
42 43 44
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
45 46 47 48
#include <qmakeprojectmanager/qmakenodes.h>
#include <qmakeprojectmanager/qmakeproject.h>
#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h>
#include <qmakeprojectmanager/qmakebuildconfiguration.h>
49
#include <qtsupport/customexecutablerunconfiguration.h>
Tobias Hunger's avatar
Tobias Hunger committed
50
#include <qtsupport/qtkitinformation.h>
Tobias Hunger's avatar
Tobias Hunger committed
51
#include <qtsupport/qtsupportconstants.h>
BogDan Vatra's avatar
BogDan Vatra committed
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66

#include <QDir>
#include <QFileSystemWatcher>
#include <QList>
#include <QProcess>
#include <QMessageBox>
#include <QApplication>
#include <QDomDocument>

namespace {
    const QLatin1String AndroidDirName("android");
    const QLatin1String AndroidManifestName("AndroidManifest.xml");
    const QLatin1String AndroidLibsFileName("/res/values/libs.xml");
    const QLatin1String AndroidStringsFileName("/res/values/strings.xml");
    const QLatin1String AndroidDefaultPropertiesName("project.properties");
67
    const QLatin1String AndroidLibraryPrefix("--Managed_by_Qt_Creator--");
BogDan Vatra's avatar
BogDan Vatra committed
68 69 70

    QString cleanPackageName(QString packageName)
    {
71
        QRegExp legalChars(QLatin1String("[a-zA-Z0-9_\\.]"));
BogDan Vatra's avatar
BogDan Vatra committed
72 73 74 75 76

        for (int i = 0; i < packageName.length(); ++i)
            if (!legalChars.exactMatch(packageName.mid(i, 1)))
                packageName[i] = QLatin1Char('_');

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
        static QStringList keywords;
        if (keywords.isEmpty())
            keywords << QLatin1String("abstract") << QLatin1String("continue") << QLatin1String("for")
                     << QLatin1String("new") << QLatin1String("switch") << QLatin1String("assert")
                     << QLatin1String("default") << QLatin1String("if") << QLatin1String("package")
                     << QLatin1String("synchronized") << QLatin1String("boolean") << QLatin1String("do")
                     << QLatin1String("goto") << QLatin1String("private") << QLatin1String("this")
                     << QLatin1String("break") << QLatin1String("double") << QLatin1String("implements")
                     << QLatin1String("protected") << QLatin1String("throw") << QLatin1String("byte")
                     << QLatin1String("else") << QLatin1String("import") << QLatin1String("public")
                     << QLatin1String("throws") << QLatin1String("case") << QLatin1String("enum")
                     << QLatin1String("instanceof") << QLatin1String("return") << QLatin1String("transient")
                     << QLatin1String("catch") << QLatin1String("extends") << QLatin1String("int")
                     << QLatin1String("short") << QLatin1String("try") << QLatin1String("char")
                     << QLatin1String("final") << QLatin1String("interface") << QLatin1String("static")
                     << QLatin1String("void") << QLatin1String("class") << QLatin1String("finally")
                     << QLatin1String("long") << QLatin1String("strictfp") << QLatin1String("volatile")
                     << QLatin1String("const") << QLatin1String("float") << QLatin1String("native")
                     << QLatin1String("super") << QLatin1String("while");

        // No keywords
        int index = -1;
        while (index != packageName.length()) {
            int next = packageName.indexOf(QLatin1Char('.'), index + 1);
            if (next == -1)
                next = packageName.length();
            QString word = packageName.mid(index + 1, next - index - 1);
            if (!word.isEmpty()) {
                QChar c = word[0];
                if (c >= QChar(QLatin1Char('0')) && c<= QChar(QLatin1Char('9'))) {
                    packageName.insert(index + 1, QLatin1Char('_'));
                    index = next + 1;
                    continue;
                }
            }
            if (keywords.contains(word)) {
                packageName.insert(next, QLatin1String("_"));
                index = next + 1;
            } else {
                index = next;
            }
        }


BogDan Vatra's avatar
BogDan Vatra committed
121 122 123 124 125 126 127
        return packageName;
    }
} // anonymous namespace

namespace Android {
namespace Internal {

Tobias Hunger's avatar
Tobias Hunger committed
128
bool AndroidManager::supportsAndroid(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
129
{
130
    if (!qobject_cast<QmakeProjectManager::QmakeProject *>(target->project()))
Tobias Hunger's avatar
Tobias Hunger committed
131
        return false;
Tobias Hunger's avatar
Tobias Hunger committed
132
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit());
133
    return version && version->platformName() == QLatin1String(QtSupport::Constants::ANDROID_PLATFORM);
Tobias Hunger's avatar
Tobias Hunger committed
134
}
BogDan Vatra's avatar
BogDan Vatra committed
135

Tobias Hunger's avatar
Tobias Hunger committed
136 137 138 139 140 141 142
QString AndroidManager::packageName(ProjectExplorer::Target *target)
{
    QDomDocument doc;
    if (!openManifest(target, doc))
        return QString();
    QDomElement manifestElem = doc.documentElement();
    return manifestElem.attribute(QLatin1String("package"));
BogDan Vatra's avatar
BogDan Vatra committed
143 144
}

Tobias Hunger's avatar
Tobias Hunger committed
145
bool AndroidManager::setPackageName(ProjectExplorer::Target *target, const QString &name)
BogDan Vatra's avatar
BogDan Vatra committed
146
{
Tobias Hunger's avatar
Tobias Hunger committed
147 148 149 150 151 152
    QDomDocument doc;
    if (!openManifest(target, doc))
        return false;
    QDomElement manifestElem = doc.documentElement();
    manifestElem.setAttribute(QLatin1String("package"), cleanPackageName(name));
    return saveManifest(target, doc);
BogDan Vatra's avatar
BogDan Vatra committed
153 154
}

Tobias Hunger's avatar
Tobias Hunger committed
155
QString AndroidManager::applicationName(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
156
{
Tobias Hunger's avatar
Tobias Hunger committed
157
    QDomDocument doc;
158
    if (!openXmlFile(doc, stringsPath(target)))
Tobias Hunger's avatar
Tobias Hunger committed
159 160 161 162 163 164 165 166 167
        return QString();
    QDomElement metadataElem = doc.documentElement().firstChildElement(QLatin1String("string"));
    while (!metadataElem.isNull()) {
        if (metadataElem.attribute(QLatin1String("name")) == QLatin1String("app_name"))
            return metadataElem.text();
        metadataElem = metadataElem.nextSiblingElement(QLatin1String("string"));
    }
    return QString();
}
BogDan Vatra's avatar
BogDan Vatra committed
168

Tobias Hunger's avatar
Tobias Hunger committed
169 170 171 172
bool AndroidManager::setApplicationName(ProjectExplorer::Target *target, const QString &name)
{
    QDomDocument doc;
    Utils::FileName path = stringsPath(target);
173
    if (!openXmlFile(doc, path))
Tobias Hunger's avatar
Tobias Hunger committed
174 175 176 177 178 179 180 181 182 183 184 185
        return false;
    QDomElement metadataElem = doc.documentElement().firstChildElement(QLatin1String("string"));
    while (!metadataElem.isNull()) {
        if (metadataElem.attribute(QLatin1String("name")) == QLatin1String("app_name")) {
            metadataElem.removeChild(metadataElem.firstChild());
            metadataElem.appendChild(doc.createTextNode(name));
            break;
        }
        metadataElem = metadataElem.nextSiblingElement(QLatin1String("string"));
    }
    return saveXmlFile(target, doc, path);
}
BogDan Vatra's avatar
BogDan Vatra committed
186

Tobias Hunger's avatar
Tobias Hunger committed
187
QString AndroidManager::intentName(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
188
{
Tobias Hunger's avatar
Tobias Hunger committed
189
    return packageName(target) + QLatin1Char('/') + activityName(target);
BogDan Vatra's avatar
BogDan Vatra committed
190 191
}

Tobias Hunger's avatar
Tobias Hunger committed
192
QString AndroidManager::activityName(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
193
{
Tobias Hunger's avatar
Tobias Hunger committed
194 195 196 197 198
    QDomDocument doc;
    if (!openManifest(target, doc))
        return QString();
    QDomElement activityElem = doc.documentElement().firstChildElement(QLatin1String("application")).firstChildElement(QLatin1String("activity"));
    return activityElem.attribute(QLatin1String("android:name"));
BogDan Vatra's avatar
BogDan Vatra committed
199 200
}

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
int AndroidManager::minimumSDK(ProjectExplorer::Target *target)
{
    QDomDocument doc;
    if (!openManifest(target, doc))
        return 0;
    QDomElement manifestElem = doc.documentElement();
    QDomElement usesSdk = manifestElem.firstChildElement(QLatin1String("uses-sdk"));
    if (usesSdk.isNull())
        return 0;
    if (usesSdk.hasAttribute(QLatin1String("android:minSdkVersion"))) {
        bool ok;
        int tmp = usesSdk.attribute(QLatin1String("android:minSdkVersion")).toInt(&ok);
        if (ok)
            return tmp;
    }
    return 0;
}

219
QString AndroidManager::buildTargetSDK(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
220
{
221 222 223 224 225 226 227 228 229 230
    QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target->kit());
    if (qt && qt->qtVersion() >= QtSupport::QtVersionNumber(5, 2, 0)) {
        if (!target->activeDeployConfiguration())
            return QLatin1String("android-9");
        AndroidDeployQtStep *step = AndroidGlobal::buildStep<AndroidDeployQtStep>(target->activeDeployConfiguration());
        if (step)
            return step->buildTargetSdk();
        return QLatin1String("android-9");
    }

231 232 233 234
    QVariant v = target->namedSettings(QLatin1String("AndroidManager.TargetSdk"));
    if (v.isValid())
        return v.toString();

235
    QString fallback = QLatin1String("android-8");
236 237
    if (qt && qt->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0))
        fallback = QLatin1String("android-9");
238

Tobias Hunger's avatar
Tobias Hunger committed
239
    if (!createAndroidTemplatesIfNecessary(target))
240
        return fallback;
241

Tobias Hunger's avatar
Tobias Hunger committed
242 243
    QFile file(defaultPropertiesPath(target).toString());
    if (!file.open(QIODevice::ReadOnly))
244
        return fallback;
Tobias Hunger's avatar
Tobias Hunger committed
245 246 247 248 249
    while (!file.atEnd()) {
        QByteArray line = file.readLine();
        if (line.startsWith("target="))
            return QString::fromLatin1(line.trimmed().mid(7));
    }
250
    return fallback;
Tobias Hunger's avatar
Tobias Hunger committed
251
}
BogDan Vatra's avatar
BogDan Vatra committed
252

253
bool AndroidManager::setBuildTargetSDK(ProjectExplorer::Target *target, const QString &sdk)
Tobias Hunger's avatar
Tobias Hunger committed
254 255
{
    updateTarget(target, sdk, applicationName(target));
256
    target->setNamedSettings(QLatin1String("AndroidManager.TargetSdk"), sdk);
Tobias Hunger's avatar
Tobias Hunger committed
257 258
    return true;
}
BogDan Vatra's avatar
BogDan Vatra committed
259

260 261
QString AndroidManager::targetArch(ProjectExplorer::Target *target)
{
262
    QmakeProjectManager::QmakeProject *pro = qobject_cast<QmakeProjectManager::QmakeProject *>(target->project());
263 264
    if (!pro)
        return QString();
265
    QmakeProjectManager::QmakeProFileNode *node = pro->rootQmakeProjectNode();
266 267
    if (!node)
        return QString();
268
    return node->singleVariableValue(QmakeProjectManager::AndroidArchVar);
269 270
}

Tobias Hunger's avatar
Tobias Hunger committed
271
Utils::FileName AndroidManager::dirPath(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
272
{
273 274
    QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(target->kit());
    if (qtVersion && qtVersion->qtVersion() >= QtSupport::QtVersionNumber(5, 2, 0))
275
        return target->activeBuildConfiguration()->buildDirectory().appendPath(QLatin1String(Constants::ANDROID_BUILDDIRECTORY));
Tobias Hunger's avatar
Tobias Hunger committed
276
    return Utils::FileName::fromString(target->project()->projectDirectory()).appendPath(AndroidDirName);
BogDan Vatra's avatar
BogDan Vatra committed
277 278
}

Tobias Hunger's avatar
Tobias Hunger committed
279
Utils::FileName AndroidManager::manifestPath(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
280
{
Tobias Hunger's avatar
Tobias Hunger committed
281
    return dirPath(target).appendPath(AndroidManifestName);
BogDan Vatra's avatar
BogDan Vatra committed
282 283
}

Tobias Hunger's avatar
Tobias Hunger committed
284
Utils::FileName AndroidManager::libsPath(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
285
{
Tobias Hunger's avatar
Tobias Hunger committed
286 287
    return dirPath(target).appendPath(AndroidLibsFileName);
}
BogDan Vatra's avatar
BogDan Vatra committed
288

Tobias Hunger's avatar
Tobias Hunger committed
289 290
Utils::FileName AndroidManager::stringsPath(ProjectExplorer::Target *target)
{
291
    return dirPath(target).appendString(AndroidStringsFileName);
BogDan Vatra's avatar
BogDan Vatra committed
292 293
}

Tobias Hunger's avatar
Tobias Hunger committed
294
Utils::FileName AndroidManager::defaultPropertiesPath(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
295
{
Tobias Hunger's avatar
Tobias Hunger committed
296 297
    return dirPath(target).appendPath(AndroidDefaultPropertiesName);
}
BogDan Vatra's avatar
BogDan Vatra committed
298

Tobias Hunger's avatar
Tobias Hunger committed
299 300 301 302
Utils::FileName AndroidManager::srcPath(ProjectExplorer::Target *target)
{
    return dirPath(target).appendPath(QLatin1String("/src"));
}
BogDan Vatra's avatar
BogDan Vatra committed
303

Tobias Hunger's avatar
Tobias Hunger committed
304 305
Utils::FileName AndroidManager::apkPath(ProjectExplorer::Target *target, BuildType buildType)
{
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
    QString packageName = QLatin1String("QtApp");
    QString buildTypeName;
    if (buildType == DebugBuild)
        buildTypeName = QLatin1String("debug");
    else if (buildType == ReleaseBuildUnsigned)
        buildTypeName =QLatin1String("release-unsigned");
    else
        buildTypeName = QLatin1String("release");

    QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target->kit());
    if (!qt || qt->qtVersion() < QtSupport::QtVersionNumber(5, 2, 0)) {
        // Qt 5.1 and earlier:
        packageName = applicationName(target);
        if (buildType == ReleaseBuildSigned)
            buildTypeName = QLatin1String("signed");
    }

Tobias Hunger's avatar
Tobias Hunger committed
323 324 325
    return dirPath(target)
            .appendPath(QLatin1String("bin"))
            .appendPath(QString::fromLatin1("%1-%2.apk")
326 327
                        .arg(packageName)
                        .arg(buildTypeName));
Tobias Hunger's avatar
Tobias Hunger committed
328
}
BogDan Vatra's avatar
BogDan Vatra committed
329

Tobias Hunger's avatar
Tobias Hunger committed
330 331 332
QStringList AndroidManager::availableTargetApplications(ProjectExplorer::Target *target)
{
    QStringList apps;
333 334
    QmakeProjectManager::QmakeProject *qmakeProject = qobject_cast<QmakeProjectManager::QmakeProject *>(target->project());
    if (!qmakeProject)
335
        return apps;
336
    foreach (QmakeProjectManager::QmakeProFileNode *proFile, qmakeProject->applicationProFiles()) {
337
        if (proFile->projectType() == QmakeProjectManager::ApplicationTemplate) {
Tobias Hunger's avatar
Tobias Hunger committed
338 339 340 341 342
            if (proFile->targetInformation().target.startsWith(QLatin1String("lib"))
                    && proFile->targetInformation().target.endsWith(QLatin1String(".so")))
                apps << proFile->targetInformation().target.mid(3, proFile->targetInformation().target.lastIndexOf(QLatin1Char('.')) - 3);
            else
                apps << proFile->targetInformation().target;
BogDan Vatra's avatar
BogDan Vatra committed
343 344
        }
    }
Tobias Hunger's avatar
Tobias Hunger committed
345 346 347
    apps.sort();
    return apps;
}
BogDan Vatra's avatar
BogDan Vatra committed
348

Tobias Hunger's avatar
Tobias Hunger committed
349 350 351 352 353 354 355 356 357 358 359 360 361
QString AndroidManager::targetApplication(ProjectExplorer::Target *target)
{
    QDomDocument doc;
    if (!openManifest(target, doc))
        return QString();
    QDomElement metadataElem = doc.documentElement().firstChildElement(QLatin1String("application")).firstChildElement(QLatin1String("activity")).firstChildElement(QLatin1String("meta-data"));
    while (!metadataElem.isNull()) {
        if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.lib_name"))
            return metadataElem.attribute(QLatin1String("android:value"));
        metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data"));
    }
    return QString();
}
BogDan Vatra's avatar
BogDan Vatra committed
362

363 364 365
// Note, this could be implemented via a base class and a couple of virtuals
// but I intend to remove the indirection once we drop support for qt 4.8
// and qt 5.1.
366 367
bool AndroidManager::bundleQt(ProjectExplorer::Target *target)
{
368 369
    AndroidDeployStep *androidDeployStep
        = AndroidGlobal::buildStep<AndroidDeployStep>(target->activeDeployConfiguration());
Orgad Shaneh's avatar
Orgad Shaneh committed
370
    if (androidDeployStep)
371 372 373 374
        return androidDeployStep->deployAction() == AndroidDeployStep::BundleLibraries;

    AndroidDeployQtStep *androidDeployQtStep
            = AndroidGlobal::buildStep<AndroidDeployQtStep>(target->activeDeployConfiguration());
Orgad Shaneh's avatar
Orgad Shaneh committed
375
    if (androidDeployQtStep)
376
        return androidDeployQtStep->deployAction() == AndroidDeployQtStep::BundleLibrariesDeployment;
377 378 379 380

    return false;
}

381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
bool AndroidManager::useLocalLibs(ProjectExplorer::Target *target)
{
    AndroidDeployStep *androidDeployStep
        = AndroidGlobal::buildStep<AndroidDeployStep>(target->activeDeployConfiguration());
    if (androidDeployStep) {
        return androidDeployStep->deployAction() == AndroidDeployStep::DeployLocal
                || androidDeployStep->deployAction() == AndroidDeployStep::BundleLibraries;
    }

    AndroidDeployQtStep *androidDeployQtStep
            = AndroidGlobal::buildStep<AndroidDeployQtStep>(target->activeDeployConfiguration());
    if (androidDeployQtStep) {
        return androidDeployQtStep->deployAction() == AndroidDeployQtStep::DebugDeployment
                || androidDeployQtStep->deployAction() == AndroidDeployQtStep::BundleLibrariesDeployment;
    }

    return false;
}

QString AndroidManager::deviceSerialNumber(ProjectExplorer::Target *target)
{
    AndroidDeployStep *androidDeployStep
        = AndroidGlobal::buildStep<AndroidDeployStep>(target->activeDeployConfiguration());
    if (androidDeployStep)
        return androidDeployStep->deviceSerialNumber();

    AndroidDeployQtStep *androidDeployQtStep
            = AndroidGlobal::buildStep<AndroidDeployQtStep>(target->activeDeployConfiguration());
    if (androidDeployQtStep)
        return androidDeployQtStep->deviceSerialNumber();
    return QString();
}

414
bool AndroidManager::updateDeploymentSettings(ProjectExplorer::Target *target)
415 416 417 418 419 420 421
{
    // For Qt 4, the "use local libs" options is handled by passing command line arguments to the
    // app, so no need to alter the AndroidManifest.xml
    QtSupport::BaseQtVersion *baseQtVersion = QtSupport::QtKitInformation::qtVersion(target->kit());
    if (baseQtVersion == 0 || baseQtVersion->qtVersion() < QtSupport::QtVersionNumber(5,0,0))
        return true;

422 423 424
    if (baseQtVersion->qtVersion() >= QtSupport::QtVersionNumber(5, 2, 0))
        return true;

425 426 427 428 429
    ProjectExplorer::RunConfiguration *runConfiguration = target->activeRunConfiguration();
    AndroidRunConfiguration *androidRunConfiguration = qobject_cast<AndroidRunConfiguration *>(runConfiguration);
    if (androidRunConfiguration == 0)
        return false;

430 431
    bool useLocalLibs = AndroidManager::useLocalLibs(target);
    bool bundleQtLibs = AndroidManager::bundleQt(target);
432

433 434 435 436 437 438
    QDomDocument doc;
    if (!openManifest(target, doc))
        return false;

    QDomElement metadataElem = doc.documentElement().firstChildElement(QLatin1String("application")).firstChildElement(QLatin1String("activity")).firstChildElement(QLatin1String("meta-data"));

439 440 441
    // ### Passes -1 for API level, which means it won't work with setups that require
    // library selection based on API level. Use the old approach (command line argument)
    // in these cases. Hence the Qt version > 4 condition at the beginning of this function.
442 443 444 445
    QString localLibs;
    QString localJars;
    QString staticInitClasses;
    if (useLocalLibs) {
446 447 448
        localLibs = loadLocalLibs(target, -1);
        localJars = loadLocalJars(target, -1);
        staticInitClasses = loadLocalJarsInitClasses(target, -1);
449 450 451 452 453
    }

    bool changedManifest = false;
    while (!metadataElem.isNull()) {
        if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.use_local_qt_libs")) {
Orgad Shaneh's avatar
Orgad Shaneh committed
454
            if (metadataElem.attribute(QLatin1String("android:value")).toInt() != int(useLocalLibs)) {
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
                metadataElem.setAttribute(QLatin1String("android:value"), int(useLocalLibs));
                changedManifest = true;
            }
        } else if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.load_local_libs")) {
            if (metadataElem.attribute(QLatin1String("android:value")) != localLibs) {
                metadataElem.setAttribute(QLatin1String("android:value"), localLibs);
                changedManifest = true;
            }
        } else if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.load_local_jars")) {
            if (metadataElem.attribute(QLatin1String("android:value")) != localJars) {
                metadataElem.setAttribute(QLatin1String("android:value"), localJars);
                changedManifest = true;
            }
        } else if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.static_init_classes")) {
            if (metadataElem.attribute(QLatin1String("android:value")) != staticInitClasses) {
                metadataElem.setAttribute(QLatin1String("android:value"), staticInitClasses);
                changedManifest = true;
            }
473
        } else if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.bundle_local_qt_libs")) {
Orgad Shaneh's avatar
Orgad Shaneh committed
474
            if (metadataElem.attribute(QLatin1String("android:value")).toInt() != int(bundleQtLibs)) {
475 476 477
                metadataElem.setAttribute(QLatin1String("android:value"), int(bundleQtLibs));
                changedManifest = true;
            }
478 479 480 481 482 483 484 485 486 487 488
        }

        metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data"));
    }

    if (changedManifest)
        return saveManifest(target, doc);
    else
        return true;
}

Tobias Hunger's avatar
Tobias Hunger committed
489 490 491 492 493 494 495 496 497 498
bool AndroidManager::setTargetApplication(ProjectExplorer::Target *target, const QString &name)
{
    QDomDocument doc;
    if (!openManifest(target, doc))
        return false;
    QDomElement metadataElem = doc.documentElement().firstChildElement(QLatin1String("application")).firstChildElement(QLatin1String("activity")).firstChildElement(QLatin1String("meta-data"));
    while (!metadataElem.isNull()) {
        if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")) {
            metadataElem.setAttribute(QLatin1String("android:value"), name);
            return saveManifest(target, doc);
BogDan Vatra's avatar
BogDan Vatra committed
499
        }
Tobias Hunger's avatar
Tobias Hunger committed
500
        metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data"));
BogDan Vatra's avatar
BogDan Vatra committed
501
    }
Tobias Hunger's avatar
Tobias Hunger committed
502
    return false;
BogDan Vatra's avatar
BogDan Vatra committed
503 504
}

Tobias Hunger's avatar
Tobias Hunger committed
505
QString AndroidManager::targetApplicationPath(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
506
{
Tobias Hunger's avatar
Tobias Hunger committed
507 508 509
    QString selectedApp = targetApplication(target);
    if (selectedApp.isEmpty())
        return QString();
510 511
    QmakeProjectManager::QmakeProject *qmakeProject = qobject_cast<QmakeProjectManager::QmakeProject *>(target->project());
    foreach (QmakeProjectManager::QmakeProFileNode *proFile, qmakeProject->applicationProFiles()) {
512
        if (proFile->projectType() == QmakeProjectManager::ApplicationTemplate) {
Tobias Hunger's avatar
Tobias Hunger committed
513 514 515 516
            if (proFile->targetInformation().target.startsWith(QLatin1String("lib"))
                    && proFile->targetInformation().target.endsWith(QLatin1String(".so"))) {
                if (proFile->targetInformation().target.mid(3, proFile->targetInformation().target.lastIndexOf(QLatin1Char('.')) - 3)
                        == selectedApp)
517
                    return proFile->targetInformation().buildDir + QLatin1Char('/') + proFile->targetInformation().target;
Tobias Hunger's avatar
Tobias Hunger committed
518 519 520 521 522 523 524
            } else {
                if (proFile->targetInformation().target == selectedApp)
                    return proFile->targetInformation().buildDir + QLatin1String("/lib") + proFile->targetInformation().target + QLatin1String(".so");
            }
        }
    }
    return QString();
BogDan Vatra's avatar
BogDan Vatra committed
525 526
}

Tobias Hunger's avatar
Tobias Hunger committed
527
bool AndroidManager::createAndroidTemplatesIfNecessary(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
528
{
Tobias Hunger's avatar
Tobias Hunger committed
529
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit());
530 531
    QmakeProjectManager::QmakeProject *qmakeProject = qobject_cast<QmakeProjectManager::QmakeProject*>(target->project());
    if (!qmakeProject || !qmakeProject->rootProjectNode() || !version)
Tobias Hunger's avatar
Tobias Hunger committed
532 533
        return false;

534 535 536 537
    // TODO we should create the AndroidManifest.xml file for that version
    if (version->qtVersion() >= QtSupport::QtVersionNumber(5, 2, 0))
        return true;

Tobias Hunger's avatar
Tobias Hunger committed
538
    Utils::FileName javaSrcPath
539
            = Utils::FileName::fromString(version->qmakeProperty("QT_INSTALL_PREFIX"))
540
            .appendPath(QLatin1String("src/android/java"));
541
    QDir projectDir(qmakeProject->projectDirectory());
Tobias Hunger's avatar
Tobias Hunger committed
542 543 544 545 546
    Utils::FileName androidPath = dirPath(target);

    QStringList m_ignoreFiles;
    bool forceUpdate = false;
    QDomDocument srcVersionDoc;
547 548
    Utils::FileName srcVersionPath = javaSrcPath;
    srcVersionPath.appendPath(QLatin1String("version.xml"));
549
    if (openXmlFile(srcVersionDoc, srcVersionPath)) {
Tobias Hunger's avatar
Tobias Hunger committed
550
        QDomDocument dstVersionDoc;
551 552
        Utils::FileName dstVersionPath=androidPath;
        dstVersionPath.appendPath(QLatin1String("version.xml"));
553
        if (openXmlFile(dstVersionDoc, dstVersionPath))
Tobias Hunger's avatar
Tobias Hunger committed
554 555 556 557 558 559 560 561 562 563 564 565 566 567
            forceUpdate = (srcVersionDoc.documentElement().attribute(QLatin1String("value")).toDouble()
                           > dstVersionDoc.documentElement().attribute(QLatin1String("value")).toDouble());
        else
            forceUpdate = true;

        if (forceUpdate && androidPath.toFileInfo().exists()) {
            QDomElement ignoreFile = srcVersionDoc.documentElement().firstChildElement(QLatin1String("ignore")).firstChildElement(QLatin1String("file"));
            while (!ignoreFile.isNull()) {
                m_ignoreFiles << ignoreFile.text();
                ignoreFile = ignoreFile.nextSiblingElement();
            }
        }
    }

BogDan Vatra's avatar
BogDan Vatra committed
568
    Utils::FileName src = androidPath;
569
    src.appendPath(QLatin1String("src"));
BogDan Vatra's avatar
BogDan Vatra committed
570
    Utils::FileName res = androidPath;
571
    res.appendPath(QLatin1String("res"));
BogDan Vatra's avatar
BogDan Vatra committed
572

Tobias Hunger's avatar
Tobias Hunger committed
573 574
    if (!forceUpdate && androidPath.toFileInfo().exists()
            && manifestPath(target).toFileInfo().exists()
BogDan Vatra's avatar
BogDan Vatra committed
575 576
            && src.toFileInfo().exists()
            && res.toFileInfo().exists())
Tobias Hunger's avatar
Tobias Hunger committed
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
        return true;

    forceUpdate &= androidPath.toFileInfo().exists();

    if (!dirPath(target).toFileInfo().exists() && !projectDir.mkdir(AndroidDirName)) {
        raiseError(tr("Error creating Android directory '%1'.").arg(AndroidDirName));
        return false;
    }

    QStringList androidFiles;
    QDirIterator it(javaSrcPath.toString(), QDirIterator::Subdirectories);
    int pos = it.path().size();
    while (it.hasNext()) {
        it.next();
        if (it.fileInfo().isDir()) {
            projectDir.mkpath(AndroidDirName + it.filePath().mid(pos));
        } else {
594 595
            Utils::FileName dstFile = androidPath;
            dstFile.appendPath(it.filePath().mid(pos));
Tobias Hunger's avatar
Tobias Hunger committed
596 597 598 599 600 601 602 603 604 605 606 607
            if (m_ignoreFiles.contains(it.fileName())) {
                continue;
            } else {
                if (dstFile.toFileInfo().exists())
                    QFile::remove(dstFile.toString());
                else
                    androidFiles << dstFile.toString();
            }
            QFile::copy(it.filePath(), dstFile.toString());
        }
    }
    if (!androidFiles.isEmpty())
608
        qmakeProject->rootProjectNode()->addFiles(androidFiles);
Tobias Hunger's avatar
Tobias Hunger committed
609

610 611 612 613 614 615
    int minApiLevel = 4;
    if (QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target->kit()))
        if (qt->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0))
            minApiLevel = 9;

    QStringList sdks = AndroidConfigurations::instance().sdkTargets(minApiLevel);
Tobias Hunger's avatar
Tobias Hunger committed
616 617 618 619
    if (sdks.isEmpty()) {
        raiseError(tr("No Qt for Android SDKs were found.\nPlease install at least one SDK."));
        return false;
    }
620

621
    updateTarget(target, sdks.first());
Tobias Hunger's avatar
Tobias Hunger committed
622 623 624 625 626 627 628 629 630 631 632 633
    QStringList apps = availableTargetApplications(target);
    if (!apps.isEmpty())
        setTargetApplication(target, apps.at(0));

    QString applicationName = target->project()->displayName();
    if (!applicationName.isEmpty()) {
        setPackageName(target, packageName(target) + QLatin1Char('.') + applicationName);
        applicationName[0] = applicationName[0].toUpper();
        setApplicationName(target, applicationName);
    }

    if (forceUpdate)
634
        QMessageBox::warning(0, tr("Warning"), tr("Android files have been updated automatically."));
Tobias Hunger's avatar
Tobias Hunger committed
635 636

    return true;
BogDan Vatra's avatar
BogDan Vatra committed
637 638
}

Tobias Hunger's avatar
Tobias Hunger committed
639
void AndroidManager::updateTarget(ProjectExplorer::Target *target, const QString &targetSDK, const QString &name)
BogDan Vatra's avatar
BogDan Vatra committed
640
{
641 642 643 644
    QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(target->kit());
    if (qtVersion && qtVersion->qtVersion() >= QtSupport::QtVersionNumber(5,2,0))
        return;

Tobias Hunger's avatar
Tobias Hunger committed
645
    QString androidDir = dirPath(target).toString();
BogDan Vatra's avatar
BogDan Vatra committed
646

647 648 649 650
    Utils::Environment env = Utils::Environment::systemEnvironment();
    QString javaHome = AndroidConfigurations::instance().config().openJDKLocation.toString();
    if (!javaHome.isEmpty())
        env.set(QLatin1String("JAVA_HOME"), javaHome);
BogDan Vatra's avatar
BogDan Vatra committed
651 652 653
    // clean previous build
    QProcess androidProc;
    androidProc.setWorkingDirectory(androidDir);
654
    androidProc.setProcessEnvironment(env.toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
655 656
    androidProc.start(AndroidConfigurations::instance().antToolPath().toString(),
                      QStringList() << QLatin1String("clean"));
BogDan Vatra's avatar
BogDan Vatra committed
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
    if (!androidProc.waitForFinished(-1))
        androidProc.terminate();
    // clean previous build

    int targetSDKNumber = targetSDK.mid(targetSDK.lastIndexOf(QLatin1Char('-')) + 1).toInt();
    bool commentLines = false;
    QDirIterator it(androidDir, QStringList() << QLatin1String("*.java"), QDir::Files, QDirIterator::Subdirectories);
    while (it.hasNext()) {
        it.next();
        QFile file(it.filePath());
        if (!file.open(QIODevice::ReadWrite))
            continue;
        QList<QByteArray> lines = file.readAll().trimmed().split('\n');

        bool modified = false;
        bool comment = false;
        for (int i = 0; i < lines.size(); i++) {
674 675 676
            QByteArray trimmed = lines[i].trimmed();
            if (trimmed.contains("@ANDROID-")) {
                commentLines = targetSDKNumber < trimmed.mid(trimmed.lastIndexOf('-') + 1).toInt();
BogDan Vatra's avatar
BogDan Vatra committed
677 678 679 680 681 682
                comment = !comment;
                continue;
            }
            if (!comment)
                continue;
            if (commentLines) {
683
                if (!trimmed.startsWith("//QtCreator")) {
BogDan Vatra's avatar
BogDan Vatra committed
684 685 686
                    lines[i] = "//QtCreator " + lines[i];
                    modified = true;
                }
687
            } else { if (trimmed.startsWith("//QtCreator")) {
BogDan Vatra's avatar
BogDan Vatra committed
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
                    lines[i] = lines[i].mid(12);
                    modified = true;
                }
            }
        }
        if (modified) {
            file.resize(0);
            foreach (const QByteArray &line, lines) {
                file.write(line);
                file.write("\n");
            }
        }
        file.close();
    }

    QStringList params;
    params << QLatin1String("update") << QLatin1String("project") << QLatin1String("-p") << androidDir;
    if (!targetSDK.isEmpty())
        params << QLatin1String("-t") << targetSDK;
    if (!name.isEmpty())
        params << QLatin1String("-n") << name;
709
    androidProc.setProcessEnvironment(AndroidConfigurations::instance().androidToolEnvironment().toProcessEnvironment());
Tobias Hunger's avatar
Tobias Hunger committed
710
    androidProc.start(AndroidConfigurations::instance().androidToolPath().toString(), params);
BogDan Vatra's avatar
BogDan Vatra committed
711 712 713 714
    if (!androidProc.waitForFinished(-1))
        androidProc.terminate();
}

Tobias Hunger's avatar
Tobias Hunger committed
715
Utils::FileName AndroidManager::localLibsRulesFilePath(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
716
{
Tobias Hunger's avatar
Tobias Hunger committed
717
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit());
Tobias Hunger's avatar
Tobias Hunger committed
718 719
    if (!version)
        return Utils::FileName();
720
    return Utils::FileName::fromString(version->qmakeProperty("QT_INSTALL_LIBS"));
Tobias Hunger's avatar
Tobias Hunger committed
721
}
BogDan Vatra's avatar
BogDan Vatra committed
722

Tobias Hunger's avatar
Tobias Hunger committed
723 724 725 726
QString AndroidManager::loadLocalLibs(ProjectExplorer::Target *target, int apiLevel)
{
    return loadLocal(target, apiLevel, Lib);
}
BogDan Vatra's avatar
BogDan Vatra committed
727

728 729 730 731 732
QString AndroidManager::loadLocalBundledFiles(ProjectExplorer::Target *target, int apiLevel)
{
    return loadLocal(target, apiLevel, BundledFile);
}

Tobias Hunger's avatar
Tobias Hunger committed
733 734
QString AndroidManager::loadLocalJars(ProjectExplorer::Target *target, int apiLevel)
{
735 736
    ItemType type = bundleQt(target) ? BundledJar : Jar;
    return loadLocal(target, apiLevel, type);
Tobias Hunger's avatar
Tobias Hunger committed
737
}
BogDan Vatra's avatar
BogDan Vatra committed
738

739 740
QString AndroidManager::loadLocalJarsInitClasses(ProjectExplorer::Target *target, int apiLevel)
{
741 742
    ItemType type = bundleQt(target) ? BundledJar : Jar;
    return loadLocal(target, apiLevel, type, QLatin1String("initClass"));
743 744
}

745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
QPair<int, int> AndroidManager::apiLevelRange(ProjectExplorer::Target *target)
{
    // 4 is the minimum version on which qt is supported
    // 19 and 20 are not yet released, but allow the user
    // to set them
    int minApiLevel = 4;
    QtSupport::BaseQtVersion *qt;
    if (target && (qt = QtSupport::QtKitInformation::qtVersion(target->kit())))
        if (qt->qtVersion() >= QtSupport::QtVersionNumber(5, 0, 0))
            minApiLevel = 9;
    return qMakePair(minApiLevel, 20);
}

QString AndroidManager::androidNameForApiLevel(int x)
{
    switch (x) {
    case 4:
        return QLatin1String("Android 1.6");
    case 5:
        return QLatin1String("Android 2.0");
    case 6:
        return QLatin1String("Android 2.0.1");
    case 7:
        return QLatin1String("Android 2.1.x");
    case 8:
        return QLatin1String("Android 2.2.x");
    case 9:
        return QLatin1String("Android 2.3, 2.3.1, 2.3.2");
    case 10:
        return QLatin1String("Android 2.3.3, 2.3.4");
    case 11:
        return QLatin1String("Android 3.0.x");
    case 12:
        return QLatin1String("Android 3.1.x");
    case 13:
        return QLatin1String("Android 3.2");
    case 14:
        return QLatin1String("Android 4.0, 4.0.1, 4.0.2");
    case 15:
        return QLatin1String("Android 4.0.3, 4.0.4");
    case 16:
        return QLatin1String("Android 4.1, 4.1.1");
    case 17:
        return QLatin1String("Android 4.2, 4.2.2");
    case 18:
        return QLatin1String("Android 4.3");
791 792
    case 19:
        return QLatin1String("Android 4.4");
793
    default:
794
        return tr("Unknown Android version.");
795 796 797
    }
}

798
QVector<AndroidManager::Library> AndroidManager::availableQtLibsWithDependencies(ProjectExplorer::Target *target)
Tobias Hunger's avatar
Tobias Hunger committed
799
{
Tobias Hunger's avatar
Tobias Hunger committed
800
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit());
Tobias Hunger's avatar
Tobias Hunger committed
801
    if (!target->activeRunConfiguration())
802
        return QVector<AndroidManager::Library>();
Tobias Hunger's avatar
Tobias Hunger committed
803

804 805
    ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(target->kit());
    if (tc->type() != QLatin1String(Constants::ANDROID_TOOLCHAIN_TYPE))
806
        return QVector<AndroidManager::Library>();
807

808 809
    QmakeProjectManager::QmakeProject *project = static_cast<QmakeProjectManager::QmakeProject *>(target->project());
    QString arch = project->rootQmakeProjectNode()->singleVariableValue(QmakeProjectManager::AndroidArchVar);
810

811
    AndroidToolChain *atc = static_cast<AndroidToolChain *>(tc);
812
    QString libgnustl = libGnuStl(arch, atc->ndkToolChainVersion());
813 814 815

    Utils::FileName readelfPath = AndroidConfigurations::instance().readelfPath(target->activeRunConfiguration()->abi().architecture(),
                                                                                atc->ndkToolChainVersion());
816
    const QmakeProjectManager::QmakeProject *const qmakeProject
817
            = qobject_cast<const QmakeProjectManager::QmakeProject *>(target->project());
818
    if (!qmakeProject || !version)
819
        return QVector<AndroidManager::Library>();
820
    QString qtLibsPath = version->qmakeProperty("QT_INSTALL_LIBS");
Orgad Shaneh's avatar
Orgad Shaneh committed
821
    if (!readelfPath.toFileInfo().exists())
822
        return QVector<AndroidManager::Library>();
Tobias Hunger's avatar
Tobias Hunger committed
823 824 825 826 827 828 829
    LibrariesMap mapLibs;
    QDir libPath;
    QDirIterator it(qtLibsPath, QStringList() << QLatin1String("*.so"), QDir::Files, QDirIterator::Subdirectories);
    while (it.hasNext()) {
        libPath = it.next();
        const QString library = libPath.absolutePath().mid(libPath.absolutePath().lastIndexOf(QLatin1Char('/')) + 1);
        mapLibs[library].dependencies = dependencies(readelfPath, libPath.absolutePath());
BogDan Vatra's avatar
BogDan Vatra committed
830 831
    }

832
    const QString library = libgnustl.mid(libgnustl.lastIndexOf(QLatin1Char('/')) + 1);
Nikolai Kosjar's avatar
Nikolai Kosjar committed
833
    mapLibs[library] = Library();
834

Tobias Hunger's avatar
Tobias Hunger committed
835
    // clean dependencies
836 837 838
    const LibrariesMap::Iterator lend = mapLibs.end();
    for (LibrariesMap::Iterator lit = mapLibs.begin(); lit != lend; ++lit) {
        Library &library = lit.value();
Tobias Hunger's avatar
Tobias Hunger committed
839
        int it = 0;
840 841 842 843
        while (it < library.dependencies.size()) {
            const QString &dependName = library.dependencies[it];
            if (!mapLibs.contains(dependName) && dependName.startsWith(QLatin1String("lib")) && dependName.endsWith(QLatin1String(".so")))
                library.dependencies.removeAt(it);
844
            else
Tobias Hunger's avatar
Tobias Hunger committed
845
                ++it;
BogDan Vatra's avatar
BogDan Vatra committed
846
        }
847 848
        if (library.dependencies.isEmpty())
            library.level = 0;
BogDan Vatra's avatar
BogDan Vatra committed
849 850
    }

Tobias Hunger's avatar
Tobias Hunger committed
851 852
    QVector<Library> qtLibraries;
    // calculate the level for every library
853 854 855 856
    for (LibrariesMap::Iterator lit = mapLibs.begin(); lit != lend; ++lit) {
        Library &library = lit.value();
        const QString &key = lit.key();
        if (library.level < 0)
Tobias Hunger's avatar
Tobias Hunger committed
857
           setLibraryLevel(key, mapLibs);
BogDan Vatra's avatar
BogDan Vatra committed
858

859 860
        if (library.name.isEmpty() && key.startsWith(QLatin1String("lib")) && key.endsWith(QLatin1String(".so")))
            library.name = key.mid(3, key.length() - 6);
BogDan Vatra's avatar
BogDan Vatra committed
861

862 863
        for (int it = 0; it < library.dependencies.size(); it++) {
            const QString &libName = library.dependencies[it];
Tobias Hunger's avatar
Tobias Hunger committed
864
            if (libName.startsWith(QLatin1String("lib")) && libName.endsWith(QLatin1String(".so")))
865
                library.dependencies[it] = libName.mid(3, libName.length() - 6);
Tobias Hunger's avatar
Tobias Hunger committed
866
        }
867
        qtLibraries.push_back(library);
BogDan Vatra's avatar
BogDan Vatra committed
868
    }
Tobias Hunger's avatar
Tobias Hunger committed
869
    qSort(qtLibraries.begin(), qtLibraries.end(), qtLibrariesLessThan);
870 871 872 873 874 875 876 877 878 879

    return qtLibraries;

}

QStringList AndroidManager::availableQtLibs(ProjectExplorer::Target *target)
{
    QStringList libs;
    QVector<Library> qtLibraries = availableQtLibsWithDependencies(target);
    foreach (Library lib, qtLibraries)
Tobias Hunger's avatar
Tobias Hunger committed
880 881
        libs.push_back(lib.name);
    return libs;
BogDan Vatra's avatar
BogDan Vatra committed
882 883
}

Tobias Hunger's avatar
Tobias Hunger committed
884
QStringList AndroidManager::qtLibs(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
885
{
Tobias Hunger's avatar
Tobias Hunger committed
886
    return libsXml(target, QLatin1String("qt_libs"));
BogDan Vatra's avatar
BogDan Vatra committed
887 888
}

Tobias Hunger's avatar
Tobias Hunger committed
889
bool AndroidManager::setQtLibs(ProjectExplorer::Target *target, const QStringList &libs)
BogDan Vatra's avatar
BogDan Vatra committed
890
{
Tobias Hunger's avatar
Tobias Hunger committed
891
    return setLibsXml(target, libs, QLatin1String("qt_libs"));
BogDan Vatra's avatar
BogDan Vatra committed
892 893
}

894 895 896 897 898 899 900 901 902 903
bool AndroidManager::setBundledInAssets(ProjectExplorer::Target *target, const QStringList &fileList)
{
    return setLibsXml(target, fileList, QLatin1String("bundled_in_assets"));
}

bool AndroidManager::setBundledInLib(ProjectExplorer::Target *target, const QStringList &fileList)
{
    return setLibsXml(target, fileList, QLatin1String("bundled_in_lib"));
}

Tobias Hunger's avatar
Tobias Hunger committed
904
QStringList AndroidManager::availablePrebundledLibs(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
905
{
Tobias Hunger's avatar
Tobias Hunger committed
906
    QStringList libs;
907 908
    QmakeProjectManager::QmakeProject *qmakeProject = qobject_cast<QmakeProjectManager::QmakeProject *>(target->project());
    if (!qmakeProject)
Tobias Hunger's avatar
Tobias Hunger committed
909
        return libs;
BogDan Vatra's avatar
BogDan Vatra committed
910

911
    foreach (QmakeProjectManager::QmakeProFileNode *node, qmakeProject->allProFiles())
912
        if (node->projectType() == QmakeProjectManager::LibraryTemplate)
913
            libs << node->targetInformation().target;
Tobias Hunger's avatar
Tobias Hunger committed
914
    return libs;
BogDan Vatra's avatar
BogDan Vatra committed
915 916
}

Tobias Hunger's avatar
Tobias Hunger committed
917
QStringList AndroidManager::prebundledLibs(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
918
{
Tobias Hunger's avatar
Tobias Hunger committed
919
    return libsXml(target, QLatin1String("bundled_libs"));
BogDan Vatra's avatar
BogDan Vatra committed
920 921
}

Tobias Hunger's avatar
Tobias Hunger committed
922
bool AndroidManager::setPrebundledLibs(ProjectExplorer::Target *target, const QStringList &libs)
BogDan Vatra's avatar
BogDan Vatra committed
923
{
Tobias Hunger's avatar
Tobias Hunger committed
924
    return setLibsXml(target, libs, QLatin1String("bundled_libs"));
BogDan Vatra's avatar
BogDan Vatra committed
925 926
}

Tobias Hunger's avatar
Tobias Hunger committed
927
bool AndroidManager::openLibsXml(ProjectExplorer::Target *target, QDomDocument &doc)
BogDan Vatra's avatar
BogDan Vatra committed
928
{
929
    return openXmlFile(doc, libsPath(target));
BogDan Vatra's avatar
BogDan Vatra committed
930 931
}

Tobias Hunger's avatar
Tobias Hunger committed
932
bool AndroidManager::saveLibsXml(ProjectExplorer::Target *target, QDomDocument &doc)
BogDan Vatra's avatar
BogDan Vatra committed
933
{
Tobias Hunger's avatar
Tobias Hunger committed
934
    return saveXmlFile(target, doc, libsPath(target));
BogDan Vatra's avatar
BogDan Vatra committed
935 936
}

Tobias Hunger's avatar
Tobias Hunger committed
937
void AndroidManager::raiseError(const QString &reason)
BogDan Vatra's avatar
BogDan Vatra committed
938
{
939
    QMessageBox::critical(0, tr("Error creating Android templates."), reason);
BogDan Vatra's avatar
BogDan Vatra committed
940 941
}

942
QString AndroidManager::loadLocal(ProjectExplorer::Target *target, int apiLevel, ItemType item, const QString &attribute)
BogDan Vatra's avatar
BogDan Vatra committed
943
{
Tobias Hunger's avatar
Tobias Hunger committed
944 945 946
    QString itemType;
    if (item == Lib)
        itemType = QLatin1String("lib");
947 948 949
    else if (item == BundledFile)
        itemType = QLatin1String("bundled");
    else // Jar or BundledJar
Tobias Hunger's avatar
Tobias Hunger committed
950 951 952
        itemType = QLatin1String("jar");

    QString localLibs;