androidmanager.cpp 33.9 KB
Newer Older
BogDan Vatra's avatar
BogDan Vatra committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 BogDan Vatra <bog_dan_ro@yahoo.com>
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

Tobias Hunger's avatar
Tobias Hunger committed
33
#include "androidmanager.h"
BogDan Vatra's avatar
BogDan Vatra committed
34 35 36 37 38 39 40
#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
41 42 43
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
BogDan Vatra's avatar
BogDan Vatra committed
44 45 46 47
#include <qt4projectmanager/qt4nodes.h>
#include <qt4projectmanager/qt4project.h>
#include <qt4projectmanager/qt4projectmanagerconstants.h>
#include <qt4projectmanager/qt4buildconfiguration.h>
48
#include <qtsupport/customexecutablerunconfiguration.h>
Tobias Hunger's avatar
Tobias Hunger committed
49 50
#include <qtsupport/qtprofileinformation.h>
#include <qtsupport/qtsupportconstants.h>
BogDan Vatra's avatar
BogDan Vatra committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68

#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)
    {
69
        QRegExp legalChars(QLatin1String("[a-zA-Z0-9_\\.]"));
BogDan Vatra's avatar
BogDan Vatra committed
70 71 72 73 74 75 76 77 78 79 80 81

        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
82
bool AndroidManager::supportsAndroid(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
83
{
Tobias Hunger's avatar
Tobias Hunger committed
84 85 86
    if (!qobject_cast<Qt4ProjectManager::Qt4Project *>(target->project()))
        return false;
    QtSupport::BaseQtVersion *version = QtSupport::QtProfileInformation::qtVersion(target->profile());
87
    return version && version->platformName() == QLatin1String(QtSupport::Constants::ANDROID_PLATFORM);
Tobias Hunger's avatar
Tobias Hunger committed
88
}
BogDan Vatra's avatar
BogDan Vatra committed
89

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

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

Tobias Hunger's avatar
Tobias Hunger committed
109
QString AndroidManager::applicationName(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
110
{
Tobias Hunger's avatar
Tobias Hunger committed
111 112 113 114 115 116 117 118 119 120 121
    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
122

Tobias Hunger's avatar
Tobias Hunger committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
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
140

Tobias Hunger's avatar
Tobias Hunger committed
141 142 143 144 145 146 147 148 149 150 151 152 153
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
154

Tobias Hunger's avatar
Tobias Hunger committed
155 156 157 158 159 160 161 162 163 164 165
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
166

Tobias Hunger's avatar
Tobias Hunger committed
167 168 169 170
    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
171
    }
Tobias Hunger's avatar
Tobias Hunger committed
172 173

    return saveManifest(target, doc);
BogDan Vatra's avatar
BogDan Vatra committed
174 175
}

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

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

Tobias Hunger's avatar
Tobias Hunger committed
190
int AndroidManager::versionCode(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
191
{
Tobias Hunger's avatar
Tobias Hunger committed
192 193 194 195 196 197
    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
198

Tobias Hunger's avatar
Tobias Hunger committed
199 200 201 202 203 204 205 206 207
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
208

Tobias Hunger's avatar
Tobias Hunger committed
209 210 211 212 213 214 215 216
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
217

Tobias Hunger's avatar
Tobias Hunger committed
218 219 220 221 222 223 224 225
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
226 227
}

Tobias Hunger's avatar
Tobias Hunger committed
228
QString AndroidManager::targetSDK(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
229
{
Tobias Hunger's avatar
Tobias Hunger committed
230 231 232 233 234 235 236 237 238 239 240 241
    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
242

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

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

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

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

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

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

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

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

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

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

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

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

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

Tobias Hunger's avatar
Tobias Hunger committed
309 310 311 312 313 314 315 316 317 318 319 320
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
321

Tobias Hunger's avatar
Tobias Hunger committed
322 323 324 325 326 327 328 329 330 331 332
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
333 334
        }
    }
Tobias Hunger's avatar
Tobias Hunger committed
335 336 337
    apps.sort();
    return apps;
}
BogDan Vatra's avatar
BogDan Vatra committed
338

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

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

Tobias Hunger's avatar
Tobias Hunger committed
369
QString AndroidManager::targetApplicationPath(ProjectExplorer::Target *target)
BogDan Vatra's avatar
BogDan Vatra committed
370
{
Tobias Hunger's avatar
Tobias Hunger committed
371 372 373 374 375 376 377 378 379 380
    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)
381
                    return proFile->targetInformation().buildDir + QLatin1Char('/') + proFile->targetInformation().target;
Tobias Hunger's avatar
Tobias Hunger committed
382 383 384 385 386 387 388
            } 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
389 390
}

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

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

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

Tobias Hunger's avatar
Tobias Hunger committed
433 434
    if (!forceUpdate && androidPath.toFileInfo().exists()
            && manifestPath(target).toFileInfo().exists()
BogDan Vatra's avatar
BogDan Vatra committed
435 436
            && src.toFileInfo().exists()
            && res.toFileInfo().exists())
Tobias Hunger's avatar
Tobias Hunger committed
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
        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 {
454 455
            Utils::FileName dstFile = androidPath;
            dstFile.appendPath(it.filePath().mid(pos));
Tobias Hunger's avatar
Tobias Hunger committed
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 489 490
            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
491 492
}

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

    // clean previous build
    QProcess androidProc;
    androidProc.setWorkingDirectory(androidDir);
Tobias Hunger's avatar
Tobias Hunger committed
500 501
    androidProc.start(AndroidConfigurations::instance().antToolPath().toString(),
                      QStringList() << QLatin1String("clean"));
BogDan Vatra's avatar
BogDan Vatra committed
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 551 552
    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
553
    androidProc.start(AndroidConfigurations::instance().androidToolPath().toString(), params);
BogDan Vatra's avatar
BogDan Vatra committed
554 555 556 557
    if (!androidProc.waitForFinished(-1))
        androidProc.terminate();
}

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

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

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

Tobias Hunger's avatar
Tobias Hunger committed
576 577 578 579 580 581 582 583 584 585 586 587
QStringList AndroidManager::availableQtLibs(ProjectExplorer::Target *target)
{
    QtSupport::BaseQtVersion *version = QtSupport::QtProfileInformation::qtVersion(target->profile());
    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;
588
    QString qtLibsPath = version->qmakeProperty("QT_INSTALL_LIBS");
Tobias Hunger's avatar
Tobias Hunger committed
589 590 591 592 593
    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
594
        }
Tobias Hunger's avatar
Tobias Hunger committed
595 596
        libs.sort();
        return libs;
BogDan Vatra's avatar
BogDan Vatra committed
597
    }
Tobias Hunger's avatar
Tobias Hunger committed
598 599 600 601 602 603 604
    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
605 606
    }

Tobias Hunger's avatar
Tobias Hunger committed
607 608 609 610 611 612 613 614 615
    // 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
616 617
            }
        }
Tobias Hunger's avatar
Tobias Hunger committed
618 619
        if (!mapLibs[key].dependencies.size())
            mapLibs[key].level = 0;
BogDan Vatra's avatar
BogDan Vatra committed
620 621
    }

Tobias Hunger's avatar
Tobias Hunger committed
622 623 624 625 626
    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
627

Tobias Hunger's avatar
Tobias Hunger committed
628 629
        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
630

Tobias Hunger's avatar
Tobias Hunger committed
631 632 633 634 635 636
        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
637
    }
Tobias Hunger's avatar
Tobias Hunger committed
638 639 640
    qSort(qtLibraries.begin(), qtLibraries.end(), qtLibrariesLessThan);
    foreach (Library lib, qtLibraries) {
        libs.push_back(lib.name);
BogDan Vatra's avatar
BogDan Vatra committed
641
    }
Tobias Hunger's avatar
Tobias Hunger committed
642
    return libs;
BogDan Vatra's avatar
BogDan Vatra committed
643 644
}

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

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

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

Tobias Hunger's avatar
Tobias Hunger committed
662 663 664 665
    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
666 667
}

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

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

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

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

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

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

    QString localLibs;
BogDan Vatra's avatar
BogDan Vatra committed
702 703

    QDomDocument doc;
Tobias Hunger's avatar
Tobias Hunger committed
704 705 706 707 708 709 710 711 712 713 714
    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
715
        }
Tobias Hunger's avatar
Tobias Hunger committed
716
        element = element.nextSiblingElement(QLatin1String("version"));
BogDan Vatra's avatar
BogDan Vatra committed
717 718
    }

Tobias Hunger's avatar
Tobias Hunger committed
719 720 721 722 723 724 725 726 727 728 729 730 731
    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
732 733
            }
        }
Tobias Hunger's avatar
Tobias Hunger committed
734
        element = element.nextSiblingElement(QLatin1String("lib"));
BogDan Vatra's avatar
BogDan Vatra committed
735
    }
Tobias Hunger's avatar
Tobias Hunger committed
736
    return localLibs;
BogDan Vatra's avatar
BogDan Vatra committed
737 738
}

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

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

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

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

Tobias Hunger's avatar
Tobias Hunger committed
761 762 763 764
    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
765
    }
Tobias Hunger's avatar
Tobias Hunger committed
766
    return f.write(doc.toByteArray(4)) >= 0;
BogDan Vatra's avatar
BogDan Vatra committed
767 768
}

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

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

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

Tobias Hunger's avatar
Tobias Hunger committed
793
QStringList AndroidManager::libsXml(ProjectExplorer::Target *target, const QString &tag)
BogDan Vatra's avatar
BogDan Vatra committed
794 795 796
{
    QStringList libs;
    QDomDocument doc;
Tobias Hunger's avatar
Tobias Hunger committed
797
    if (!openLibsXml(target, doc))
BogDan Vatra's avatar
BogDan Vatra committed
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
        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
814
bool AndroidManager::setLibsXml(ProjectExplorer::Target *target, const QStringList &libs, const QString &tag)
BogDan Vatra's avatar
BogDan Vatra committed
815 816
{
    QDomDocument doc;
Tobias Hunger's avatar
Tobias Hunger committed
817
    if (!openLibsXml(target, doc))
BogDan Vatra's avatar
BogDan Vatra committed
818 819 820 821 822 823 824 825 826 827 828 829 830
        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
831
            return saveLibsXml(target, doc);
BogDan Vatra's avatar
BogDan Vatra committed
832 833 834 835 836 837 838
        }
        arrayElem = arrayElem.nextSiblingElement(QLatin1String("array"));
    }
    return false;
}


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

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

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

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

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

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

Tobias Hunger's avatar
Tobias Hunger committed
866 867 868 869 870 871 872 873
    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
874 875
}

Tobias Hunger's avatar
Tobias Hunger committed
876
int AndroidManager::setLibraryLevel(const QString &library, LibrariesMap &mapLibs)
BogDan Vatra's avatar
BogDan Vatra committed
877
{
Tobias Hunger's avatar
Tobias Hunger committed
878 879 880 881 882 883 884 885 886
    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
887

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

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

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

} // namespace Internal
} // namespace Qt4ProjectManager