159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet/*
259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet * Copyright (C) 2010 The Android Open Source Project
359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet *
459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet * Licensed under the Eclipse Public License, Version 1.0 (the "License");
559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet * you may not use this file except in compliance with the License.
659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet * You may obtain a copy of the License at
759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet *
859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet *      http://www.eclipse.org/org/documents/epl-v10.php
959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet *
1059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software
1159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
1259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet * See the License for the specific language governing permissions and
1459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet * limitations under the License.
1559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet */
1659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
1759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetpackage com.android.ide.eclipse.adt.internal.build;
1859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
1981cefe2a26dd6db8a878e30874d12cdcbff0e83bXavier Ducrohetimport com.android.SdkConstants;
207e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbyeimport com.android.annotations.Nullable;
21c3105b949cd2a0f6cbf8a12ec4f30e49b5b5a502Xavier Ducrohetimport com.android.ide.eclipse.adt.AdtConstants;
22fd19b2c89be703549e23d501541632883819ab7bRaphael Mollimport com.android.ide.eclipse.adt.AdtPlugin;
233d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohetimport com.android.ide.eclipse.adt.AndroidPrintStream;
2459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
2559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity;
2698b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohetimport com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
2759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport com.android.ide.eclipse.adt.internal.sdk.Sdk;
2859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport com.android.prefs.AndroidLocation.AndroidLocationException;
2959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport com.android.sdklib.IAndroidTarget;
3067000f1a4e4cc31c258afd80fe13939ae66aea2aXavier Ducrohetimport com.android.sdklib.IAndroidTarget.IOptionalLibrary;
317c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohetimport com.android.sdklib.build.ApkBuilder;
32ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbyeimport com.android.sdklib.build.ApkBuilder.JarStatus;
33ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbyeimport com.android.sdklib.build.ApkBuilder.SigningInfo;
341fd0a0d0ad99735551876d6f7ceab7ff5d42b575Xavier Ducrohetimport com.android.sdklib.build.ApkCreationException;
351fd0a0d0ad99735551876d6f7ceab7ff5d42b575Xavier Ducrohetimport com.android.sdklib.build.DuplicateFileException;
361fd0a0d0ad99735551876d6f7ceab7ff5d42b575Xavier Ducrohetimport com.android.sdklib.build.SealedApkException;
3710e712627b86b2b0061dbd3a20f5f966b2cd7330Xavier Ducrohetimport com.android.sdklib.internal.build.DebugKeyProvider;
3867000f1a4e4cc31c258afd80fe13939ae66aea2aXavier Ducrohetimport com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException;
398c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphaelimport com.android.sdklib.util.GrabProcessOutput;
408c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphaelimport com.android.sdklib.util.GrabProcessOutput.IProcessOutput;
41e27bbc4d1cf9c9d6b23344b977331bed0a3357a5Raphaelimport com.android.sdklib.util.GrabProcessOutput.Wait;
4259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
4359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.core.resources.IFile;
4459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.core.resources.IFolder;
4559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.core.resources.IProject;
4659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.core.resources.IResource;
4759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.core.resources.IWorkspaceRoot;
4859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.core.resources.ResourcesPlugin;
4959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.core.runtime.CoreException;
5059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.core.runtime.IPath;
5159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.core.runtime.IStatus;
5259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.core.runtime.Status;
53babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohetimport org.eclipse.jdt.core.IClasspathContainer;
5459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.jdt.core.IClasspathEntry;
5559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.jdt.core.IJavaProject;
5659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.jdt.core.JavaCore;
5759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.jdt.core.JavaModelException;
5859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport org.eclipse.jface.preference.IPreferenceStore;
5959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
6059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport java.io.File;
61eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Mollimport java.io.FileWriter;
6259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport java.io.IOException;
6359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport java.io.PrintStream;
643d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohetimport java.security.PrivateKey;
653d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohetimport java.security.cert.X509Certificate;
6659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport java.util.ArrayList;
67bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohetimport java.util.Collection;
68cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohetimport java.util.Collections;
69bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohetimport java.util.HashSet;
7059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohetimport java.util.List;
71eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Mollimport java.util.Map;
72bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohetimport java.util.Set;
73eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Mollimport java.util.TreeMap;
7459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
757c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet/**
767c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet * Helper with methods for the last 3 steps of the generation of an APK.
777c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet *
787c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet * {@link #packageResources(IFile, IProject[], String, int, String, String)} packages the
797c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet * application resources using aapt into a zip file that is ready to be integrated into the apk.
807c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet *
817c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet * {@link #executeDx(IJavaProject, String, String, IJavaProject[])} will convert the Java byte
827c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet * code into the Dalvik bytecode.
837c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet *
847c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet * {@link #finalPackage(String, String, String, boolean, IJavaProject, IProject[], IJavaProject[], String, boolean)}
857c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet * will make the apk from all the previous components.
867c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet *
873d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet * This class only executes the 3 above actions. It does not handle the errors, and simply sends
883d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet * them back as custom exceptions.
893d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet *
903d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet * Warnings are handled by the {@link ResourceMarker} interface.
913d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet *
923d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet * Console output (verbose and non verbose) is handled through the {@link AndroidPrintStream} passed
933d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet * to the constructor.
943d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet *
957c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet */
9659f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohetpublic class BuildHelper {
9759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
98eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll    private static final String CONSOLE_PREFIX_DX = "Dx";   //$NON-NLS-1$
99eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll    private final static String TEMP_PREFIX = "android_";   //$NON-NLS-1$
1003d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
101c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin    private static final String COMMAND_CRUNCH = "crunch";  //$NON-NLS-1$
102c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin    private static final String COMMAND_PACKAGE = "package"; //$NON-NLS-1$
103c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
10459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    private final IProject mProject;
1053d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet    private final AndroidPrintStream mOutStream;
1063d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet    private final AndroidPrintStream mErrStream;
1073d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet    private final boolean mVerbose;
1083d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet    private final boolean mDebugMode;
1093d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
110bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet    private final Set<String> mCompiledCodePaths = new HashSet<String>();
111bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet
112c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin    public static final boolean BENCHMARK_FLAG = false;
113c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin    public static long sStartOverallTime = 0;
114c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin    public static long sStartJavaCTime = 0;
115c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
116c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin    private final static int MILLION = 1000000;
117cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet    private String mProguardFile;
118c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
1193d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet    /**
1203d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * An object able to put a marker on a resource.
1213d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     */
1223d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet    public interface ResourceMarker {
1233d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        void setWarning(IResource resource, String message);
1243d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet    }
1253d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
1263d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet    /**
1273d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * Creates a new post-compiler helper
1283d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @param project
1293d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @param outStream
1303d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @param errStream
1313d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @param debugMode whether this is a debug build
1323d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @param verbose
133bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet     * @throws CoreException
1343d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     */
13559f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet    public BuildHelper(IProject project, AndroidPrintStream outStream,
136bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            AndroidPrintStream errStream, boolean debugMode, boolean verbose,
137bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            ResourceMarker resMarker) throws CoreException {
13859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        mProject = project;
13959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        mOutStream = outStream;
14059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        mErrStream = errStream;
1413d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        mDebugMode = debugMode;
1423d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        mVerbose = verbose;
143bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet
144bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        gatherPaths(resMarker);
14559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    }
14659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
147c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin    public void updateCrunchCache() throws AaptExecException, AaptResultException {
148c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        // Benchmarking start
149c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        long startCrunchTime = 0;
150c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        if (BENCHMARK_FLAG) {
151c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            String msg = "BENCHMARK ADT: Starting Initial Packaging (.ap_)"; //$NON-NLS-1$
152c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg);
153c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            startCrunchTime = System.nanoTime();
154c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        }
155c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
156c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        // Get the resources folder to crunch from
157c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        IFolder resFolder = mProject.getFolder(AdtConstants.WS_RESOURCES);
158c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        List<String> resPaths = new ArrayList<String>();
159c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        resPaths.add(resFolder.getLocation().toOSString());
160c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
161c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        // Get the output folder where the cache is stored.
162c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        IFolder cacheFolder = mProject.getFolder(AdtConstants.WS_CRUNCHCACHE);
163c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        String cachePath = cacheFolder.getLocation().toOSString();
164c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
165c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        /* For crunching, we don't need the osManifestPath, osAssetsPath, or the configFilter
166c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin         * parameters for executeAapt
167c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin         */
168c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        executeAapt(COMMAND_CRUNCH, "", resPaths, "", cachePath, "", 0);
169c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
170c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        // Benchmarking end
171c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        if (BENCHMARK_FLAG) {
172c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            String msg = "BENCHMARK ADT: Ending Initial Package (.ap_). \nTime Elapsed: " //$NON-NLS-1$
173c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                            + ((System.nanoTime() - startCrunchTime)/MILLION) + "ms";     //$NON-NLS-1$
174c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg);
175c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        }
176c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin    }
177babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet
178853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet    /**
179853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * Packages the resources of the projet into a .ap_ file.
180853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * @param manifestFile the manifest of the project.
181853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * @param libProjects the list of library projects that this project depends on.
182853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * @param resFilter an optional resource filter to be used with the -c option of aapt. If null
183853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * no filters are used.
184853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * @param versionCode an optional versionCode to be inserted in the manifest during packaging.
185853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * If the value is <=0, no values are inserted.
186853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * @param outputFolder where to write the resource ap_ file.
187853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * @param outputFilename the name of the resource ap_ file.
1883d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws AaptExecException
1893d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws AaptResultException
190853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     */
191a0340fdf211a94d4d96a9e063386b0eccae9b74cXavier Ducrohet    public void packageResources(IFile manifestFile, List<IProject> libProjects, String resFilter,
1923d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            int versionCode, String outputFolder, String outputFilename)
1933d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            throws AaptExecException, AaptResultException {
194c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
195c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        // Benchmarking start
196c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        long startPackageTime = 0;
197c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        if (BENCHMARK_FLAG) {
198c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            String msg = "BENCHMARK ADT: Starting Initial Packaging (.ap_)";    //$NON-NLS-1$
199c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg);
200c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            startPackageTime = System.nanoTime();
201c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        }
202c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
20359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        // need to figure out some path before we can execute aapt;
20459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
205c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        // get the cache folder
206c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        IFolder cacheFolder = mProject.getFolder(AdtConstants.WS_CRUNCHCACHE);
207c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
20859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        // get the resource folder
209c3105b949cd2a0f6cbf8a12ec4f30e49b5b5a502Xavier Ducrohet        IFolder resFolder = mProject.getFolder(AdtConstants.WS_RESOURCES);
21059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
21159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        // and the assets folder
212c3105b949cd2a0f6cbf8a12ec4f30e49b5b5a502Xavier Ducrohet        IFolder assetsFolder = mProject.getFolder(AdtConstants.WS_ASSETS);
21359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
21459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        // we need to make sure this one exists.
21559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        if (assetsFolder.exists() == false) {
21659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            assetsFolder = null;
21759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        }
21859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
21916ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet        // list of res folder (main project + maybe libraries)
22016ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet        ArrayList<String> osResPaths = new ArrayList<String>();
22116ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet
22259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        IPath resLocation = resFolder.getLocation();
22359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        IPath manifestLocation = manifestFile.getLocation();
22459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
22559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        if (resLocation != null && manifestLocation != null) {
22659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
22716ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet            // png cache folder first.
22816ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet            addFolderToList(osResPaths, cacheFolder);
22916ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet
23016ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet            // regular res folder next.
23116ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet            osResPaths.add(resLocation.toOSString());
23216ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet
23316ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet            // then libraries
23459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            if (libProjects != null) {
23559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                for (IProject lib : libProjects) {
23616ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet                    // png cache folder first
23778c89f931135c11c45f26590ea5ae29577bced85Xavier Ducrohet                    IFolder libCacheFolder = lib.getFolder(AdtConstants.WS_CRUNCHCACHE);
23816ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet                    addFolderToList(osResPaths, libCacheFolder);
23916ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet
24016ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet                    // regular res folder next.
24178c89f931135c11c45f26590ea5ae29577bced85Xavier Ducrohet                    IFolder libResFolder = lib.getFolder(AdtConstants.WS_RESOURCES);
24216ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet                    addFolderToList(osResPaths, libResFolder);
24359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                }
24459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            }
24559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
24659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            String osManifestPath = manifestLocation.toOSString();
24759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
24859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            String osAssetsPath = null;
24959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            if (assetsFolder != null) {
25059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                osAssetsPath = assetsFolder.getLocation().toOSString();
25159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            }
25259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
25359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            // build the default resource package
254c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            executeAapt(COMMAND_PACKAGE, osManifestPath, osResPaths, osAssetsPath,
255853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet                    outputFolder + File.separator + outputFilename, resFilter,
2563d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet                    versionCode);
25759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        }
258c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
259c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        // Benchmarking end
260c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        if (BENCHMARK_FLAG) {
261c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            String msg = "BENCHMARK ADT: Ending Initial Package (.ap_). \nTime Elapsed: " //$NON-NLS-1$
262c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                            + ((System.nanoTime() - startPackageTime)/MILLION) + "ms";    //$NON-NLS-1$
263c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg);
264c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        }
2653d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet    }
26659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
2673d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet    /**
26816ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet     * Adds os path of a folder to a list only if the folder actually exists.
26916ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet     * @param pathList
27016ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet     * @param folder
27116ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet     */
27216ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet    private void addFolderToList(List<String> pathList, IFolder folder) {
27316ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet        // use a File instead of the IFolder API to ignore workspace refresh issue.
27416ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet        File testFile = new File(folder.getLocation().toOSString());
27516ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet        if (testFile.isDirectory()) {
27616ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet            pathList.add(testFile.getAbsolutePath());
27716ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet        }
27816ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet    }
27916ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet
28016ed545d6175d2afde14b9585eed1feb28ce6364Xavier Ducrohet    /**
2813d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * Makes a final package signed with the debug key.
2823d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     *
2833d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * Packages the dex files, the temporary resource file into the final package file.
2843d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     *
2853d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * Whether the package is a debug package is controlled with the <var>debugMode</var> parameter
2863d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * in {@link #PostCompilerHelper(IProject, PrintStream, PrintStream, boolean, boolean)}
2873d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     *
2883d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @param intermediateApk The path to the temporary resource file.
2893d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @param dex The path to the dex file.
2903d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @param output The path to the final package file to create.
2913d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @param libProjects an optional list of library projects (can be null)
2923d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @return true if success, false otherwise.
2933d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws ApkCreationException
2943d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws AndroidLocationException
2953d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws KeytoolException
2963d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws NativeLibInJarException
2973d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws CoreException
2983d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws DuplicateFileException
2993d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     */
3003d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet    public void finalDebugPackage(String intermediateApk, String dex, String output,
301cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet            List<IProject> libProjects, ResourceMarker resMarker)
3023d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            throws ApkCreationException, KeytoolException, AndroidLocationException,
3033d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            NativeLibInJarException, DuplicateFileException, CoreException {
3043d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
305a19e364a559f151ca2985d348384bf0e2ef7768dRaphael Moll        AdtPlugin adt = AdtPlugin.getDefault();
306a19e364a559f151ca2985d348384bf0e2ef7768dRaphael Moll        if (adt == null) {
307a19e364a559f151ca2985d348384bf0e2ef7768dRaphael Moll            return;
308a19e364a559f151ca2985d348384bf0e2ef7768dRaphael Moll        }
309a19e364a559f151ca2985d348384bf0e2ef7768dRaphael Moll
3103d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        // get the debug keystore to use.
311a19e364a559f151ca2985d348384bf0e2ef7768dRaphael Moll        IPreferenceStore store = adt.getPreferenceStore();
3123d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        String keystoreOsPath = store.getString(AdtPrefs.PREFS_CUSTOM_DEBUG_KEYSTORE);
3133d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        if (keystoreOsPath == null || new File(keystoreOsPath).isFile() == false) {
3143d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            keystoreOsPath = DebugKeyProvider.getDefaultKeyStoreOsPath();
3153d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject,
3163d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet                    Messages.ApkBuilder_Using_Default_Key);
3173d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        } else {
3183d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, mProject,
3193d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet                    String.format(Messages.ApkBuilder_Using_s_To_Sign, keystoreOsPath));
3203d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        }
3213d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
3223d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        // from the keystore, get the signing info
3233d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        SigningInfo info = ApkBuilder.getDebugKey(keystoreOsPath, mVerbose ? mOutStream : null);
3243d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
325cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet        finalPackage(intermediateApk, dex, output, libProjects,
3263d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet                info != null ? info.key : null, info != null ? info.certificate : null, resMarker);
32759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    }
32859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
32959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    /**
3303d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * Makes the final package.
3313d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     *
3323d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * Packages the dex files, the temporary resource file into the final package file.
3333d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     *
3343d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * Whether the package is a debug package is controlled with the <var>debugMode</var> parameter
3353d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * in {@link #PostCompilerHelper(IProject, PrintStream, PrintStream, boolean, boolean)}
3363d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     *
33759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @param intermediateApk The path to the temporary resource file.
33859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @param dex The path to the dex file.
33959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @param output The path to the final package file to create.
3407c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet     * @param debugSign whether the apk must be signed with the debug key.
34159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @param libProjects an optional list of library projects (can be null)
342853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * @param abiFilter an optional filter. If not null, then only the matching ABI is included in
343853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * the final archive
34459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @return true if success, false otherwise.
3453d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws NativeLibInJarException
3463d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws ApkCreationException
3473d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws CoreException
3483d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws DuplicateFileException
34959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     */
3503d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet    public void finalPackage(String intermediateApk, String dex, String output,
351cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet            List<IProject> libProjects,
352cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet            PrivateKey key, X509Certificate certificate, ResourceMarker resMarker)
3533d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            throws NativeLibInJarException, ApkCreationException, DuplicateFileException,
3543d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            CoreException {
3557c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet
3567c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet        try {
3573d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            ApkBuilder apkBuilder = new ApkBuilder(output, intermediateApk, dex,
3583d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet                    key, certificate,
3593d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet                    mVerbose ? mOutStream: null);
3603d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            apkBuilder.setDebugMode(mDebugMode);
36159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
362cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet            // either use the full compiled code paths or just the proguard file
363cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet            // if present
364cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet            Collection<String> pathsCollection = mCompiledCodePaths;
365cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet            if (mProguardFile != null) {
366cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet                pathsCollection = Collections.singletonList(mProguardFile);
367cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet                mProguardFile = null;
368cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet            }
369cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet
370bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            // Now we write the standard resources from all the output paths.
371cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet            for (String path : pathsCollection) {
372bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                File file = new File(path);
373bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                if (file.isFile()) {
374bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    JarStatus jarStatus = apkBuilder.addResourcesFromJar(file);
3757c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet
376433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                    // check if we found native libraries in the external library. This
377433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                    // constitutes an error or warning depending on if they are in lib/
378433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                    if (jarStatus.getNativeLibs().size() > 0) {
379bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                        String libName = file.getName();
3803d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
381433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        String msg = String.format(
382433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                                "Native libraries detected in '%1$s'. See console for more information.",
383433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                                libName);
38459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
385433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        ArrayList<String> consoleMsgs = new ArrayList<String>();
3863d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
387433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        consoleMsgs.add(String.format(
388433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                                "The library '%1$s' contains native libraries that will not run on the device.",
389433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                                libName));
3903d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
391433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        if (jarStatus.hasNativeLibsConflicts()) {
392433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                            consoleMsgs.add("Additionally some of those libraries will interfer with the installation of the application because of their location in lib/");
393433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                            consoleMsgs.add("lib/ is reserved for NDK libraries.");
394433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        }
3953d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
396433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        consoleMsgs.add("The following libraries were found:");
3973d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
398433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        for (String lib : jarStatus.getNativeLibs()) {
399433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                            consoleMsgs.add(" - " + lib);
400433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        }
4017c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet
402433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        String[] consoleStrings = consoleMsgs.toArray(new String[consoleMsgs.size()]);
4033d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
404433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        // if there's a conflict or if the prefs force error on any native code in jar
405433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        // files, throw an exception
406433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        if (jarStatus.hasNativeLibsConflicts() ||
407433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                                AdtPrefs.getPrefs().getBuildForceErrorOnNativeLibInJar()) {
408433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                            throw new NativeLibInJarException(jarStatus, msg, libName, consoleStrings);
409433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                        } else {
410433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                            // otherwise, put a warning, and output to the console also.
411433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                            if (resMarker != null) {
412433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                                resMarker.setWarning(mProject, msg);
413433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                            }
4143d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
415433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                            for (String string : consoleStrings) {
416433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                                mOutStream.println(string);
417433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                            }
4183d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet                        }
4193d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet                    }
420bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                } else if (file.isDirectory()) {
421433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                    // this is technically not a source folder (class folder instead) but since we
422433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                    // only care about Java resources (ie non class/java files) this will do the
423433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet                    // same
424bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    apkBuilder.addSourceFolder(file);
42559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                }
42659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            }
42759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
42859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            // now write the native libraries.
42959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            // First look if the lib folder is there.
43059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            IResource libFolder = mProject.findMember(SdkConstants.FD_NATIVE_LIBS);
43159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            if (libFolder != null && libFolder.exists() &&
43259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                    libFolder.getType() == IResource.FOLDER) {
4337c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet                // get a File for the folder.
43467000f1a4e4cc31c258afd80fe13939ae66aea2aXavier Ducrohet                apkBuilder.addNativeLibraries(libFolder.getLocation().toFile());
43559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            }
43659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
43759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            // write the native libraries for the library projects.
43859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            if (libProjects != null) {
43959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                for (IProject lib : libProjects) {
44059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                    libFolder = lib.findMember(SdkConstants.FD_NATIVE_LIBS);
44159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                    if (libFolder != null && libFolder.exists() &&
44259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                            libFolder.getType() == IResource.FOLDER) {
44367000f1a4e4cc31c258afd80fe13939ae66aea2aXavier Ducrohet                        apkBuilder.addNativeLibraries(libFolder.getLocation().toFile());
44459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                    }
44559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                }
44659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            }
44759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
4487c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet            // seal the APK.
4497c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet            apkBuilder.sealApk();
4507c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet        } catch (SealedApkException e) {
4517c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet            // this won't happen as we control when the apk is sealed.
45259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        }
45359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    }
45459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
455cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet    public void setProguardOutput(String proguardFile) {
456cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet        mProguardFile = proguardFile;
457cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet    }
458cc62a7f883c51fb8908bf936e894170d775385bcXavier Ducrohet
459bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet    public Collection<String> getCompiledCodePaths() {
460bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        return mCompiledCodePaths;
461edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet    }
462edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
463bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet    public void runProguard(List<File> proguardConfigs, File inputJar, Collection<String> jarFiles,
464eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll                            File obfuscatedJar, File logOutput)
465eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll            throws ProguardResultException, ProguardExecException, IOException {
466edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
467edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
468edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        // prepare the command line for proguard
469edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        List<String> command = new ArrayList<String>();
470edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        command.add(AdtPlugin.getOsAbsoluteProguard());
471edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
4720bf1b2c94e8b3d829fd69d11f2efd550d6159cb9Tor Norbye        for (File configFile : proguardConfigs) {
4730bf1b2c94e8b3d829fd69d11f2efd550d6159cb9Tor Norbye            command.add("-include"); //$NON-NLS-1$
4740bf1b2c94e8b3d829fd69d11f2efd550d6159cb9Tor Norbye            command.add(quotePath(configFile.getAbsolutePath()));
4750bf1b2c94e8b3d829fd69d11f2efd550d6159cb9Tor Norbye        }
476edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
477edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        command.add("-injars"); //$NON-NLS-1$
478fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        StringBuilder sb = new StringBuilder(quotePath(inputJar.getAbsolutePath()));
479edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        for (String jarFile : jarFiles) {
480edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            sb.append(File.pathSeparatorChar);
481fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            sb.append(quotePath(jarFile));
482edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        }
483fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        command.add(quoteWinArg(sb.toString()));
484edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
485edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        command.add("-outjars"); //$NON-NLS-1$
486fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        command.add(quotePath(obfuscatedJar.getAbsolutePath()));
487edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
488edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        command.add("-libraryjars"); //$NON-NLS-1$
489fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        sb = new StringBuilder(quotePath(target.getPath(IAndroidTarget.ANDROID_JAR)));
490edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        IOptionalLibrary[] libraries = target.getOptionalLibraries();
491edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        if (libraries != null) {
492edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            for (IOptionalLibrary lib : libraries) {
493edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet                sb.append(File.pathSeparatorChar);
494fd19b2c89be703549e23d501541632883819ab7bRaphael Moll                sb.append(quotePath(lib.getJarPath()));
495edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            }
496edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        }
497fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        command.add(quoteWinArg(sb.toString()));
498edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
499edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        if (logOutput != null) {
500edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            if (logOutput.isDirectory() == false) {
501edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet                logOutput.mkdirs();
502edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            }
503edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
504edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            command.add("-dump");                                              //$NON-NLS-1$
505edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            command.add(new File(logOutput, "dump.txt").getAbsolutePath());    //$NON-NLS-1$
506edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
507edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            command.add("-printseeds");                                        //$NON-NLS-1$
508edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            command.add(new File(logOutput, "seeds.txt").getAbsolutePath());   //$NON-NLS-1$
509edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
510edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            command.add("-printusage");                                        //$NON-NLS-1$
511edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            command.add(new File(logOutput, "usage.txt").getAbsolutePath());   //$NON-NLS-1$
512edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
513edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            command.add("-printmapping");                                      //$NON-NLS-1$
514edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            command.add(new File(logOutput, "mapping.txt").getAbsolutePath()); //$NON-NLS-1$
515edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        }
516edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
517fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        String commandArray[] = null;
518eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll
519eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll        if (SdkConstants.currentPlatform() == SdkConstants.PLATFORM_WINDOWS) {
520fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            commandArray = createWindowsProguardConfig(command);
521fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        }
522eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll
523fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        if (commandArray == null) {
524eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll            // For Mac & Linux, use a regular command string array.
525eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll            commandArray = command.toArray(new String[command.size()]);
526eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll        }
527eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll
528eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll        // Define PROGUARD_HOME to point to $SDK/tools/proguard if it's not yet defined.
529eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll        // The Mac/Linux proguard.sh can infer it correctly but not the proguard.bat one.
530eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll        String[] envp = null;
531eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll        Map<String, String> envMap = new TreeMap<String, String>(System.getenv());
532eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll        if (!envMap.containsKey("PROGUARD_HOME")) {                                    //$NON-NLS-1$
533eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll            envMap.put("PROGUARD_HOME",    Sdk.getCurrent().getSdkLocation() +         //$NON-NLS-1$
534eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll                                            SdkConstants.FD_TOOLS + File.separator +
535eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll                                            SdkConstants.FD_PROGUARD);
536eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll            envp = new String[envMap.size()];
537eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll            int i = 0;
538eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll            for (Map.Entry<String, String> entry : envMap.entrySet()) {
539eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll                envp[i++] = String.format("%1$s=%2$s",                                 //$NON-NLS-1$
540eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll                                          entry.getKey(),
541eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll                                          entry.getValue());
542eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll            }
543eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll        }
544edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
545fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) {
546fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            sb = new StringBuilder();
547fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            for (String c : commandArray) {
548fd19b2c89be703549e23d501541632883819ab7bRaphael Moll                sb.append(c).append(' ');
549fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            }
550fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            AdtPlugin.printToConsole(mProject, sb.toString());
551fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        }
552fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
553edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        // launch
554edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        int execError = 1;
555edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        try {
556edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            // launch the command line process
557eca9ade6294f925e266eeece8071d5bfdede9c6aRaphael Moll            Process process = Runtime.getRuntime().exec(commandArray, envp);
558edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
559edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            // list to store each line of stderr
560edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            ArrayList<String> results = new ArrayList<String>();
561edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
562edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            // get the output and return code from the process
563edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            execError = grabProcessOutput(mProject, process, results);
564edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
5657139790c9af02de824c6f2dae7a68ff694ae1f19Xavier Ducrohet            if (mVerbose) {
566edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet                for (String resultString : results) {
567edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet                    mOutStream.println(resultString);
568edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet                }
569edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            }
570edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
5717139790c9af02de824c6f2dae7a68ff694ae1f19Xavier Ducrohet            if (execError != 0) {
5727139790c9af02de824c6f2dae7a68ff694ae1f19Xavier Ducrohet                throw new ProguardResultException(execError,
5737139790c9af02de824c6f2dae7a68ff694ae1f19Xavier Ducrohet                        results.toArray(new String[results.size()]));
5747139790c9af02de824c6f2dae7a68ff694ae1f19Xavier Ducrohet            }
5757139790c9af02de824c6f2dae7a68ff694ae1f19Xavier Ducrohet
576edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        } catch (IOException e) {
577edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            String msg = String.format(Messages.Proguard_Exec_Error, commandArray[0]);
578edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            throw new ProguardExecException(msg, e);
579edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        } catch (InterruptedException e) {
580edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            String msg = String.format(Messages.Proguard_Exec_Error, commandArray[0]);
581edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            throw new ProguardExecException(msg, e);
582edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet        }
583edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet    }
584edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
585fd19b2c89be703549e23d501541632883819ab7bRaphael Moll    /**
586fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * For tools R8 up to R11, the proguard.bat launcher on Windows only accepts
587fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * arguments %1..%9. Since we generally have about 15 arguments, we were working
588fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * around this by generating a temporary config file for proguard and then using
589fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * that.
590fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * Starting with tools R12, the proguard.bat launcher has been fixed to take
591fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * all arguments using %* so we no longer need this hack.
592fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     *
593fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * @param command
594fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * @return
595fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * @throws IOException
596fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     */
597fd19b2c89be703549e23d501541632883819ab7bRaphael Moll    private String[] createWindowsProguardConfig(List<String> command) throws IOException {
598fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
599fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        // Arg 0 is the proguard.bat path and arg 1 is the user config file
600fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        String launcher = AdtPlugin.readFile(new File(command.get(0)));
601fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        if (launcher.contains("%*")) {                                      //$NON-NLS-1$
602fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            // This is the launcher from Tools R12. Don't work around it.
603fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            return null;
604fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        }
605fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
606fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        // On Windows, proguard.bat can only pass %1...%9 to the java -jar proguard.jar
607fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        // call, but we have at least 15 arguments here so some get dropped silently
608fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        // and quoting is a big issue. So instead we'll work around that by writing
609fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        // all the arguments to a temporary config file.
610fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
611fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        String[] commandArray = new String[3];
612fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
613fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        commandArray[0] = command.get(0);
614fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        commandArray[1] = command.get(1);
615fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
616fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        // Write all the other arguments to a config file
617fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        File argsFile = File.createTempFile(TEMP_PREFIX, ".pro");           //$NON-NLS-1$
618fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        // TODO FIXME this may leave a lot of temp files around on a long session.
619fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        // Should have a better way to clean up e.g. before each build.
620fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        argsFile.deleteOnExit();
621fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
622fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        FileWriter fw = new FileWriter(argsFile);
623fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
624fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        for (int i = 2; i < command.size(); i++) {
625fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            String s = command.get(i);
626fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            fw.write(s);
627fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            fw.write(s.startsWith("-") ? ' ' : '\n');                       //$NON-NLS-1$
628fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        }
629fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
630fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        fw.close();
631fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
632fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        commandArray[2] = "@" + argsFile.getAbsolutePath();                 //$NON-NLS-1$
633fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        return commandArray;
634fd19b2c89be703549e23d501541632883819ab7bRaphael Moll    }
635fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
636fd19b2c89be703549e23d501541632883819ab7bRaphael Moll    /**
637fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * Quotes a single path for proguard to deal with spaces.
638fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     *
639fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * @param path The path to quote.
640fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * @return The original path if it doesn't contain a space.
641fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     *   Or the original path surrounded by single quotes if it contains spaces.
642fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     */
643fd19b2c89be703549e23d501541632883819ab7bRaphael Moll    private String quotePath(String path) {
644fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        if (path.indexOf(' ') != -1) {
645fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            path = '\'' + path + '\'';
646fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        }
647fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        return path;
648fd19b2c89be703549e23d501541632883819ab7bRaphael Moll    }
649fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
650fd19b2c89be703549e23d501541632883819ab7bRaphael Moll    /**
651fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * Quotes a compound proguard argument to deal with spaces.
652fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * <p/>
653fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * Proguard takes multi-path arguments such as "path1;path2" for some options.
654fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * When the {@link #quotePath} methods adds quotes for such a path if it contains spaces,
655fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * the proguard shell wrapper will absorb the quotes, so we need to quote around the
656fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * quotes.
657fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     *
658fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * @param path The path to quote.
659fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     * @return The original path if it doesn't contain a single quote.
660fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     *   Or on Windows the original path surrounded by double quotes if it contains a quote.
661fd19b2c89be703549e23d501541632883819ab7bRaphael Moll     */
662fd19b2c89be703549e23d501541632883819ab7bRaphael Moll    private String quoteWinArg(String path) {
663fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        if (path.indexOf('\'') != -1 &&
664fd19b2c89be703549e23d501541632883819ab7bRaphael Moll                SdkConstants.currentPlatform() == SdkConstants.PLATFORM_WINDOWS) {
665fd19b2c89be703549e23d501541632883819ab7bRaphael Moll            path = '"' + path + '"';
666fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        }
667fd19b2c89be703549e23d501541632883819ab7bRaphael Moll        return path;
668fd19b2c89be703549e23d501541632883819ab7bRaphael Moll    }
669fd19b2c89be703549e23d501541632883819ab7bRaphael Moll
670edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet
67159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    /**
67259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * Execute the Dx tool for dalvik code conversion.
67359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @param javaProject The java project
674bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet     * @param inputPaths the input paths for DX
67559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @param osOutFilePath the path of the dex file to create.
67659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     *
67759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @throws CoreException
6783d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws DexException
67959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     */
680bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet    public void executeDx(IJavaProject javaProject, Collection<String> inputPaths,
681bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            String osOutFilePath)
682edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            throws CoreException, DexException {
68359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
68459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        // get the dex wrapper
6857695260241c862329e63ee2fa210af5ff3c95ea7Xavier Ducrohet        Sdk sdk = Sdk.getCurrent();
6867695260241c862329e63ee2fa210af5ff3c95ea7Xavier Ducrohet        DexWrapper wrapper = sdk.getDexWrapper();
68759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
68859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        if (wrapper == null) {
68959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
69059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                    Messages.ApkBuilder_UnableBuild_Dex_Not_loaded));
69159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        }
69259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
69359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        try {
6943d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            // set a temporary prefix on the print streams.
6953d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            mOutStream.setPrefix(CONSOLE_PREFIX_DX);
6963d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            mErrStream.setPrefix(CONSOLE_PREFIX_DX);
6973d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
69898b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet            IFolder binFolder = BaseProjectHelper.getAndroidOutputFolder(javaProject.getProject());
69998b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet            File binFile = binFolder.getLocation().toFile();
70098b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet            File dexedLibs = new File(binFile, "dexedLibs");
70198b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet            if (dexedLibs.exists() == false) {
70298b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                dexedLibs.mkdir();
70398b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet            }
70498b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet
70598b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet            // replace the libs by their dexed versions (dexing them if needed.)
70698b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet            List<String> finalInputPaths = new ArrayList<String>(inputPaths.size());
70798b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet            if (inputPaths.size() == 1) {
70898b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                // only one input, no need to put a pre-dexed version, even if this path is
70998b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                // just a jar file (case for proguard'ed builds)
71098b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                finalInputPaths.addAll(inputPaths);
71198b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet            } else {
712fabbec5e8c5f7a052e337972f963cb3163243c36Xavier Ducrohet                for (String input : inputPaths) {
71398b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                    File inputFile = new File(input);
71498b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                    if (inputFile.isDirectory()) {
71598b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                        finalInputPaths.add(input);
71698b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                    } else if (inputFile.isFile()) {
71798b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                        File dexedLib = new File(dexedLibs, inputFile.getName());
71898b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                        String dexedLibPath = dexedLib.getAbsolutePath();
71998b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet
72098b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                        if (dexedLib.isFile() == false ||
72198b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                                dexedLib.lastModified() < inputFile.lastModified()) {
72298b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet
72398b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                            if (mVerbose) {
72498b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                                mOutStream.println("Pre-Dexing " + input);
72598b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                            }
72698b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet
72798b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                            if (dexedLib.isFile()) {
72898b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                                dexedLib.delete();
72998b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                            }
73098b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet
73198b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                            int res = wrapper.run(dexedLibPath, Collections.singleton(input),
73298b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                                    mVerbose, mOutStream, mErrStream);
73398b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet
73498b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                            if (res != 0) {
73598b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                                // output error message and mark the project.
73698b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                                String message = String.format(Messages.Dalvik_Error_d, res);
73798b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                                throw new DexException(message);
73898b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                            }
73998b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                        }
74098b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet
74198b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                        finalInputPaths.add(dexedLibPath);
74298b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                    }
74398b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                }
74498b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet            }
74598b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet
74698b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet            if (mVerbose) {
74798b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                for (String input : finalInputPaths) {
748fabbec5e8c5f7a052e337972f963cb3163243c36Xavier Ducrohet                    mOutStream.println("Input: " + input);
749fabbec5e8c5f7a052e337972f963cb3163243c36Xavier Ducrohet                }
750fabbec5e8c5f7a052e337972f963cb3163243c36Xavier Ducrohet            }
751fabbec5e8c5f7a052e337972f963cb3163243c36Xavier Ducrohet
752edeea1c711e0fd692df97f284594b59921e35b1aXavier Ducrohet            int res = wrapper.run(osOutFilePath,
75398b631c6b3765be96b3707ba7aa54d52b10f4872Xavier Ducrohet                    finalInputPaths,
7543d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet                    mVerbose,
75559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                    mOutStream, mErrStream);
75659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
7573d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            mOutStream.setPrefix(null);
7583d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            mErrStream.setPrefix(null);
7593d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
76059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            if (res != 0) {
76159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                // output error message and marker the project.
7623d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet                String message = String.format(Messages.Dalvik_Error_d, res);
7633d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet                throw new DexException(message);
76459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            }
7653d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        } catch (DexException e) {
7663d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            throw e;
7673d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        } catch (Throwable t) {
7683d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            String message = t.getMessage();
76959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            if (message == null) {
7703d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet                message = t.getClass().getCanonicalName();
77159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            }
77259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            message = String.format(Messages.Dalvik_Error_s, message);
77359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
7743d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            throw new DexException(message, t);
7753d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        }
77659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    }
77759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
77859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    /**
77959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * Executes aapt. If any error happen, files or the project will be marked.
780c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin     * @param command The command for aapt to execute. Currently supported: package and crunch
78159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @param osManifestPath The path to the manifest file
78259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @param osResPath The path to the res folder
78359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @param osAssetsPath The path to the assets folder. This can be null.
784c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin     * @param osOutFilePath The path to the temporary resource file to create,
785c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin     *   or in the case of crunching the path to the cache to create/update.
78659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @param configFilter The configuration filter for the resources to include
78759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * (used with -c option, for example "port,en,fr" to include portrait, English and French
78859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * resources.)
789853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * @param versionCode optional version code to insert in the manifest during packaging. If <=0
790853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * then no value is inserted
7913d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws AaptExecException
7923d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet     * @throws AaptResultException
79359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     */
794c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin    private void executeAapt(String aaptCommand, String osManifestPath,
79559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            List<String> osResPaths, String osAssetsPath, String osOutFilePath,
7963d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            String configFilter, int versionCode) throws AaptExecException, AaptResultException {
79759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
79859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
79981c5fb5448a6342cb3bb29ea501fccf95573288cXavier Ducrohet        @SuppressWarnings("deprecation") String aapt = target.getPath(IAndroidTarget.AAPT);
80081c5fb5448a6342cb3bb29ea501fccf95573288cXavier Ducrohet
80159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        // Create the command line.
80259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        ArrayList<String> commandArray = new ArrayList<String>();
80381c5fb5448a6342cb3bb29ea501fccf95573288cXavier Ducrohet        commandArray.add(aapt);
804c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        commandArray.add(aaptCommand);
80559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) {
80659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            commandArray.add("-v"); //$NON-NLS-1$
80759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        }
80859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
809c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        // Common to all commands
810c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        for (String path : osResPaths) {
811c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            commandArray.add("-S"); //$NON-NLS-1$
812c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            commandArray.add(path);
81359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        }
81459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
815c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        if (aaptCommand.equals(COMMAND_PACKAGE)) {
816c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            commandArray.add("-f");          //$NON-NLS-1$
817c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            commandArray.add("--no-crunch"); //$NON-NLS-1$
8183d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet
819c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            // if more than one res, this means there's a library (or more) and we need
820c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            // to activate the auto-add-overlay
821c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            if (osResPaths.size() > 1) {
822c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                commandArray.add("--auto-add-overlay"); //$NON-NLS-1$
823c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            }
824853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet
825c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            if (mDebugMode) {
826c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                commandArray.add("--debug-mode"); //$NON-NLS-1$
827c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            }
82859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
829c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            if (versionCode > 0) {
830c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                commandArray.add("--version-code"); //$NON-NLS-1$
831c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                commandArray.add(Integer.toString(versionCode));
832c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            }
83359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
834c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            if (configFilter != null) {
835c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                commandArray.add("-c"); //$NON-NLS-1$
836c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                commandArray.add(configFilter);
837c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            }
83859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
839c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            commandArray.add("-M"); //$NON-NLS-1$
840c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            commandArray.add(osManifestPath);
841c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
842c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            if (osAssetsPath != null) {
843c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                commandArray.add("-A"); //$NON-NLS-1$
844c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                commandArray.add(osAssetsPath);
845c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            }
84659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
847c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            commandArray.add("-I"); //$NON-NLS-1$
848c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            commandArray.add(target.getPath(IAndroidTarget.ANDROID_JAR));
84959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
850c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            commandArray.add("-F"); //$NON-NLS-1$
851c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            commandArray.add(osOutFilePath);
852c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        } else if (aaptCommand.equals(COMMAND_CRUNCH)) {
853c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            commandArray.add("-C"); //$NON-NLS-1$
854c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            commandArray.add(osOutFilePath);
855c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        }
85659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
85759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        String command[] = commandArray.toArray(
85859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                new String[commandArray.size()]);
85959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
86059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) {
86159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            StringBuilder sb = new StringBuilder();
86259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            for (String c : command) {
86359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                sb.append(c);
86459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                sb.append(' ');
86559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            }
86659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            AdtPlugin.printToConsole(mProject, sb.toString());
86759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        }
86859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
869c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        // Benchmarking start
870c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        long startAaptTime = 0;
871c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        if (BENCHMARK_FLAG) {
872c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            String msg = "BENCHMARK ADT: Starting " + aaptCommand  //$NON-NLS-1$
873c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                         + " call to Aapt";                        //$NON-NLS-1$
874c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg);
875c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            startAaptTime = System.nanoTime();
876c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        }
877c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
87859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        // launch
87959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        try {
88059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            // launch the command line process
88159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            Process process = Runtime.getRuntime().exec(command);
88259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
88359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            // list to store each line of stderr
8844152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet            ArrayList<String> stdErr = new ArrayList<String>();
88559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
88659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            // get the output and return code from the process
8874152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet            int returnCode = grabProcessOutput(mProject, process, stdErr);
88859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
8897139790c9af02de824c6f2dae7a68ff694ae1f19Xavier Ducrohet            if (mVerbose) {
8904152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet                for (String stdErrString : stdErr) {
8914152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet                    mOutStream.println(stdErrString);
89259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                }
89359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            }
8944152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet            if (returnCode != 0) {
8954152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet                throw new AaptResultException(returnCode,
8964152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet                        stdErr.toArray(new String[stdErr.size()]));
8977139790c9af02de824c6f2dae7a68ff694ae1f19Xavier Ducrohet            }
8983d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet        } catch (IOException e) {
8994152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet            String msg = String.format(Messages.AAPT_Exec_Error_s, command[0]);
9003d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            throw new AaptExecException(msg, e);
90159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        } catch (InterruptedException e) {
9024152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet            String msg = String.format(Messages.AAPT_Exec_Error_s, command[0]);
9033d3c3c3a3e4e05f7ae7a0dff440fe500f90b785cXavier Ducrohet            throw new AaptExecException(msg, e);
90459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        }
905c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin
906c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        // Benchmarking end
907c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        if (BENCHMARK_FLAG) {
908c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            String msg = "BENCHMARK ADT: Ending " + aaptCommand                  //$NON-NLS-1$
909c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                         + " call to Aapt.\nBENCHMARK ADT: Time Elapsed: "       //$NON-NLS-1$
910c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                         + ((System.nanoTime() - startAaptTime)/MILLION) + "ms"; //$NON-NLS-1$
911c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin            AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS, mProject, msg);
912c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin        }
91359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    }
91459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
91559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    /**
916bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet     * Computes all the project output and dependencies that must go into building the apk.
917bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet     *
918bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet     * @param resMarker
91959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @throws CoreException
92059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     */
921bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet    private void gatherPaths(ResourceMarker resMarker)
922bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            throws CoreException {
923bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
92459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
925bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        // get a java project for the project.
926bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        IJavaProject javaProject = JavaCore.create(mProject);
927bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet
928bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet
929bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        // get the output of the main project
930bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        IPath path = javaProject.getOutputLocation();
931bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        IResource outputResource = wsRoot.findMember(path);
932bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        if (outputResource != null && outputResource.getType() == IResource.FOLDER) {
933bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            mCompiledCodePaths.add(outputResource.getLocation().toOSString());
934237d006af115bf2fa05058015e8a15d4487e7fe1Dominic Mitchell        }
935237d006af115bf2fa05058015e8a15d4487e7fe1Dominic Mitchell
936bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        // we could use IJavaProject.getResolvedClasspath directly, but we actually
937bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        // want to see the containers themselves.
938bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        IClasspathEntry[] classpaths = javaProject.readRawClasspath();
939bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        if (classpaths != null) {
940bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            for (IClasspathEntry e : classpaths) {
941bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                // ignore non exported entries, unless it's the LIBRARIES container,
942bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                // in which case we always want it (there may be some older projects that
943bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                // have it as non exported).
944bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                if (e.isExported() ||
945bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                        (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER &&
946bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                         e.getPath().toString().equals(AdtConstants.CONTAINER_LIBRARIES))) {
947bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    handleCPE(e, javaProject, wsRoot, resMarker);
948237d006af115bf2fa05058015e8a15d4487e7fe1Dominic Mitchell                }
94959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            }
95059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        }
95159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    }
95259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
953bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet    private void handleCPE(IClasspathEntry entry, IJavaProject javaProject,
954bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            IWorkspaceRoot wsRoot, ResourceMarker resMarker) {
95559243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
956bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        // if this is a classpath variable reference, we resolve it.
957bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
958bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            entry = JavaCore.getResolvedClasspathEntry(entry);
959bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        }
96059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
961bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
962bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            IProject refProject = wsRoot.getProject(entry.getPath().lastSegment());
963bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            try {
964bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                // ignore if it's an Android project, or if it's not a Java Project
965bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                if (refProject.hasNature(JavaCore.NATURE_ID) &&
966bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                        refProject.hasNature(AdtConstants.NATURE_DEFAULT) == false) {
967bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    IJavaProject refJavaProject = JavaCore.create(refProject);
968babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet
969bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    // get the output folder
970bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    IPath path = refJavaProject.getOutputLocation();
971bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    IResource outputResource = wsRoot.findMember(path);
972bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    if (outputResource != null && outputResource.getType() == IResource.FOLDER) {
973bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                        mCompiledCodePaths.add(outputResource.getLocation().toOSString());
974bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    }
975babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                }
976bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            } catch (CoreException exception) {
977bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                // can't query the project nature? ignore
978bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            }
979433236156debbb84b13776649e20258c1fc51491Xavier Ducrohet
980bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        } else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
981bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            handleClasspathLibrary(entry, wsRoot, resMarker);
982bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet        } else if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
983bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            // get the container
984bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            try {
985bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                IClasspathContainer container = JavaCore.getClasspathContainer(
986bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                        entry.getPath(), javaProject);
987bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                // ignore the system and default_system types as they represent
988bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                // libraries that are part of the runtime.
989aea408b68a6f833327b6e0954a28f414f58133acXavier Ducrohet                if (container != null && container.getKind() == IClasspathContainer.K_APPLICATION) {
990bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    IClasspathEntry[] entries = container.getClasspathEntries();
991bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    for (IClasspathEntry cpe : entries) {
992bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                        handleCPE(cpe, javaProject, wsRoot, resMarker);
99359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                    }
99459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet                }
995bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            } catch (JavaModelException jme) {
996bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                // can't resolve the container? ignore it.
997bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", entry.getPath());
99859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet            }
99959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        }
100059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    }
100159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
1002bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet    private void handleClasspathLibrary(IClasspathEntry e, IWorkspaceRoot wsRoot,
1003bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet            ResourceMarker resMarker) {
1004babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet        // get the IPath
1005babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet        IPath path = e.getPath();
1006babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet
1007babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet        IResource resource = wsRoot.findMember(path);
100881c5fb5448a6342cb3bb29ea501fccf95573288cXavier Ducrohet
100981c5fb5448a6342cb3bb29ea501fccf95573288cXavier Ducrohet        if (resource != null && resource.getType() == IResource.PROJECT) {
101081c5fb5448a6342cb3bb29ea501fccf95573288cXavier Ducrohet            // if it's a project we should just ignore it because it's going to be added
101181c5fb5448a6342cb3bb29ea501fccf95573288cXavier Ducrohet            // later when we add all the referenced projects.
101281c5fb5448a6342cb3bb29ea501fccf95573288cXavier Ducrohet
101312d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye        } else if (SdkConstants.EXT_JAR.equalsIgnoreCase(path.getFileExtension())) {
101481c5fb5448a6342cb3bb29ea501fccf95573288cXavier Ducrohet            // case of a jar file (which could be relative to the workspace or a full path)
1015babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet            if (resource != null && resource.exists() &&
1016babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                    resource.getType() == IResource.FILE) {
1017bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                mCompiledCodePaths.add(resource.getLocation().toOSString());
1018babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet            } else {
1019babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                // if the jar path doesn't match a workspace resource,
1020babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                // then we get an OSString and check if this links to a valid file.
1021babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                String osFullPath = path.toOSString();
1022babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet
1023babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                File f = new File(osFullPath);
1024babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                if (f.isFile()) {
1025bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    mCompiledCodePaths.add(osFullPath);
1026babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                } else {
1027babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                    String message = String.format( Messages.Couldnt_Locate_s_Error,
1028babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                            path);
1029babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                    // always output to the console
1030babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                    mOutStream.println(message);
1031babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet
1032babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                    // put a marker
1033babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                    if (resMarker != null) {
1034babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                        resMarker.setWarning(mProject, message);
1035babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                    }
1036babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                }
1037babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet            }
1038babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet        } else {
1039babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet            // this can be the case for a class folder.
1040babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet            if (resource != null && resource.exists() &&
1041babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                    resource.getType() == IResource.FOLDER) {
1042bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                mCompiledCodePaths.add(resource.getLocation().toOSString());
1043babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet            } else {
1044babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                // if the path doesn't match a workspace resource,
1045babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                // then we get an OSString and check if this links to a valid folder.
1046babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                String osFullPath = path.toOSString();
1047babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet
1048babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                File f = new File(osFullPath);
1049babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                if (f.isDirectory()) {
1050bcf44e9429811b3e1f97d21ea92816957bce2601Xavier Ducrohet                    mCompiledCodePaths.add(osFullPath);
1051babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet                }
1052babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet            }
1053babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet        }
1054babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet    }
1055babf25ca7162849f0145f75be1b6c09b359b122cXavier Ducrohet
105659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    /**
105759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * Checks a {@link IFile} to make sure it should be packaged as standard resources.
105859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @param file the IFile representing the file.
105959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @return true if the file should be packaged as standard java resources.
106059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     */
106159f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet    public static boolean checkFileForPackaging(IFile file) {
106259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        String name = file.getName();
106359243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
106459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        String ext = file.getFileExtension();
10657c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet        return ApkBuilder.checkFileForPackaging(name, ext);
106659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    }
106759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
106859243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    /**
106959243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * Checks whether an {@link IFolder} and its content is valid for packaging into the .apk as
107059243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * standard Java resource.
107159243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     * @param folder the {@link IFolder} to check.
107259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet     */
107359f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet    public static boolean checkFolderForPackaging(IFolder folder) {
107459243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet        String name = folder.getName();
10757c19dcf5aead68f4f6675db0bac6b495396e2967Xavier Ducrohet        return ApkBuilder.checkFolderForPackaging(name);
107659243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet    }
107759243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet
1078853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet    /**
1079a0340fdf211a94d4d96a9e063386b0eccae9b74cXavier Ducrohet     * Returns a list of {@link IJavaProject} matching the provided {@link IProject} objects.
1080853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * @param projects the IProject objects.
1081a0340fdf211a94d4d96a9e063386b0eccae9b74cXavier Ducrohet     * @return a new list object containing the IJavaProject object for the given IProject objects.
1082853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     * @throws CoreException
1083853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet     */
1084a0340fdf211a94d4d96a9e063386b0eccae9b74cXavier Ducrohet    public static List<IJavaProject> getJavaProjects(List<IProject> projects) throws CoreException {
1085853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet        ArrayList<IJavaProject> list = new ArrayList<IJavaProject>();
1086853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet
1087853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet        for (IProject p : projects) {
1088853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet            if (p.isOpen() && p.hasNature(JavaCore.NATURE_ID)) {
1089853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet
1090853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet                list.add(JavaCore.create(p));
1091853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet            }
1092853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet        }
1093853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet
1094a0340fdf211a94d4d96a9e063386b0eccae9b74cXavier Ducrohet        return list;
1095853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet    }
1096853ab5a62d09675e0921d2eed60c02f66e3d0050Xavier Ducrohet
109759f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet    /**
109859f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet     * Get the stderr output of a process and return when the process is done.
10994152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet     * @param process The process to get the output from
11004152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet     * @param stderr The array to store the stderr output
110159f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet     * @return the process return code.
110259f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet     * @throws InterruptedException
110359f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet     */
11048c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael    public final static int grabProcessOutput(
11058c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael            final IProject project,
11068c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael            final Process process,
11074152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet            final ArrayList<String> stderr)
110859f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet            throws InterruptedException {
110959f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet
11108c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael        return GrabProcessOutput.grabProcessOutput(
11118c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael                process,
11124152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet                Wait.WAIT_FOR_READERS, // we really want to make sure we get all the output!
11138c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael                new IProcessOutput() {
111459f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet
11158c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael                    @SuppressWarnings("unused")
11168c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael                    @Override
11177e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye                    public void out(@Nullable String line) {
111859f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet                        if (line != null) {
1119c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                            // If benchmarking always print the lines that
1120c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                            // correspond to benchmarking info returned by ADT
1121c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                            if (BENCHMARK_FLAG && line.startsWith("BENCHMARK:")) {    //$NON-NLS-1$
1122c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                                AdtPlugin.printBuildToConsole(BuildVerbosity.ALWAYS,
1123c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                                        project, line);
1124c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                            } else {
1125c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                                AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE,
1126c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                                        project, line);
1127c15b4fdc76142c61db1ec29feb2afdfaea43a84bJosiah Gaskin                            }
112859f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet                        }
112959f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet                    }
113059f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet
11318c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael                    @Override
11327e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye                    public void err(@Nullable String line) {
11338c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael                        if (line != null) {
11344152b691d53c5621c186bbd1a41f31024809aa7aXavier Ducrohet                            stderr.add(line);
11358818ca4db2f1ae396964912bf8035ee88988f4ddXavier Ducrohet                            if (BuildVerbosity.VERBOSE == AdtPrefs.getPrefs().getBuildVerbosity()) {
11368818ca4db2f1ae396964912bf8035ee88988f4ddXavier Ducrohet                                AdtPlugin.printErrorToConsole(project, line);
11378818ca4db2f1ae396964912bf8035ee88988f4ddXavier Ducrohet                            }
11388c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael                        }
11398c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael                    }
11408c578aff7c5d84bc38d5a6d391986aece3cd2e19Raphael                });
114159f8d5012426884e40b77b02a7c3274eb66019a1Xavier Ducrohet    }
114259243b8de886379e7154c886adbefc74dac24055Xavier Ducrohet}
1143