| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2015 - ROLI Ltd.
 - 
 -    Permission is granted to use this software under the terms of either:
 -    a) the GPL v2 (or any later version)
 -    b) the Affero GPL v3
 - 
 -    Details of these licenses can be found at: www.gnu.org/licenses
 - 
 -    JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
 -    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 -    A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 - 
 -    ------------------------------------------------------------------------------
 - 
 -    To release a closed-source product which uses JUCE, commercial licenses are
 -    available: visit www.juce.com for more information.
 - 
 -   ==============================================================================
 - */
 - 
 - class AndroidStudioProjectExporter  : public AndroidProjectExporterBase
 - {
 - public:
 -     //==============================================================================
 -     static const char* getName()                { return "Android Studio"; }
 -     static const char* getValueTreeTypeName()   { return "ANDROIDSTUDIO"; }
 - 
 -     static AndroidStudioProjectExporter* createForSettings (Project& project, const ValueTree& settings)
 -     {
 -         if (settings.hasType (getValueTreeTypeName()))
 -             return new AndroidStudioProjectExporter (project, settings);
 - 
 -         return nullptr;
 -     }
 - 
 -     //==============================================================================
 -     AndroidStudioProjectExporter (Project& p, const ValueTree& t)
 -         : AndroidProjectExporterBase (p, t),
 -           androidStudioExecutable (findAndroidStudioExecutable())
 -     {
 -         name = getName();
 - 
 -         if (getTargetLocationString().isEmpty())
 -             getTargetLocationValue() = getDefaultBuildsRootFolder() + "AndroidStudio";
 -     }
 - 
 -     //==============================================================================
 -     bool canLaunchProject() override
 -     {
 -         return androidStudioExecutable.exists();
 -     }
 - 
 -     bool launchProject() override
 -     {
 -         if (! androidStudioExecutable.exists())
 -         {
 -             jassertfalse;
 -             return false;
 -         }
 - 
 -         const File targetFolder (getTargetFolder());
 - 
 -         // we have to surround the path with extra quotes, otherwise Android Studio
 -         // will choke if there are any space characters in the path.
 -         return androidStudioExecutable.startAsProcess ("\"" + targetFolder.getFullPathName() + "\"");
 -     }
 - 
 -     void createExporterProperties (PropertyListBuilder& props) override
 -     {
 -         AndroidProjectExporterBase::createExporterProperties (props);
 - 
 -         props.add (new TextPropertyComponent (getNDKPlatformVersionValue(), "NDK Platform Version", 32, false),
 -                    "The value to use for android$user.ndk.platformVersion in Gradle");
 - 
 -         props.add (new TextPropertyComponent (getBuildToolsVersionValue(), "Build Tools Version", 32, false),
 -                    "The version of build tools use for build tools in Gradle");
 -     }
 - 
 -     Value getNDKPlatformVersionValue()         { return getSetting (Ids::androidNdkPlatformVersion); }
 -     String getNDKPlatformVersionString() const { return settings [Ids::androidNdkPlatformVersion]; }
 - 
 -     Value getBuildToolsVersionValue()          { return getSetting (Ids::buildToolsVersion); }
 -     String getBuildToolsVersionString() const  { return settings [Ids::buildToolsVersion]; }
 - 
 -     void removeOldFiles (const File& targetFolder) const
 -     {
 -         targetFolder.getChildFile ("app/src").deleteRecursively();
 -         targetFolder.getChildFile ("app/build").deleteRecursively();
 -         targetFolder.getChildFile ("app/build.gradle").deleteFile();
 -         targetFolder.getChildFile ("gradle").deleteRecursively();
 -         targetFolder.getChildFile ("local.properties").deleteFile();
 -         targetFolder.getChildFile ("settings.gradle").deleteFile();
 -     }
 - 
 -     void create (const OwnedArray<LibraryModule>& modules) const override
 -     {
 -         const File targetFolder (getTargetFolder());
 - 
 -         removeOldFiles (targetFolder);
 - 
 -         {
 -             const String package (getActivityClassPackage());
 -             const String path (package.replaceCharacter ('.', File::separator));
 -             const File javaTarget (targetFolder.getChildFile ("app/src/main/java").getChildFile (path));
 - 
 -             copyActivityJavaFiles (modules, javaTarget, package);
 -         }
 - 
 -         writeSettingsDotGradle       (targetFolder);
 -         writeLocalDotProperties      (targetFolder);
 -         writeBuildDotGradleRoot      (targetFolder);
 -         writeBuildDotGradleApp       (targetFolder);
 -         writeGradleWrapperProperties (targetFolder);
 -         writeAndroidManifest         (targetFolder);
 -         writeStringsXML              (targetFolder);
 -         writeAppIcons                (targetFolder);
 - 
 -         createSourceSymlinks         (targetFolder);
 -     }
 - 
 -     static File findAndroidStudioExecutable()
 -     {
 -        #if JUCE_WINDOWS
 -         const File defaultInstallation ("C:\\Program Files\\Android\\Android Studio\\bin");
 - 
 -         if (defaultInstallation.exists())
 -         {
 -             {
 -                 const File studio64 = defaultInstallation.getChildFile ("studio64.exe");
 - 
 -                 if (studio64.existsAsFile())
 -                     return studio64;
 -             }
 - 
 -             {
 -                 const File studio = defaultInstallation.getChildFile ("studio.exe");
 - 
 -                 if (studio.existsAsFile())
 -                     return studio;
 -             }
 -         }
 -       #elif JUCE_MAC
 -        const File defaultInstallation ("/Applications/Android Studio.app");
 - 
 -        if (defaultInstallation.exists())
 -            return defaultInstallation;
 -       #endif
 - 
 -         return File::nonexistent;
 -     }
 - 
 - protected:
 -     //==============================================================================
 -     class AndroidStudioBuildConfiguration  : public BuildConfiguration
 -     {
 -     public:
 -         AndroidStudioBuildConfiguration (Project& p, const ValueTree& settings, const ProjectExporter& e)
 -             : BuildConfiguration (p, settings, e)
 -         {
 -             if (getArchitectures().isEmpty())
 -             {
 -                 if (isDebug())
 -                     getArchitecturesValue() = "armeabi x86";
 -                 else
 -                     getArchitecturesValue() = "armeabi armeabi-v7a x86";
 -             }
 -         }
 - 
 -         Value getArchitecturesValue()           { return getValue (Ids::androidArchitectures); }
 -         String getArchitectures() const         { return config [Ids::androidArchitectures]; }
 - 
 -         var getDefaultOptimisationLevel() const override    { return var ((int) (isDebug() ? gccO0 : gccO3)); }
 - 
 -         void createConfigProperties (PropertyListBuilder& props) override
 -         {
 -             addGCCOptimisationProperty (props);
 - 
 -             props.add (new TextPropertyComponent (getArchitecturesValue(), "Architectures", 256, false),
 -                        "A list of the ARM architectures to build (for a fat binary).");
 -         }
 -     };
 - 
 -     BuildConfiguration::Ptr createBuildConfig (const ValueTree& v) const override
 -     {
 -         return new AndroidStudioBuildConfiguration (project, v, *this);
 -     }
 - 
 - private:
 -     static void createSymboicLinkAndCreateParentFolders (const File& originalFile, const File& linkFile)
 -     {
 -         {
 -             const File linkFileParentDirectory (linkFile.getParentDirectory());
 - 
 -             // this will recursively creative the parent directories for the file
 -             // without this, the symlink would fail because it doesn't automatically create
 -             // the folders if they don't exist
 -             if (! linkFileParentDirectory.createDirectory())
 -                 throw SaveError (String ("Could not create directory ") + linkFileParentDirectory.getFullPathName());
 -         }
 - 
 -         if (! originalFile.createSymbolicLink (linkFile, true))
 -             throw SaveError (String ("Failed to create symlink from ")
 -                               + linkFile.getFullPathName() + " to "
 -                               + originalFile.getFullPathName() + "!");
 -     }
 - 
 -     void makeSymlinksForGroup (const Project::Item& group, const File& targetFolder) const
 -     {
 -         if (! group.isGroup())
 -         {
 -             throw SaveError ("makeSymlinksForGroup was called with something other than a group!");
 -         }
 - 
 -         for (int i = 0; i < group.getNumChildren(); ++i)
 -         {
 -             const Project::Item& projectItem = group.getChild (i);
 - 
 -             if (projectItem.isGroup())
 -             {
 -                 makeSymlinksForGroup (projectItem, targetFolder.getChildFile (projectItem.getName()));
 -             }
 -             else if (projectItem.shouldBeAddedToTargetProject()) // must be a file then
 -             {
 -                 const File originalFile (projectItem.getFile());
 -                 const File targetFile (targetFolder.getChildFile (originalFile.getFileName()));
 - 
 -                 createSymboicLinkAndCreateParentFolders (originalFile, targetFile);
 -             }
 -         }
 -     }
 - 
 -     void createSourceSymlinks (const File& folder) const
 -     {
 -         const File targetFolder (folder.getChildFile ("app/src/main/jni"));
 - 
 -         // here we make symlinks to only to files included in the groups inside the project
 -         // this is because Android Studio does not have a concept of groups and just uses
 -         // the file system layout to determine what's to be compiled
 -         {
 -             const Array<Project::Item>& groups = getAllGroups();
 - 
 -             for (int i = 0; i < groups.size(); ++i)
 -             {
 -                 const Project::Item projectItem (groups.getReference (i));
 -                 const String projectItemName (projectItem.getName());
 - 
 -                 if (projectItem.isGroup())
 -                     makeSymlinksForGroup (projectItem, projectItemName == "Juce Modules" ? targetFolder.getChildFile ("JuceModules") : targetFolder);
 -             }
 -         }
 -     }
 - 
 -     void writeAppIcons (const File& folder) const
 -     {
 -         writeIcons (folder.getChildFile ("app/src/main/res/"));
 -     }
 - 
 -     void writeSettingsDotGradle (const File& folder) const
 -     {
 -         MemoryOutputStream memoryOutputStream;
 - 
 -         memoryOutputStream << "include ':app'";
 - 
 -         overwriteFileIfDifferentOrThrow (folder.getChildFile ("settings.gradle"), memoryOutputStream);
 -     }
 - 
 -     static String sanitisePath (String path)
 -     {
 -         return expandHomeFolderToken (path).replace ("\\", "\\\\");
 -     }
 - 
 -     static String expandHomeFolderToken (const String& path)
 -     {
 -         String homeFolder = File::getSpecialLocation (File::userHomeDirectory).getFullPathName();
 - 
 -         return path.replace ("${user.home}", homeFolder)
 -                    .replace ("~", homeFolder);
 -     }
 - 
 -     void writeLocalDotProperties (const File& folder) const
 -     {
 -         MemoryOutputStream memoryOutputStream;
 - 
 -         memoryOutputStream << "ndk.dir=" << sanitisePath (getNDKPathString()) << newLine
 -                            << "sdk.dir=" << sanitisePath (getSDKPathString());
 - 
 -         overwriteFileIfDifferentOrThrow (folder.getChildFile ("local.properties"), memoryOutputStream);
 -     }
 - 
 -     void writeGradleWrapperProperties (const File& folder) const
 -     {
 -         MemoryOutputStream memoryOutputStream;
 - 
 -         memoryOutputStream << "distributionUrl=https\\://services.gradle.org/distributions/gradle-2.10-all.zip";
 - 
 -         overwriteFileIfDifferentOrThrow (folder.getChildFile ("gradle/wrapper/gradle-wrapper.properties"), memoryOutputStream);
 -     }
 - 
 -     void writeBuildDotGradleRoot (const File& folder) const
 -     {
 -         MemoryOutputStream memoryOutputStream;
 - 
 -         const String indent = getIndentationString();
 - 
 -         // this is needed to make sure the correct version of the gradle build tools is available.
 -         // needs to be kept up to date!
 -         memoryOutputStream << "buildscript {" << newLine
 -                            << indent << "repositories {" << newLine
 -                            << indent << indent << "jcenter()" << newLine
 -                            << indent << "}" << newLine
 -                            << indent << "dependencies {" << newLine
 -                            << indent << indent << "classpath 'com.android.tools.build:gradle-experimental:0.6.0-alpha5'" << newLine
 -                            << indent << "}" << newLine
 -                            << "}" << newLine
 -                            << newLine
 -                            << "allprojects {" << newLine
 -                            << indent << "repositories {" << newLine
 -                            << indent << indent << "jcenter()" << newLine
 -                            << indent << "}" << newLine
 -                            << "}";
 - 
 -         overwriteFileIfDifferentOrThrow (folder.getChildFile ("build.gradle"), memoryOutputStream);
 -     }
 - 
 -     void writeStringsXML (const File& folder) const
 -     {
 -         XmlElement strings ("resources");
 -         XmlElement* resourceName = strings.createNewChildElement ("string");
 - 
 -         resourceName->setAttribute ("name", "app_name");
 -         resourceName->addTextElement (projectName);
 - 
 -         writeXmlOrThrow (strings, folder.getChildFile ("app/src/main/res/values/string.xml"), "utf-8", 100, true);
 -     }
 - 
 -     void writeAndroidManifest (const File& folder) const
 -     {
 -         ScopedPointer<XmlElement> manifest (createManifestXML());
 - 
 -         writeXmlOrThrow (*manifest, folder.getChildFile ("app/src/main/AndroidManifest.xml"), "utf-8", 100, true);
 -     }
 - 
 -     String createModelDotAndroid (const String& indent,
 -                                   const String& minimumSDKVersion,
 -                                   const String& buildToolsVersion,
 -                                   const String& bundleIdentifier) const
 -     {
 -         String result;
 - 
 -         result << "android {" << newLine
 -                << indent << "compileSdkVersion = " << minimumSDKVersion << newLine
 -                << indent << "buildToolsVersion = \"" << buildToolsVersion << "\"" << newLine
 -                << indent << "defaultConfig.with {" << newLine
 -                << indent << indent << "applicationId = \"" << bundleIdentifier.toLowerCase() << "\"" << newLine
 -                << indent << indent << "minSdkVersion.apiLevel = " << minimumSDKVersion << newLine
 -                << indent << indent << "targetSdkVersion.apiLevel = " << minimumSDKVersion << newLine
 -                << indent << "}" << newLine
 -                << "}" << newLine;
 - 
 -         return result;
 -     }
 - 
 -     String createModelDotAndroidSources (const String& indent) const
 -     {
 -         String result;
 - 
 -         result << "android.sources {" << newLine
 -                << indent << "main {" << newLine
 -                << indent << indent << "jni {" << newLine
 -                << indent << indent << indent << "source {" << newLine
 -                << indent << indent << indent << indent << "exclude \"**/JuceModules/\"" << newLine
 -                << indent << indent << indent << "}" << newLine
 -                << indent << indent << "}" << newLine
 -                << indent << "}" << newLine
 -                << "}" << newLine;
 - 
 -         return result;
 -     }
 - 
 -     struct ShouldBeAddedToProjectPredicate
 -     {
 -         bool operator() (const Project::Item& projectItem) const { return projectItem.shouldBeAddedToTargetProject(); }
 -     };
 - 
 -     StringArray getCPPFlags() const
 -     {
 -         StringArray result;
 - 
 -         result.add ("\"-fsigned-char\"");
 -         result.add ("\"-fexceptions\"");
 -         result.add ("\"-frtti\"");
 - 
 -         if (isCPP11Enabled())
 -             result.add ("\"-std=c++11\"");
 - 
 -         StringArray extraFlags (StringArray::fromTokens (getExtraCompilerFlagsString(), " ", ""));
 - 
 -         for (int i = 0; i < extraFlags.size(); ++i)
 -             result.add (String ("\"") + extraFlags[i] + "\"");
 - 
 -         // include paths
 - 
 -         result.add ("\"-I${project.rootDir}/app\".toString()");
 -         result.add ("\"-I${ext.juceRootDir}\".toString()");
 -         result.add ("\"-I${ext.juceModuleDir}\".toString()");
 - 
 -         {
 -             Array<RelativePath> cppFiles;
 -             const Array<Project::Item>& groups = getAllGroups();
 - 
 -             for (int i = 0; i < groups.size(); ++i)
 -                 findAllProjectItemsWithPredicate (groups.getReference (i), cppFiles, ShouldBeAddedToProjectPredicate());
 - 
 -             for (int i = 0; i < cppFiles.size(); ++i)
 -             {
 -                 const RelativePath absoluteSourceFile (cppFiles.getReference (i).rebased (getTargetFolder(),
 -                                                                                           project.getProjectFolder(),
 -                                                                                           RelativePath::projectFolder));
 - 
 -                 const String absoluteIncludeFolder (sanitisePath (project.getProjectFolder().getFullPathName() + "/"
 -                                                                    + absoluteSourceFile.toUnixStyle().upToLastOccurrenceOf ("/", false, false)));
 - 
 -                 result.addIfNotAlreadyThere ("\"-I" + absoluteIncludeFolder + "\".toString()");
 -             }
 -         }
 - 
 -         return result;
 -     }
 - 
 -     StringArray getLDLibs() const
 -     {
 -         StringArray result;
 - 
 -         result.add ("android");
 -         result.add ("EGL");
 -         result.add ("GLESv2");
 -         result.add ("log");
 - 
 -         result.addArray (StringArray::fromTokens(getExternalLibrariesString(), ";", ""));
 - 
 -         return result;
 -     }
 - 
 -     String createModelDotAndroidNDK (const String& indent) const
 -     {
 -         String result;
 -         const String platformVersion (getNDKPlatformVersionString());
 - 
 -         result << "android.ndk {" << newLine
 -                << indent << "moduleName = \"juce_jni\"" << newLine
 -                << indent << "stl = \"c++_static\"" << newLine
 -                << indent << "toolchain = \"clang\"" << newLine
 -                << indent << "toolchainVersion = 3.6" << newLine;
 - 
 -         if (platformVersion.isNotEmpty())
 -             result << indent << "platformVersion = " << getNDKPlatformVersionString() << newLine;
 - 
 -         result << indent << "ext {" << newLine
 -                << indent << indent << "juceRootDir = \"" << "${project.rootDir}/../../../../" << "\".toString()" << newLine
 -                << indent << indent << "juceModuleDir = \"" << "${juceRootDir}/modules" << "\".toString()" << newLine
 -                << indent << "}" << newLine;
 - 
 -         // CPP flags
 - 
 -         {
 -             StringArray cppFlags (getCPPFlags());
 - 
 -             for (int i = 0; i < cppFlags.size(); ++i)
 -                 result << indent << "cppFlags.add(" << cppFlags[i] << ")" << newLine;
 -         }
 - 
 -         // libraries
 - 
 -         {
 -             StringArray libraries (getLDLibs());
 - 
 -             result << indent << "ldLibs.addAll(";
 - 
 -             for (int i = 0; i < libraries.size(); ++i)
 -             {
 -                 result << "\"" << libraries[i] << "\"";
 - 
 -                 if (i + 1 != libraries.size())
 -                     result << ", ";
 -             }
 - 
 -             result << ")" << newLine;
 -         }
 - 
 -         result << "}" << newLine;
 - 
 -         return result;
 -     }
 - 
 -     String getModelDotAndroidDotBuildTypesFlags (const String& indent, const ConstConfigIterator& config) const
 -     {
 -         const String configName (config->getName());
 - 
 -         // there appears to be an issue with build types that have a name other than
 -         // "debug" or "release". Apparently this is hard coded in Android Studio ...
 - 
 -         if (configName != "Debug" && configName != "Release")
 -             throw SaveError ("Build configurations other than Debug and Release are not yet support for Android Studio");
 - 
 -         StringArray rootFlags;  // model.android.buildTypes.debug/release { ... }
 -         StringArray ndkFlags;   // model.android.buildTypes.debug/release.ndk.with { ... }
 - 
 -         if (config->isDebug())
 -         {
 -             ndkFlags.add ("debuggable = true");
 -             ndkFlags.add ("cppFlags.add(\"-g\")");
 -             ndkFlags.add ("cppFlags.add(\"-DDEBUG=1\")");
 -             ndkFlags.add ("cppFlags.add(\"-D_DEBUG=1\")");
 -         }
 -         else
 -         {
 -             rootFlags.add ("signingConfig = $(\"android.signingConfigs.releaseConfig\")");
 -             ndkFlags.add ("cppFlags.add(\"-DNDEBUG=1\")");
 -         }
 - 
 -         const StringArray& headerSearchPaths = config->getHeaderSearchPaths();
 -         for (int i = 0; i < headerSearchPaths.size(); ++i)
 -             ndkFlags.add ("cppFlags.add(\"-I" + sanitisePath (headerSearchPaths[i]) + "\".toString())");
 - 
 -         const StringArray& librarySearchPaths = config->getLibrarySearchPaths();
 -         for (int i = 0; i < librarySearchPaths.size(); ++i)
 -             ndkFlags.add ("cppFlags.add(\"-L" + sanitisePath (librarySearchPaths[i]) + "\".toString())");
 - 
 -         {
 -             StringPairArray preprocessorDefinitions = config->getAllPreprocessorDefs();
 -             preprocessorDefinitions.set ("JUCE_ANDROID", "1");
 -             preprocessorDefinitions.set ("JUCE_ANDROID_API_VERSION", getMinimumSDKVersionString());
 -             preprocessorDefinitions.set ("JUCE_ANDROID_ACTIVITY_CLASSNAME", getJNIActivityClassName().replaceCharacter ('/', '_'));
 -             preprocessorDefinitions.set ("JUCE_ANDROID_ACTIVITY_CLASSPATH", "\\\"" + getActivityClassPath().replaceCharacter('.', '/') + "\\\"");
 - 
 -             const StringArray& keys = preprocessorDefinitions.getAllKeys();
 - 
 -             for (int i = 0; i < keys.size(); ++i)
 -                 ndkFlags.add (String ("cppFlags.add(\"-D") + keys[i] + String ("=") + preprocessorDefinitions[keys[i]] + "\")");
 -         }
 - 
 -         ndkFlags.add ("cppFlags.add(\"-O" + config->getGCCOptimisationFlag() + "\")");
 - 
 -         String result;
 - 
 -         result << configName.toLowerCase() << " {" << newLine;
 - 
 -         for (int i = 0; i < rootFlags.size(); ++i)
 -             result << indent << rootFlags[i] << newLine;
 - 
 -         result << indent << "ndk.with {" << newLine;
 - 
 -         for (int i = 0; i < ndkFlags.size(); ++i)
 -             result << indent << indent << ndkFlags[i] << newLine;
 - 
 -         result << indent << "}" << newLine
 -                << "}" << newLine;
 - 
 -         return result;
 -     }
 - 
 -     String createModelDotAndroidDotBuildTypes (const String& indent) const
 -     {
 -         String result;
 - 
 -         result << "android.buildTypes {" << newLine;
 - 
 -         for (ConstConfigIterator config (*this); config.next();)
 -             result << CodeHelpers::indent (getModelDotAndroidDotBuildTypesFlags (indent, config), indent.length(), true);
 - 
 -         result << "}" << newLine;
 - 
 -         return result;
 -     }
 - 
 -     String createModelDotAndroidDotSigningConfigs (const String& indent) const
 -     {
 -         String result;
 - 
 -         result << "android.signingConfigs {" << newLine
 -                << indent << "create(\"releaseConfig\") {" << newLine
 -                << indent << indent << "storeFile = new File(\"" << sanitisePath (getKeyStoreString()) << "\")" << newLine
 -                << indent << indent << "storePassword = \"" << getKeyStorePassString() << "\"" << newLine
 -                << indent << indent << "keyAlias = \"" << getKeyAliasString() << "\"" << newLine
 -                << indent << indent << "keyPassword = \"" << getKeyAliasPassString() << "\"" << newLine
 -                << indent << indent << "storeType = \"jks\"" << newLine
 -                << indent << "}" << newLine
 -                << "}" << newLine;
 - 
 -         return result;
 -     }
 - 
 -     String createModelDotAndroidDotProductFlavors (const String& indent) const
 -     {
 -         String result;
 - 
 -         result << "android.productFlavors {" << newLine;
 - 
 -         // TODO! - this needs to be changed so that it generates seperate flags for debug and release ...
 -         // at present, it just generates all ABIs for all build types
 - 
 -         StringArray architectures (StringArray::fromTokens (getABIs<AndroidStudioBuildConfiguration> (true),  " ", ""));
 -         architectures.mergeArray  (StringArray::fromTokens (getABIs<AndroidStudioBuildConfiguration> (false), " ", ""));
 - 
 -         if (architectures.size() == 0)
 -             throw SaveError ("Can't build for no architectures!");
 - 
 -         for (int i = 0; i < architectures.size(); ++i)
 -         {
 -             String architecture (architectures[i].trim());
 - 
 -             if (architecture.isEmpty())
 -                 continue;
 - 
 -             result << indent << "create(\"" << architecture << "\") {" << newLine
 -                    << indent << indent << "ndk.abiFilters.add(\"" << architecture << "\")" << newLine
 -                    << indent << "}" << newLine;
 -         }
 - 
 -         result << "}" << newLine;
 - 
 -         return result;
 -     }
 - 
 -     void writeBuildDotGradleApp (const File& folder) const
 -     {
 -         MemoryOutputStream memoryOutputStream;
 - 
 -         const String indent            = getIndentationString();
 -         const String minimumSDKVersion = getMinimumSDKVersionString();
 -         const String bundleIdentifier  = project.getBundleIdentifier().toString();
 - 
 -         String buildToolsVersion = getBuildToolsVersionString();
 - 
 -         if (buildToolsVersion.isEmpty())
 -             buildToolsVersion = "23.0.1";
 - 
 -         memoryOutputStream << "apply plugin: 'com.android.model.application'" << newLine
 -                            << newLine
 -                            << "model {" << newLine
 -                            << CodeHelpers::indent (createModelDotAndroid (indent,
 -                                                                           minimumSDKVersion,
 -                                                                           buildToolsVersion,
 -                                                                           bundleIdentifier), indent.length(), true)
 -                            << newLine
 -                            << CodeHelpers::indent (createModelDotAndroidNDK (indent), indent.length(), true)
 -                            << newLine
 -                            << CodeHelpers::indent (createModelDotAndroidSources (indent), indent.length(), true)
 -                            << newLine
 -                            << CodeHelpers::indent (createModelDotAndroidDotBuildTypes (indent), indent.length(), true)
 -                            << newLine
 -                            << CodeHelpers::indent (createModelDotAndroidDotSigningConfigs (indent), indent.length(), true)
 -                            << newLine
 -                            << CodeHelpers::indent (createModelDotAndroidDotProductFlavors (indent), indent.length(), true)
 -                            << "}";
 - 
 -         overwriteFileIfDifferentOrThrow (folder.getChildFile ("app/build.gradle"), memoryOutputStream);
 -     }
 - 
 -     static const char* getIndentationString() noexcept
 -     {
 -         return "    ";
 -     }
 - 
 -     const File androidStudioExecutable;
 - 
 -     JUCE_DECLARE_NON_COPYABLE (AndroidStudioProjectExporter)
 - };
 
 
  |