androidmanager.cpp 33.7 KB
Newer Older
BogDan Vatra's avatar
BogDan Vatra committed
1 2 3 4 5 6
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 BogDan Vatra <bog_dan_ro@yahoo.com>
**
Eike Ziller's avatar
Eike Ziller committed
7
** Contact: http://www.qt-project.org/
BogDan Vatra's avatar
BogDan Vatra committed
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
**
**
** GNU Lesser General Public License Usage
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/

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

Tobias Hunger's avatar
Tobias Hunger committed
39 40 41
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
BogDan Vatra's avatar
BogDan Vatra committed
42 43 44 45
#include <qt4projectmanager/qt4nodes.h>
#include <qt4projectmanager/qt4project.h>
#include <qt4projectmanager/qt4projectmanagerconstants.h>
#include <qt4projectmanager/qt4buildconfiguration.h>
46
#include <qtsupport/customexecutablerunconfiguration.h>
Tobias Hunger's avatar
Tobias Hunger committed
47
#include <qtsupport/qtkitinformation.h>
Tobias Hunger's avatar
Tobias Hunger committed
48
#include <qtsupport/qtsupportconstants.h>
BogDan Vatra's avatar
BogDan Vatra committed
49 50 51 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");

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

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

        return packageName;
    }
} // anonymous namespace

namespace Android {
namespace Internal {

Tobias Hunger's avatar
Tobias Hunger committed
80
bool AndroidManager::supportsAndroid(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
81
{
Tobias Hunger's avatar
Tobias Hunger committed
82 83
    if (!qobject_cast<Qt4ProjectManager::Qt4Project *>(target->project()))
        return false;
Tobias Hunger's avatar
Tobias Hunger committed
84
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit());
85
    return version && version->platformName() == QLatin1String(QtSupport::Constants::ANDROID_PLATFORM);
Tobias Hunger's avatar
Tobias Hunger committed
86
}
BogDan Vatra's avatar
BogDan Vatra committed
87

Tobias Hunger's avatar
Tobias Hunger committed
88 89 90 91 92 93 94
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
95 96
}

Tobias Hunger's avatar
Tobias Hunger committed
97
bool AndroidManager::setPackageName(ProjectExplorer::Target *target, const QString &name)
BogDan Vatra's avatar
BogDan Vatra committed
98
{
Tobias Hunger's avatar
Tobias Hunger committed
99 100 101 102 103 104
    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
105 106
}

Tobias Hunger's avatar
Tobias Hunger committed
107
QString AndroidManager::applicationName(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
108
{
Tobias Hunger's avatar
Tobias Hunger committed
109 110 111 112 113 114 115 116 117 118 119
    QDomDocument doc;
    if (!openXmlFile(target, doc, stringsPath(target)))
        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
120

Tobias Hunger's avatar
Tobias Hunger committed
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
bool AndroidManager::setApplicationName(ProjectExplorer::Target *target, const QString &name)
{
    QDomDocument doc;
    Utils::FileName path = stringsPath(target);
    if (!openXmlFile(target, doc, path))
        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
138

Tobias Hunger's avatar
Tobias Hunger committed
139 140 141 142 143 144 145 146 147 148 149 150 151
QStringList AndroidManager::permissions(ProjectExplorer::Target *target)
{
    QStringList per;
    QDomDocument doc;
    if (!openManifest(target, doc))
        return per;
    QDomElement permissionElem = doc.documentElement().firstChildElement(QLatin1String("uses-permission"));
    while (!permissionElem.isNull()) {
        per << permissionElem.attribute(QLatin1String("android:name"));
        permissionElem = permissionElem.nextSiblingElement(QLatin1String("uses-permission"));
    }
    return per;
}
BogDan Vatra's avatar
BogDan Vatra committed
152

Tobias Hunger's avatar
Tobias Hunger committed
153 154 155 156 157 158 159 160 161 162 163
bool AndroidManager::setPermissions(ProjectExplorer::Target *target, const QStringList &permissions)
{
    QDomDocument doc;
    if (!openManifest(target, doc))
        return false;
    QDomElement docElement = doc.documentElement();
    QDomElement permissionElem = docElement.firstChildElement(QLatin1String("uses-permission"));
    while (!permissionElem.isNull()) {
        docElement.removeChild(permissionElem);
        permissionElem = docElement.firstChildElement(QLatin1String("uses-permission"));
    }
BogDan Vatra's avatar
BogDan Vatra committed
164

Tobias Hunger's avatar
Tobias Hunger committed
165 166 167 168
    foreach (const QString &permission, permissions ) {
        permissionElem = doc.createElement(QLatin1String("uses-permission"));
        permissionElem.setAttribute(QLatin1String("android:name"), permission);
        docElement.appendChild(permissionElem);
BogDan Vatra's avatar
BogDan Vatra committed
169
    }
Tobias Hunger's avatar
Tobias Hunger committed
170 171

    return saveManifest(target, doc);
BogDan Vatra's avatar
BogDan Vatra committed
172 173
}

Tobias Hunger's avatar
Tobias Hunger committed
174
QString AndroidManager::intentName(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
175
{
Tobias Hunger's avatar
Tobias Hunger committed
176
    return packageName(target) + QLatin1Char('/') + activityName(target);
BogDan Vatra's avatar
BogDan Vatra committed
177 178
}

Tobias Hunger's avatar
Tobias Hunger committed
179
QString AndroidManager::activityName(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
180
{
Tobias Hunger's avatar
Tobias Hunger committed
181 182 183 184 185
    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
186 187
}

Tobias Hunger's avatar
Tobias Hunger committed
188
int AndroidManager::versionCode(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
189
{
Tobias Hunger's avatar
Tobias Hunger committed
190 191 192 193 194 195
    QDomDocument doc;
    if (!openManifest(target, doc))
        return 0;
    QDomElement manifestElem = doc.documentElement();
    return manifestElem.attribute(QLatin1String("android:versionCode")).toInt();
}
BogDan Vatra's avatar
BogDan Vatra committed
196

Tobias Hunger's avatar
Tobias Hunger committed
197 198 199 200 201 202 203 204 205
bool AndroidManager::setVersionCode(ProjectExplorer::Target *target, int version)
{
    QDomDocument doc;
    if (!openManifest(target, doc))
        return false;
    QDomElement manifestElem = doc.documentElement();
    manifestElem.setAttribute(QLatin1String("android:versionCode"), version);
    return saveManifest(target, doc);
}
BogDan Vatra's avatar
BogDan Vatra committed
206

Tobias Hunger's avatar
Tobias Hunger committed
207 208 209 210 211 212 213 214
QString AndroidManager::versionName(ProjectExplorer::Target *target)
{
    QDomDocument doc;
    if (!openManifest(target, doc))
        return QString();
    QDomElement manifestElem = doc.documentElement();
    return manifestElem.attribute(QLatin1String("android:versionName"));
}
BogDan Vatra's avatar
BogDan Vatra committed
215

Tobias Hunger's avatar
Tobias Hunger committed
216 217 218 219 220 221 222 223
bool AndroidManager::setVersionName(ProjectExplorer::Target *target, const QString &version)
{
    QDomDocument doc;
    if (!openManifest(target, doc))
        return false;
    QDomElement manifestElem = doc.documentElement();
    manifestElem.setAttribute(QLatin1String("android:versionName"), version);
    return saveManifest(target, doc);
BogDan Vatra's avatar
BogDan Vatra committed
224 225
}

Tobias Hunger's avatar
Tobias Hunger committed
226
QString AndroidManager::targetSDK(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
227
{
Tobias Hunger's avatar
Tobias Hunger committed
228 229 230 231 232 233 234 235 236 237 238 239
    if (!createAndroidTemplatesIfNecessary(target))
        return AndroidConfigurations::instance().bestMatch(QLatin1String("android-8"));
    QFile file(defaultPropertiesPath(target).toString());
    if (!file.open(QIODevice::ReadOnly))
        return AndroidConfigurations::instance().bestMatch(QLatin1String("android-8"));
    while (!file.atEnd()) {
        QByteArray line = file.readLine();
        if (line.startsWith("target="))
            return QString::fromLatin1(line.trimmed().mid(7));
    }
    return AndroidConfigurations::instance().bestMatch(QLatin1String("android-8"));
}
BogDan Vatra's avatar
BogDan Vatra committed
240

Tobias Hunger's avatar
Tobias Hunger committed
241 242 243 244 245
bool AndroidManager::setTargetSDK(ProjectExplorer::Target *target, const QString &sdk)
{
    updateTarget(target, sdk, applicationName(target));
    return true;
}
BogDan Vatra's avatar
BogDan Vatra committed
246

Tobias Hunger's avatar
Tobias Hunger committed
247 248 249
QIcon AndroidManager::highDpiIcon(ProjectExplorer::Target *target)
{
    return icon(target, HighDPI);
BogDan Vatra's avatar
BogDan Vatra committed
250 251
}

Tobias Hunger's avatar
Tobias Hunger committed
252
bool AndroidManager::setHighDpiIcon(ProjectExplorer::Target *target, const QString &iconFilePath)
BogDan Vatra's avatar
BogDan Vatra committed
253
{
Tobias Hunger's avatar
Tobias Hunger committed
254
    return setIcon(target, HighDPI, iconFilePath);
BogDan Vatra's avatar
BogDan Vatra committed
255 256
}

Tobias Hunger's avatar
Tobias Hunger committed
257
QIcon AndroidManager::mediumDpiIcon(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
258
{
Tobias Hunger's avatar
Tobias Hunger committed
259
    return icon(target, MediumDPI);
BogDan Vatra's avatar
BogDan Vatra committed
260 261
}

Tobias Hunger's avatar
Tobias Hunger committed
262
bool AndroidManager::setMediumDpiIcon(ProjectExplorer::Target *target, const QString &iconFilePath)
BogDan Vatra's avatar
BogDan Vatra committed
263
{
Tobias Hunger's avatar
Tobias Hunger committed
264
    return setIcon(target, MediumDPI, iconFilePath);
BogDan Vatra's avatar
BogDan Vatra committed
265 266
}

Tobias Hunger's avatar
Tobias Hunger committed
267
QIcon AndroidManager::lowDpiIcon(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
268
{
Tobias Hunger's avatar
Tobias Hunger committed
269
    return icon(target, LowDPI);
BogDan Vatra's avatar
BogDan Vatra committed
270 271
}

Tobias Hunger's avatar
Tobias Hunger committed
272
bool AndroidManager::setLowDpiIcon(ProjectExplorer::Target *target, const QString &iconFilePath)
BogDan Vatra's avatar
BogDan Vatra committed
273
{
Tobias Hunger's avatar
Tobias Hunger committed
274
    return setIcon(target, LowDPI, iconFilePath);
BogDan Vatra's avatar
BogDan Vatra committed
275 276
}

Tobias Hunger's avatar
Tobias Hunger committed
277
Utils::FileName AndroidManager::dirPath(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
278
{
Tobias Hunger's avatar
Tobias Hunger committed
279
    return Utils::FileName::fromString(target->project()->projectDirectory()).appendPath(AndroidDirName);
BogDan Vatra's avatar
BogDan Vatra committed
280 281
}

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

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

Tobias Hunger's avatar
Tobias Hunger committed
292 293 294
Utils::FileName AndroidManager::stringsPath(ProjectExplorer::Target *target)
{
    return dirPath(target).append(AndroidStringsFileName);
BogDan Vatra's avatar
BogDan Vatra committed
295 296
}

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

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

Tobias Hunger's avatar
Tobias Hunger committed
307 308 309 310 311 312 313 314 315 316 317 318
Utils::FileName AndroidManager::apkPath(ProjectExplorer::Target *target, BuildType buildType)
{
    return dirPath(target)
            .appendPath(QLatin1String("bin"))
            .appendPath(QString::fromLatin1("%1-%2.apk")
                        .arg(applicationName(target))
                        .arg(buildType == DebugBuild
                             ? QLatin1String("debug")
                             : (buildType == ReleaseBuildUnsigned)
                               ? QLatin1String("release-unsigned")
                               : QLatin1String("signed")));
}
BogDan Vatra's avatar
BogDan Vatra committed
319

Tobias Hunger's avatar
Tobias Hunger committed
320 321 322 323 324 325 326 327 328 329 330
QStringList AndroidManager::availableTargetApplications(ProjectExplorer::Target *target)
{
    QStringList apps;
    Qt4ProjectManager::Qt4Project *qt4Project = qobject_cast<Qt4ProjectManager::Qt4Project *>(target->project());
    foreach (Qt4ProjectManager::Qt4ProFileNode *proFile, qt4Project->applicationProFiles()) {
        if (proFile->projectType() == Qt4ProjectManager::ApplicationTemplate) {
            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
331 332
        }
    }
Tobias Hunger's avatar
Tobias Hunger committed
333 334 335
    apps.sort();
    return apps;
}
BogDan Vatra's avatar
BogDan Vatra committed
336

Tobias Hunger's avatar
Tobias Hunger committed
337 338 339 340 341 342 343 344 345 346 347 348 349
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
350

Tobias Hunger's avatar
Tobias Hunger committed
351 352 353 354 355 356 357 358 359 360
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
361
        }
Tobias Hunger's avatar
Tobias Hunger committed
362
        metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data"));
BogDan Vatra's avatar
BogDan Vatra committed
363
    }
Tobias Hunger's avatar
Tobias Hunger committed
364
    return false;
BogDan Vatra's avatar
BogDan Vatra committed
365 366
}

Tobias Hunger's avatar
Tobias Hunger committed
367
QString AndroidManager::targetApplicationPath(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
368
{
Tobias Hunger's avatar
Tobias Hunger committed
369 370 371 372 373 374 375 376 377 378
    QString selectedApp = targetApplication(target);
    if (selectedApp.isEmpty())
        return QString();
    Qt4ProjectManager::Qt4Project *qt4Project = qobject_cast<Qt4ProjectManager::Qt4Project *>(target->project());
    foreach (Qt4ProjectManager::Qt4ProFileNode *proFile, qt4Project->applicationProFiles()) {
        if (proFile->projectType() == Qt4ProjectManager::ApplicationTemplate) {
            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)
379
                    return proFile->targetInformation().buildDir + QLatin1Char('/') + proFile->targetInformation().target;
Tobias Hunger's avatar
Tobias Hunger committed
380 381 382 383 384 385 386
            } 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
387 388
}

Tobias Hunger's avatar
Tobias Hunger committed
389
bool AndroidManager::createAndroidTemplatesIfNecessary(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
390
{
Tobias Hunger's avatar
Tobias Hunger committed
391
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit());
Tobias Hunger's avatar
Tobias Hunger committed
392 393 394 395 396
    Qt4ProjectManager::Qt4Project *qt4Project = qobject_cast<Qt4ProjectManager::Qt4Project*>(target->project());
    if (!qt4Project || !qt4Project->rootProjectNode() || !version)
        return false;

    Utils::FileName javaSrcPath
397
            = Utils::FileName::fromString(version->qmakeProperty("QT_INSTALL_PREFIX"))
398
            .appendPath(QLatin1String("src/android/java"));
Tobias Hunger's avatar
Tobias Hunger committed
399 400 401 402 403 404
    QDir projectDir(qt4Project->projectDirectory());
    Utils::FileName androidPath = dirPath(target);

    QStringList m_ignoreFiles;
    bool forceUpdate = false;
    QDomDocument srcVersionDoc;
405 406 407
    Utils::FileName srcVersionPath = javaSrcPath;
    srcVersionPath.appendPath(QLatin1String("version.xml"));
    if (openXmlFile(target, srcVersionDoc, srcVersionPath, false)) {
Tobias Hunger's avatar
Tobias Hunger committed
408
        QDomDocument dstVersionDoc;
409 410 411
        Utils::FileName dstVersionPath=androidPath;
        dstVersionPath.appendPath(QLatin1String("version.xml"));
        if (openXmlFile(target, dstVersionDoc, dstVersionPath, false))
Tobias Hunger's avatar
Tobias Hunger committed
412 413 414 415 416 417 418 419 420 421 422 423 424 425
            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
426
    Utils::FileName src = androidPath;
427
    src.appendPath(QLatin1String("src"));
BogDan Vatra's avatar
BogDan Vatra committed
428
    Utils::FileName res = androidPath;
429
    res.appendPath(QLatin1String("res"));
BogDan Vatra's avatar
BogDan Vatra committed
430

Tobias Hunger's avatar
Tobias Hunger committed
431 432
    if (!forceUpdate && androidPath.toFileInfo().exists()
            && manifestPath(target).toFileInfo().exists()
BogDan Vatra's avatar
BogDan Vatra committed
433 434
            && src.toFileInfo().exists()
            && res.toFileInfo().exists())
Tobias Hunger's avatar
Tobias Hunger committed
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
        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 {
452 453
            Utils::FileName dstFile = androidPath;
            dstFile.appendPath(it.filePath().mid(pos));
Tobias Hunger's avatar
Tobias Hunger committed
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
            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())
        qt4Project->rootProjectNode()->addFiles(ProjectExplorer::UnknownFileType, androidFiles);

    QStringList sdks = AndroidConfigurations::instance().sdkTargets();
    if (sdks.isEmpty()) {
        raiseError(tr("No Qt for Android SDKs were found.\nPlease install at least one SDK."));
        return false;
    }
    updateTarget(target, AndroidConfigurations::instance().sdkTargets().at(0));
    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)
        QMessageBox::warning(0, tr("Warning"), tr("Android files have been updated automatically"));

    return true;
BogDan Vatra's avatar
BogDan Vatra committed
489 490
}

Tobias Hunger's avatar
Tobias Hunger committed
491
void AndroidManager::updateTarget(ProjectExplorer::Target *target, const QString &targetSDK, const QString &name)
BogDan Vatra's avatar
BogDan Vatra committed
492
{
Tobias Hunger's avatar
Tobias Hunger committed
493
    QString androidDir = dirPath(target).toString();
BogDan Vatra's avatar
BogDan Vatra committed
494 495 496 497

    // clean previous build
    QProcess androidProc;
    androidProc.setWorkingDirectory(androidDir);
Tobias Hunger's avatar
Tobias Hunger committed
498 499
    androidProc.start(AndroidConfigurations::instance().antToolPath().toString(),
                      QStringList() << QLatin1String("clean"));
BogDan Vatra's avatar
BogDan Vatra committed
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
    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++) {
            if (lines[i].contains("@ANDROID-")) {
                commentLines = targetSDKNumber < lines[i].mid(lines[i].lastIndexOf('-') + 1).toInt();
                comment = !comment;
                continue;
            }
            if (!comment)
                continue;
            if (commentLines) {
                if (!lines[i].trimmed().startsWith("//QtCreator")) {
                    lines[i] = "//QtCreator " + lines[i];
                    modified = true;
                }
            } else { if (lines[i].trimmed().startsWith("//QtCreator")) {
                    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;
Tobias Hunger's avatar
Tobias Hunger committed
551
    androidProc.start(AndroidConfigurations::instance().androidToolPath().toString(), params);
BogDan Vatra's avatar
BogDan Vatra committed
552 553 554 555
    if (!androidProc.waitForFinished(-1))
        androidProc.terminate();
}

Tobias Hunger's avatar
Tobias Hunger committed
556
Utils::FileName AndroidManager::localLibsRulesFilePath(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
557
{
Tobias Hunger's avatar
Tobias Hunger committed
558
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit());
Tobias Hunger's avatar
Tobias Hunger committed
559 560
    if (!version)
        return Utils::FileName();
561
    return Utils::FileName::fromString(version->qmakeProperty("QT_INSTALL_LIBS") + QLatin1String("/rules.xml"));
Tobias Hunger's avatar
Tobias Hunger committed
562
}
BogDan Vatra's avatar
BogDan Vatra committed
563

Tobias Hunger's avatar
Tobias Hunger committed
564 565 566 567
QString AndroidManager::loadLocalLibs(ProjectExplorer::Target *target, int apiLevel)
{
    return loadLocal(target, apiLevel, Lib);
}
BogDan Vatra's avatar
BogDan Vatra committed
568

Tobias Hunger's avatar
Tobias Hunger committed
569 570 571 572
QString AndroidManager::loadLocalJars(ProjectExplorer::Target *target, int apiLevel)
{
    return loadLocal(target, apiLevel, Jar);
}
BogDan Vatra's avatar
BogDan Vatra committed
573

Tobias Hunger's avatar
Tobias Hunger committed
574 575
QStringList AndroidManager::availableQtLibs(ProjectExplorer::Target *target)
{
Tobias Hunger's avatar
Tobias Hunger committed
576
    QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit());
Tobias Hunger's avatar
Tobias Hunger committed
577 578 579 580 581 582 583 584 585
    if (!target->activeRunConfiguration())
        return QStringList();

    Utils::FileName readelfPath = AndroidConfigurations::instance().readelfPath(target->activeRunConfiguration()->abi().architecture());
    QStringList libs;
    const Qt4ProjectManager::Qt4Project *const qt4Project
            = qobject_cast<const Qt4ProjectManager::Qt4Project *>(target->project());
    if (!qt4Project || !version)
        return libs;
586
    QString qtLibsPath = version->qmakeProperty("QT_INSTALL_LIBS");
Tobias Hunger's avatar
Tobias Hunger committed
587 588 589 590 591
    if (!readelfPath.toFileInfo().exists()) {
        QDirIterator libsIt(qtLibsPath, QStringList() << QLatin1String("libQt*.so"));
        while (libsIt.hasNext()) {
            libsIt.next();
            libs << libsIt.fileName().mid(3, libsIt.fileName().indexOf(QLatin1Char('.')) - 3);
BogDan Vatra's avatar
BogDan Vatra committed
592
        }
Tobias Hunger's avatar
Tobias Hunger committed
593 594
        libs.sort();
        return libs;
BogDan Vatra's avatar
BogDan Vatra committed
595
    }
Tobias Hunger's avatar
Tobias Hunger committed
596 597 598 599 600 601 602
    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
603 604
    }

Tobias Hunger's avatar
Tobias Hunger committed
605 606 607 608 609 610 611 612 613
    // clean dependencies
    foreach (const QString &key, mapLibs.keys()) {
        int it = 0;
        while (it < mapLibs[key].dependencies.size()) {
            const QString &dependName = mapLibs[key].dependencies[it];
            if (!mapLibs.keys().contains(dependName) && dependName.startsWith(QLatin1String("lib")) && dependName.endsWith(QLatin1String(".so"))) {
                mapLibs[key].dependencies.removeAt(it);
            } else {
                ++it;
BogDan Vatra's avatar
BogDan Vatra committed
614 615
            }
        }
Tobias Hunger's avatar
Tobias Hunger committed
616 617
        if (!mapLibs[key].dependencies.size())
            mapLibs[key].level = 0;
BogDan Vatra's avatar
BogDan Vatra committed
618 619
    }

Tobias Hunger's avatar
Tobias Hunger committed
620 621 622 623 624
    QVector<Library> qtLibraries;
    // calculate the level for every library
    foreach (const QString &key, mapLibs.keys()) {
        if (mapLibs[key].level < 0)
           setLibraryLevel(key, mapLibs);
BogDan Vatra's avatar
BogDan Vatra committed
625

Tobias Hunger's avatar
Tobias Hunger committed
626 627
        if (!mapLibs[key].name.length() && key.startsWith(QLatin1String("lib")) && key.endsWith(QLatin1String(".so")))
            mapLibs[key].name = key.mid(3, key.length() - 6);
BogDan Vatra's avatar
BogDan Vatra committed
628

Tobias Hunger's avatar
Tobias Hunger committed
629 630 631 632 633 634
        for (int it = 0; it < mapLibs[key].dependencies.size(); it++) {
            const QString &libName = mapLibs[key].dependencies[it];
            if (libName.startsWith(QLatin1String("lib")) && libName.endsWith(QLatin1String(".so")))
                mapLibs[key].dependencies[it] = libName.mid(3, libName.length() - 6);
        }
        qtLibraries.push_back(mapLibs[key]);
BogDan Vatra's avatar
BogDan Vatra committed
635
    }
Tobias Hunger's avatar
Tobias Hunger committed
636 637 638
    qSort(qtLibraries.begin(), qtLibraries.end(), qtLibrariesLessThan);
    foreach (Library lib, qtLibraries) {
        libs.push_back(lib.name);
BogDan Vatra's avatar
BogDan Vatra committed
639
    }
Tobias Hunger's avatar
Tobias Hunger committed
640
    return libs;
BogDan Vatra's avatar
BogDan Vatra committed
641 642
}

Tobias Hunger's avatar
Tobias Hunger committed
643
QStringList AndroidManager::qtLibs(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
644
{
Tobias Hunger's avatar
Tobias Hunger committed
645
    return libsXml(target, QLatin1String("qt_libs"));
BogDan Vatra's avatar
BogDan Vatra committed
646 647
}

Tobias Hunger's avatar
Tobias Hunger committed
648
bool AndroidManager::setQtLibs(ProjectExplorer::Target *target, const QStringList &libs)
BogDan Vatra's avatar
BogDan Vatra committed
649
{
Tobias Hunger's avatar
Tobias Hunger committed
650
    return setLibsXml(target, libs, QLatin1String("qt_libs"));
BogDan Vatra's avatar
BogDan Vatra committed
651 652
}

Tobias Hunger's avatar
Tobias Hunger committed
653
QStringList AndroidManager::availablePrebundledLibs(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
654
{
Tobias Hunger's avatar
Tobias Hunger committed
655 656 657 658
    QStringList libs;
    Qt4ProjectManager::Qt4Project *qt4Project = qobject_cast<Qt4ProjectManager::Qt4Project *>(target->project());
    if (!qt4Project)
        return libs;
BogDan Vatra's avatar
BogDan Vatra committed
659

Tobias Hunger's avatar
Tobias Hunger committed
660 661 662 663
    foreach (Qt4ProjectManager::Qt4ProFileNode *node, qt4Project->allProFiles())
        if (node->projectType() == Qt4ProjectManager::LibraryTemplate)
            libs << QLatin1String("lib") + node->targetInformation().target + QLatin1String(".so");
    return libs;
BogDan Vatra's avatar
BogDan Vatra committed
664 665
}

Tobias Hunger's avatar
Tobias Hunger committed
666
QStringList AndroidManager::prebundledLibs(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
667
{
Tobias Hunger's avatar
Tobias Hunger committed
668
    return libsXml(target, QLatin1String("bundled_libs"));
BogDan Vatra's avatar
BogDan Vatra committed
669 670
}

Tobias Hunger's avatar
Tobias Hunger committed
671
bool AndroidManager::setPrebundledLibs(ProjectExplorer::Target *target, const QStringList &libs)
BogDan Vatra's avatar
BogDan Vatra committed
672
{
Tobias Hunger's avatar
Tobias Hunger committed
673
    return setLibsXml(target, libs, QLatin1String("bundled_libs"));
BogDan Vatra's avatar
BogDan Vatra committed
674 675
}

Tobias Hunger's avatar
Tobias Hunger committed
676
bool AndroidManager::openLibsXml(ProjectExplorer::Target *target, QDomDocument &doc)
BogDan Vatra's avatar
BogDan Vatra committed
677
{
Tobias Hunger's avatar
Tobias Hunger committed
678
    return openXmlFile(target, doc, libsPath(target));
BogDan Vatra's avatar
BogDan Vatra committed
679 680
}

Tobias Hunger's avatar
Tobias Hunger committed
681
bool AndroidManager::saveLibsXml(ProjectExplorer::Target *target, QDomDocument &doc)
BogDan Vatra's avatar
BogDan Vatra committed
682
{
Tobias Hunger's avatar
Tobias Hunger committed
683
    return saveXmlFile(target, doc, libsPath(target));
BogDan Vatra's avatar
BogDan Vatra committed
684 685
}

Tobias Hunger's avatar
Tobias Hunger committed
686
void AndroidManager::raiseError(const QString &reason)
BogDan Vatra's avatar
BogDan Vatra committed
687
{
Tobias Hunger's avatar
Tobias Hunger committed
688
    QMessageBox::critical(0, tr("Error creating Android templates"), reason);
BogDan Vatra's avatar
BogDan Vatra committed
689 690
}

Tobias Hunger's avatar
Tobias Hunger committed
691
QString AndroidManager::loadLocal(ProjectExplorer::Target *target, int apiLevel, ItemType item)
BogDan Vatra's avatar
BogDan Vatra committed
692
{
Tobias Hunger's avatar
Tobias Hunger committed
693 694 695 696 697 698 699
    QString itemType;
    if (item == Lib)
        itemType = QLatin1String("lib");
    else
        itemType = QLatin1String("jar");

    QString localLibs;
BogDan Vatra's avatar
BogDan Vatra committed
700 701

    QDomDocument doc;
Tobias Hunger's avatar
Tobias Hunger committed
702 703 704 705 706 707 708 709 710 711 712
    if (!openXmlFile(target, doc, localLibsRulesFilePath(target)))
        return localLibs;

    QStringList libs;
    libs << qtLibs(target) << prebundledLibs(target);
    QDomElement element = doc.documentElement().firstChildElement(QLatin1String("platforms")).firstChildElement(itemType + QLatin1Char('s')).firstChildElement(QLatin1String("version"));
    while (!element.isNull()) {
        if (element.attribute(QLatin1String("value")).toInt() == apiLevel) {
            if (element.hasAttribute(QLatin1String("symlink")))
                apiLevel = element.attribute(QLatin1String("symlink")).toInt();
            break;
BogDan Vatra's avatar
BogDan Vatra committed
713
        }
Tobias Hunger's avatar
Tobias Hunger committed
714
        element = element.nextSiblingElement(QLatin1String("version"));
BogDan Vatra's avatar
BogDan Vatra committed
715 716
    }

Tobias Hunger's avatar
Tobias Hunger committed
717 718 719 720 721 722 723 724 725 726 727 728 729
    element = doc.documentElement().firstChildElement(QLatin1String("dependencies")).firstChildElement(QLatin1String("lib"));
    while (!element.isNull()) {
        if (libs.contains(element.attribute(QLatin1String("name")))) {
            QDomElement libElement = element.firstChildElement(QLatin1String("depends")).firstChildElement(itemType);
            while (!libElement.isNull()) {
                localLibs += libElement.attribute(QLatin1String("file")).arg(apiLevel) + QLatin1Char(':');
                libElement = libElement.nextSiblingElement(itemType);
            }

            libElement = element.firstChildElement(QLatin1String("replaces")).firstChildElement(itemType);
            while (!libElement.isNull()) {
                localLibs.replace(libElement.attribute(QLatin1String("file")).arg(apiLevel) + QLatin1Char(':'), QString());
                libElement = libElement.nextSiblingElement(itemType);
BogDan Vatra's avatar
BogDan Vatra committed
730 731
            }
        }
Tobias Hunger's avatar
Tobias Hunger committed
732
        element = element.nextSiblingElement(QLatin1String("lib"));
BogDan Vatra's avatar
BogDan Vatra committed
733
    }
Tobias Hunger's avatar
Tobias Hunger committed
734
    return localLibs;
BogDan Vatra's avatar
BogDan Vatra committed
735 736
}

Tobias Hunger's avatar
Tobias Hunger committed
737 738
bool AndroidManager::openXmlFile(ProjectExplorer::Target *target, QDomDocument &doc,
                                 const Utils::FileName &fileName, bool createAndroidTemplates)
BogDan Vatra's avatar
BogDan Vatra committed
739
{
Tobias Hunger's avatar
Tobias Hunger committed
740
    if (createAndroidTemplates && !createAndroidTemplatesIfNecessary(target))
BogDan Vatra's avatar
BogDan Vatra committed
741 742
        return false;

Tobias Hunger's avatar
Tobias Hunger committed
743 744
    QFile f(fileName.toString());
    if (!f.open(QIODevice::ReadOnly))
BogDan Vatra's avatar
BogDan Vatra committed
745 746
        return false;

Tobias Hunger's avatar
Tobias Hunger committed
747 748
    if (!doc.setContent(f.readAll())) {
        raiseError(tr("Can't parse '%1'").arg(fileName.toUserOutput()));
BogDan Vatra's avatar
BogDan Vatra committed
749 750
        return false;
    }
Tobias Hunger's avatar
Tobias Hunger committed
751
    return true;
BogDan Vatra's avatar
BogDan Vatra committed
752 753
}

Tobias Hunger's avatar
Tobias Hunger committed
754
bool AndroidManager::saveXmlFile(ProjectExplorer::Target *target, QDomDocument &doc, const Utils::FileName &fileName)
BogDan Vatra's avatar
BogDan Vatra committed
755
{
Tobias Hunger's avatar
Tobias Hunger committed
756 757
    if (!createAndroidTemplatesIfNecessary(target))
        return false;
BogDan Vatra's avatar
BogDan Vatra committed
758

Tobias Hunger's avatar
Tobias Hunger committed
759 760 761 762
    QFile f(fileName.toString());
    if (!f.open(QIODevice::WriteOnly)) {
        raiseError(tr("Can't open '%1'").arg(fileName.toUserOutput()));
        return false;
BogDan Vatra's avatar
BogDan Vatra committed
763
    }
Tobias Hunger's avatar
Tobias Hunger committed
764
    return f.write(doc.toByteArray(4)) >= 0;
BogDan Vatra's avatar
BogDan Vatra committed
765 766
}

Tobias Hunger's avatar
Tobias Hunger committed
767
bool AndroidManager::openManifest(ProjectExplorer::Target *target, QDomDocument &doc)
BogDan Vatra's avatar
BogDan Vatra committed
768
{
Tobias Hunger's avatar
Tobias Hunger committed
769
    return openXmlFile(target, doc, manifestPath(target));
BogDan Vatra's avatar
BogDan Vatra committed
770 771
}

Tobias Hunger's avatar
Tobias Hunger committed
772
bool AndroidManager::saveManifest(ProjectExplorer::Target *target, QDomDocument &doc)
BogDan Vatra's avatar
BogDan Vatra committed
773
{
Tobias Hunger's avatar
Tobias Hunger committed
774
    return saveXmlFile(target, doc, manifestPath(target));
BogDan Vatra's avatar
BogDan Vatra committed
775 776
}

Tobias Hunger's avatar
Tobias Hunger committed
777
QString AndroidManager::iconPath(ProjectExplorer::Target *target, AndroidManager::IconType type)
BogDan Vatra's avatar
BogDan Vatra committed
778 779 780
{
    switch (type) {
    case HighDPI:
Tobias Hunger's avatar
Tobias Hunger committed
781
        return dirPath(target).appendPath(QLatin1String("res/drawable-hdpi/icon.png")).toString();
BogDan Vatra's avatar
BogDan Vatra committed
782
    case MediumDPI:
Tobias Hunger's avatar
Tobias Hunger committed
783
        return dirPath(target).appendPath(QLatin1String("res/drawable-mdpi/icon.png")).toString();
BogDan Vatra's avatar
BogDan Vatra committed
784
    case LowDPI:
Tobias Hunger's avatar
Tobias Hunger committed
785 786 787
        return dirPath(target).appendPath(QLatin1String("res/drawable-ldpi/icon.png")).toString();
    default:
        return QString();
BogDan Vatra's avatar
BogDan Vatra committed
788 789 790
    }
}

Tobias Hunger's avatar
Tobias Hunger committed
791
QStringList AndroidManager::libsXml(ProjectExplorer::Target *target, const QString &tag)
BogDan Vatra's avatar
BogDan Vatra committed
792 793 794
{
    QStringList libs;
    QDomDocument doc;
Tobias Hunger's avatar
Tobias Hunger committed
795
    if (!openLibsXml(target, doc))
BogDan Vatra's avatar
BogDan Vatra committed
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
        return libs;
    QDomElement arrayElem = doc.documentElement().firstChildElement(QLatin1String("array"));
    while (!arrayElem.isNull()) {
        if (arrayElem.attribute(QLatin1String("name")) == tag) {
            arrayElem = arrayElem.firstChildElement(QLatin1String("item"));
            while (!arrayElem.isNull()) {
                libs << arrayElem.text();
                arrayElem = arrayElem.nextSiblingElement(QLatin1String("item"));
            }
            return libs;
        }
        arrayElem = arrayElem.nextSiblingElement(QLatin1String("array"));
    }
    return libs;
}

Tobias Hunger's avatar
Tobias Hunger committed
812
bool AndroidManager::setLibsXml(ProjectExplorer::Target *target, const QStringList &libs, const QString &tag)
BogDan Vatra's avatar
BogDan Vatra committed
813 814
{
    QDomDocument doc;
Tobias Hunger's avatar
Tobias Hunger committed
815
    if (!openLibsXml(target, doc))
BogDan Vatra's avatar
BogDan Vatra committed
816 817 818 819 820 821 822 823 824 825 826 827 828
        return false;
    QDomElement arrayElem = doc.documentElement().firstChildElement(QLatin1String("array"));
    while (!arrayElem.isNull()) {
        if (arrayElem.attribute(QLatin1String("name")) == tag) {
            doc.documentElement().removeChild(arrayElem);
            arrayElem = doc.createElement(QLatin1String("array"));
            arrayElem.setAttribute(QLatin1String("name"), tag);
            foreach (const QString &lib, libs) {
                QDomElement item = doc.createElement(QLatin1String("item"));
                item.appendChild(doc.createTextNode(lib));
                arrayElem.appendChild(item);
            }
            doc.documentElement().appendChild(arrayElem);
Tobias Hunger's avatar
Tobias Hunger committed
829
            return saveLibsXml(target, doc);
BogDan Vatra's avatar
BogDan Vatra committed
830 831 832 833 834 835 836
        }
        arrayElem = arrayElem.nextSiblingElement(QLatin1String("array"));
    }
    return false;
}


Tobias Hunger's avatar
Tobias Hunger committed
837
QIcon AndroidManager::icon(ProjectExplorer::Target *target, IconType type)
BogDan Vatra's avatar
BogDan Vatra committed
838
{
Tobias Hunger's avatar
Tobias Hunger committed
839
    return QIcon(iconPath(target, type));
BogDan Vatra's avatar
BogDan Vatra committed
840 841
}

Tobias Hunger's avatar
Tobias Hunger committed
842
bool AndroidManager::setIcon(ProjectExplorer::Target *target, IconType type, const QString &iconFileName)
BogDan Vatra's avatar
BogDan Vatra committed
843
{
Tobias Hunger's avatar
Tobias Hunger committed
844 845
    if (!QFileInfo(iconFileName).exists())
        return false;
BogDan Vatra's avatar
BogDan Vatra committed
846

Tobias Hunger's avatar
Tobias Hunger committed
847 848 849
    const QString path = iconPath(target, type);
    QFile::remove(path);
    return QFile::copy(iconFileName, path);
BogDan Vatra's avatar
BogDan Vatra committed
850 851
}

Tobias Hunger's avatar
Tobias Hunger committed
852
QStringList AndroidManager::dependencies(const Utils::FileName &readelfPath, const QString &lib)
BogDan Vatra's avatar
BogDan Vatra committed
853
{
Tobias Hunger's avatar
Tobias Hunger committed
854
    QStringList libs;
BogDan Vatra's avatar
BogDan Vatra committed
855

Tobias Hunger's avatar
Tobias Hunger committed
856 857
    QProcess readelfProc;
    readelfProc.start(readelfPath.toString(), QStringList() << QLatin1String("-d") << QLatin1String("-W") << lib);
BogDan Vatra's avatar
BogDan Vatra committed
858

Tobias Hunger's avatar
Tobias Hunger committed
859 860 861 862
    if (!readelfProc.waitForFinished(-1)) {
        readelfProc.terminate();
        return libs;
    }
BogDan Vatra's avatar
BogDan Vatra committed
863

Tobias Hunger's avatar
Tobias Hunger committed
864 865 866 867 868 869 870 871
    QList<QByteArray> lines = readelfProc.readAll().trimmed().split('\n');
    foreach (const QByteArray &line, lines) {
        if (line.contains("(NEEDED)") && line.contains("Shared library:") ) {
            const int pos = line.lastIndexOf('[') + 1;
            libs << QString::fromLatin1(line.mid(pos, line.lastIndexOf(']') - pos));
        }
    }
    return libs;
BogDan Vatra's avatar
BogDan Vatra committed
872 873
}

Tobias Hunger's avatar
Tobias Hunger committed
874
int AndroidManager::setLibraryLevel(const QString &library, LibrariesMap &mapLibs)
BogDan Vatra's avatar
BogDan Vatra committed
875
{
Tobias Hunger's avatar
Tobias Hunger committed
876 877 878 879 880 881 882 883 884
    int maxlevel = mapLibs[library].level;
    if (maxlevel > 0)
        return maxlevel;
    foreach (QString lib, mapLibs[library].dependencies) {
        foreach (const QString &key, mapLibs.keys()) {
            if (library == key)
                continue;
            if (key == lib) {
                int libLevel = mapLibs[key].level;
BogDan Vatra's avatar
BogDan Vatra committed
885

Tobias Hunger's avatar
Tobias Hunger committed
886 887
                if (libLevel < 0)
                    libLevel = setLibraryLevel(key, mapLibs);
BogDan Vatra's avatar
BogDan Vatra committed
888

Tobias Hunger's avatar
Tobias Hunger committed
889 890 891 892 893
                if (libLevel > maxlevel)
                    maxlevel = libLevel;
                break;
            }
        }
BogDan Vatra's avatar
BogDan Vatra committed
894
    }
Tobias Hunger's avatar
Tobias Hunger committed
895 896 897
    if (mapLibs[library].level < 0)
        mapLibs[library].level = maxlevel + 1;
    return maxlevel + 1;
BogDan Vatra's avatar
BogDan Vatra committed
898 899
}

Tobias Hunger's avatar
Tobias Hunger committed
900
bool AndroidManager::qtLibrariesLessThan(const Library &a, const Library &b)
BogDan Vatra's avatar
BogDan Vatra committed
901
{
Tobias Hunger's avatar
Tobias Hunger committed
902 903 904
    if (a.level == b.level)
        return a.name < b.name;
    return a.level < b.level;
BogDan Vatra's avatar
BogDan Vatra committed
905 906 907 908
}

} // namespace Internal
} // namespace Qt4ProjectManager