aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse/plugins/com.android.ide.eclipse.adt
diff options
context:
space:
mode:
authorXavier Ducrohet <xav@android.com>2010-06-14 14:45:35 -0700
committerXavier Ducrohet <xav@android.com>2010-06-15 11:32:21 -0700
commit853ab5a62d09675e0921d2eed60c02f66e3d0050 (patch)
treecba298e9ba9fcd185f93391f9153fde98288e213 /eclipse/plugins/com.android.ide.eclipse.adt
parentd931df6de27a068475b4b9760ef3800dfcb6dbd6 (diff)
downloadsdk-853ab5a62d09675e0921d2eed60c02f66e3d0050.zip
sdk-853ab5a62d09675e0921d2eed60c02f66e3d0050.tar.gz
sdk-853ab5a62d09675e0921d2eed60c02f66e3d0050.tar.bz2
ADT: Multi-apk export action.
This is a first step with no UI. Still needed: - handling signing - add control to how ApkBuilderHelper handles errors to prevent output to the console during export. Change-Id: Id44d708c2b0f5bb52508c33a241bbe921b4297e1
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml51
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/ConvertToAndroidAction.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/FixProjectAction.java6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/MultiApkExportAction.java298
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/RenamePackageAction.java20
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java31
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilderHelper.java75
7 files changed, 420 insertions, 63 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
index 78ebac3..13cf652 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
@@ -207,16 +207,21 @@
<separator name="group1"/>
</menu>
<visibility>
- <not>
- <or>
- <objectState
- name="projectNature"
- value="com.android.ide.eclipse.adt.AndroidNature"/>
- <objectState
- name="open"
- value="false"/>
- </or>
- </not>
+ <and>
+ <not>
+ <objectState
+ name="projectNature"
+ value="com.android.ide.eclipse.adt.AndroidNature"/>
+ </not>
+ <not>
+ <objectState
+ name="projectNature"
+ value="com.android.ide.eclipse.adt.AndroidExportNature"/>
+ </not>
+ <objectState
+ name="open"
+ value="true"/>
+ </and>
</visibility>
<action
class="com.android.ide.eclipse.adt.internal.actions.ConvertToAndroidAction"
@@ -284,7 +289,31 @@
label="Rename Application Package"
menubarPath="com.android.ide.eclipse.adt.AndroidTools/group3"/>
</objectContribution>
-
+ <objectContribution
+ id="com.android.ide.eclipse.adt.contribution3"
+ nameFilter="*"
+ objectClass="org.eclipse.core.resources.IProject"
+ adaptable="true">
+ <menu
+ id="com.android.ide.eclipse.adt.AndroidTools"
+ label="Android Tools"
+ path="additions">
+ <separator name="group1"/>
+ <separator name="group2"/>
+ </menu>
+ <filter
+ name="projectNature"
+ value="com.android.ide.eclipse.adt.AndroidExportNature">
+ </filter>
+ <action
+ class="com.android.ide.eclipse.adt.internal.actions.MultiApkExportAction"
+ enablesFor="1"
+ id="com.android.ide.eclipse.adt.actions.MultiApkExportAction"
+ label="Export APKs"
+ menubarPath="com.android.ide.eclipse.adt.AndroidTools/group1"
+ tooltip="Exports multiple APKs from the export project configuration">
+ </action>
+ </objectContribution>
</extension>
<extension
point="org.eclipse.ui.preferencePages">
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/ConvertToAndroidAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/ConvertToAndroidAction.java
index ad9fce0..92604fb 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/ConvertToAndroidAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/ConvertToAndroidAction.java
@@ -84,7 +84,7 @@ public class ConvertToAndroidAction implements IObjectActionDelegate {
* @see IActionDelegate#selectionChanged(IAction, ISelection)
*/
public void selectionChanged(IAction action, ISelection selection) {
- this.mSelection = selection;
+ mSelection = selection;
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/FixProjectAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/FixProjectAction.java
index cb4f7e7..8a2400b 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/FixProjectAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/FixProjectAction.java
@@ -75,7 +75,7 @@ public class FixProjectAction implements IObjectActionDelegate {
}
public void selectionChanged(IAction action, ISelection selection) {
- this.mSelection = selection;
+ mSelection = selection;
}
private void fixProject(final IProject project) {
@@ -92,7 +92,7 @@ public class FixProjectAction implements IObjectActionDelegate {
if (monitor != null) {
monitor.worked(1);
}
-
+
// fix the nature order to have the proper project icon
ProjectHelper.fixProjectNatureOrder(project);
if (monitor != null) {
@@ -114,7 +114,7 @@ public class FixProjectAction implements IObjectActionDelegate {
if (monitor != null) {
monitor.worked(1);
}
-
+
return Status.OK_STATUS;
} catch (JavaModelException e) {
return e.getJavaModelStatus();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/MultiApkExportAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/MultiApkExportAction.java
new file mode 100644
index 0000000..fe05b1d
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/MultiApkExportAction.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.actions;
+
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.AndroidConstants;
+import com.android.ide.eclipse.adt.internal.build.ApkBuilderHelper;
+import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
+import com.android.ide.eclipse.adt.internal.project.ProjectState;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.ide.eclipse.adt.io.IFolderWrapper;
+import com.android.sdklib.SdkConstants;
+import com.android.sdklib.internal.export.ApkData;
+import com.android.sdklib.internal.export.MultiApkExportHelper;
+import com.android.sdklib.internal.export.ProjectConfig;
+import com.android.sdklib.internal.export.MultiApkExportHelper.ExportException;
+import com.android.sdklib.internal.export.MultiApkExportHelper.Target;
+import com.android.sdklib.internal.project.ProjectProperties;
+import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PlatformUI;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Multiple APK export Action.
+ * The action is triggered on a project selection, and performs a full APK export based on the
+ * content of the export.properties file.
+ */
+public class MultiApkExportAction implements IObjectActionDelegate {
+
+ private ISelection mSelection;
+
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ // pass
+ }
+
+ public void run(IAction action) {
+ if (mSelection instanceof IStructuredSelection) {
+ for (Iterator<?> it = ((IStructuredSelection)mSelection).iterator(); it.hasNext();) {
+ Object element = it.next();
+ IProject project = null;
+ if (element instanceof IProject) {
+ project = (IProject)element;
+ } else if (element instanceof IAdaptable) {
+ project = (IProject)((IAdaptable)element).getAdapter(IProject.class);
+ }
+ if (project != null) {
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ final IProject fProject = project;
+ try {
+ workbench.getProgressService().busyCursorWhile(new IRunnableWithProgress() {
+ /**
+ * Run the export.
+ * @throws InvocationTargetException
+ * @throws InterruptedException
+ */
+ public void run(IProgressMonitor monitor)
+ throws InvocationTargetException, InterruptedException {
+ try {
+ runMultiApkExport(fProject, monitor);
+ } catch (Exception e) {
+ AdtPlugin.logAndPrintError(e, fProject.getName(),
+ "Failed to export project: %1$s", e.getMessage());
+ } finally {
+ monitor.done();
+ }
+ }
+ });
+ } catch (Exception e) {
+ AdtPlugin.logAndPrintError(e, project.getName(),
+ "Failed to export project: %1$s",
+ e.getMessage());
+ }
+ }
+ }
+ }
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ mSelection = selection;
+ }
+
+ /**
+ * Runs the multi-apk export.
+ * @param exportProject the main "export" project.
+ * @param monitor the progress monitor.
+ * @throws ExportException
+ * @throws CoreException
+ */
+ private void runMultiApkExport(IProject exportProject, IProgressMonitor monitor)
+ throws ExportException, CoreException {
+
+ ProjectProperties props = ProjectProperties.load(new IFolderWrapper(exportProject),
+ PropertyType.EXPORT);
+
+ // get some props and make sure their values are valid.
+
+ String appPackage = props.getProperty(ProjectProperties.PROPERTY_PACKAGE);
+ if (appPackage == null || appPackage.length() == 0) {
+ throw new IllegalArgumentException("Invalid 'package' property values.");
+ }
+
+ String version = props.getProperty(ProjectProperties.PROPERTY_VERSIONCODE);
+ int versionCode;
+ try {
+ versionCode = Integer.parseInt(version);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("version value is not a valid integer.", e);
+ }
+
+ String projects = props.getProperty(ProjectProperties.PROPERTY_PROJECTS);
+ if (projects == null || projects.length() == 0) {
+ throw new IllegalArgumentException("Missing project list.");
+ }
+
+ // create the multi apk helper to get the list of apk to export.
+ MultiApkExportHelper helper = new MultiApkExportHelper(
+ exportProject.getLocation().toOSString(),
+ appPackage, versionCode, Target.RELEASE, System.out);
+
+ List<ApkData> apks = helper.getApkData(projects);
+
+ // list of projects that have been resolved (ie the IProject has been found from the
+ // ProjectConfig) and compiled.
+ HashMap<ProjectConfig, ProjectState> resolvedProjects =
+ new HashMap<ProjectConfig, ProjectState>();
+
+ IWorkspace ws = ResourcesPlugin.getWorkspace();
+ IWorkspaceRoot wsRoot = ws.getRoot();
+
+ // bin folder for the export project
+ IFolder binFolder = exportProject.getFolder(SdkConstants.FD_OUTPUT);
+ if (binFolder.exists() == false) {
+ binFolder.create(true, true, monitor);
+ }
+
+ for (ApkData apk : apks) {
+ // find the IProject object for this apk.
+ ProjectConfig projectConfig = apk.getProjectConfig();
+ ProjectState projectState = resolvedProjects.get(projectConfig);
+ if (projectState == null) {
+ // first time? resolve the project and compile it.
+ IPath path = exportProject.getFullPath().append(projectConfig.getRelativePath());
+
+ IResource res = wsRoot.findMember(path);
+ if (res.getType() != IResource.PROJECT) {
+ throw new IllegalArgumentException(String.format(
+ "%1$s does not resolve to a project.",
+ projectConfig.getRelativePath()));
+ }
+
+ IProject project = (IProject)res;
+
+ projectState = Sdk.getProjectState(project);
+ if (projectState == null) {
+ throw new IllegalArgumentException(String.format(
+ "State for project %1$s could not be loaded.",
+ project.getName()));
+ }
+
+ if (projectState.isLibrary()) {
+ throw new IllegalArgumentException(String.format(
+ "Project %1$s is a library and cannot be part of a multi-apk export.",
+ project.getName()));
+ }
+
+ // build the project, mainly for the java compilation. The rest is handled below.
+ project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor);
+
+ // store the resolved project in the map.
+ resolvedProjects.put(projectConfig, projectState);
+ }
+
+ Map<String, String> variantMap = apk.getSoftVariantMap();
+
+ if (variantMap.size() > 0) {
+ // if there are soft variants, only export those.
+ for (Entry<String, String> entry : variantMap.entrySet()) {
+ buildVariant(wsRoot, projectState, appPackage, versionCode, apk, entry,
+ binFolder);
+ }
+ } else {
+ buildVariant(wsRoot, projectState, appPackage, versionCode, apk,
+ null /*soft variant*/, binFolder);
+ }
+ }
+
+ helper.writeLogs();
+ }
+
+ /**
+ * Builds a particular variant of an APK
+ * @param wsRoot the workspace root
+ * @param projectState the project to export
+ * @param appPackage the application package
+ * @param versionCode the major version code.
+ * @param apk the {@link ApkData} describing how the export should happen.
+ * @param softVariant an optional soft variant info. The entry contains (name, resource filter).
+ * @param binFolder the binFolder where the file must be created.
+ * @throws CoreException
+ */
+ private void buildVariant(IWorkspaceRoot wsRoot, ProjectState projectState, String appPackage,
+ int versionCode, ApkData apk, Entry<String, String> softVariant, IFolder binFolder)
+ throws CoreException {
+ // get the libraries for this project
+ IProject[] libProjects = projectState.getLibraryProjects();
+
+ IProject project = projectState.getProject();
+ IJavaProject javaProject = JavaCore.create(project);
+
+ int compositeVersionCode = apk.getCompositeVersionCode(versionCode);
+
+ // figure out the file names
+ String pkgName = project.getName() + "-" + apk.getBuildInfo();
+ String finalNameRoot = appPackage + "-" + compositeVersionCode;
+ if (softVariant != null) {
+ String tmp = "-" + softVariant.getKey();
+ pkgName += tmp;
+ finalNameRoot += tmp;
+ }
+
+ pkgName += ".ap_";
+ String outputName = finalNameRoot + "-unsigned.apk";
+
+ ApkBuilderHelper helper = new ApkBuilderHelper(project, System.out, System.err);
+
+ // get the manifest file
+ IFile manifestFile = project.getFile(SdkConstants.FN_ANDROID_MANIFEST_XML);
+ // get the project bin folder
+ IFolder projectBinFolder = wsRoot.getFolder(javaProject.getOutputLocation());
+ String projectBinFolderPath = projectBinFolder.getLocation().toOSString();
+
+ // package the resources
+ if (helper.packageResources(manifestFile, libProjects,
+ softVariant != null ? softVariant.getValue() : null, compositeVersionCode,
+ projectBinFolderPath, pkgName) == false) {
+ return;
+ }
+
+ apk.setOutputName(softVariant != null ? softVariant.getKey() : null, outputName);
+
+ // do the final export.
+ IFile dexFile = projectBinFolder.getFile(AndroidConstants.FN_CLASSES_DEX);
+ String outputFile = binFolder.getFile(outputName).getLocation().toOSString();
+
+ // get the list of referenced projects.
+ IProject[] javaRefs = ProjectHelper.getReferencedProjects(project);
+ IJavaProject[] referencedJavaProjects = ApkBuilderHelper.getJavaProjects(javaRefs);
+
+ helper.finalPackage(new File(projectBinFolderPath, pkgName).getAbsolutePath(),
+ dexFile.getLocation().toOSString(),
+ outputFile, javaProject, libProjects, referencedJavaProjects,
+ apk.getAbi(), false /*debuggable*/);
+
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/RenamePackageAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/RenamePackageAction.java
index e8f8ed0..f06e00d 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/RenamePackageAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/RenamePackageAction.java
@@ -126,11 +126,11 @@ public class RenamePackageAction implements IObjectActionDelegate {
* @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
*/
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
- this.mTargetPart = targetPart;
+ mTargetPart = targetPart;
}
public void selectionChanged(IAction action, ISelection selection) {
- this.mSelection = selection;
+ mSelection = selection;
}
/**
@@ -184,7 +184,7 @@ public class RenamePackageAction implements IObjectActionDelegate {
final String old_package_name_string = manifestData.getPackage();
final AST ast_validator = AST.newAST(AST.JLS3);
- this.mOldPackageName = ast_validator.newName(old_package_name_string);
+ mOldPackageName = ast_validator.newName(old_package_name_string);
IInputValidator validator = new IInputValidator() {
@@ -207,7 +207,7 @@ public class RenamePackageAction implements IObjectActionDelegate {
validator);
if (dialog.open() == Window.OK) {
- this.mNewPackageName = ast_validator.newName(dialog.getValue());
+ mNewPackageName = ast_validator.newName(dialog.getValue());
initiateAndroidPackageRefactoring(project);
}
}
@@ -565,8 +565,8 @@ public class RenamePackageAction implements IObjectActionDelegate {
final ASTRewrite mRewriter;
ImportVisitor(AST ast) {
- this.mAst = ast;
- this.mRewriter = ASTRewrite.create(ast);
+ mAst = ast;
+ mRewriter = ASTRewrite.create(ast);
}
public TextEdit getTextEdit() {
@@ -591,7 +591,7 @@ public class RenamePackageAction implements IObjectActionDelegate {
if (qualified_import_name.getName().getIdentifier()
.equals(AndroidConstants.FN_RESOURCE_BASE)) {
- this.mRewriter.replace(qualified_import_name.getQualifier(), mNewPackageName,
+ mRewriter.replace(qualified_import_name.getQualifier(), mNewPackageName,
null);
}
}
@@ -619,7 +619,7 @@ public class RenamePackageAction implements IObjectActionDelegate {
IProject mProject;
ApplicationPackageNameRefactoring(final IProject project) {
- this.mProject = project;
+ mProject = project;
}
@Override
@@ -636,7 +636,7 @@ public class RenamePackageAction implements IObjectActionDelegate {
// Accurate refactoring of the "shorthand" names in
// AndroidManifest.xml
// depends on not having compilation errors.
- if (this.mProject.findMaxProblemSeverity(
+ if (mProject.findMaxProblemSeverity(
IMarker.PROBLEM,
true,
IResource.DEPTH_INFINITE) == IMarker.SEVERITY_ERROR) {
@@ -653,7 +653,7 @@ public class RenamePackageAction implements IObjectActionDelegate {
// Traverse all files in the project, building up a list of changes
JavaFileVisitor file_visitor = new JavaFileVisitor();
- this.mProject.accept(file_visitor);
+ mProject.accept(file_visitor);
return file_visitor.getChange();
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java
index c3983b0..9cd3036 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java
@@ -213,7 +213,7 @@ public class ApkBuilder extends BaseBuilder {
// get the list of referenced projects.
javaProjects = ProjectHelper.getReferencedProjects(project);
- IJavaProject[] referencedJavaProjects = getJavaProjects(javaProjects);
+ IJavaProject[] referencedJavaProjects = ApkBuilderHelper.getJavaProjects(javaProjects);
// mix the java project and the library projects
final int libCount = libProjects != null ? libProjects.length : 0;
@@ -427,7 +427,8 @@ public class ApkBuilder extends BaseBuilder {
removeMarkersFromContainer(project, AndroidConstants.MARKER_AAPT_PACKAGE);
// need to figure out some path before we can execute aapt;
- if (helper.packageResources( manifestFile, libProjects, osBinPath,
+ if (helper.packageResources( manifestFile, libProjects, null /*resfilter*/,
+ 0 /*versionCode */, osBinPath,
AndroidConstants.FN_RESOURCES_AP_) == false) {
// aapt failed. Whatever files that needed to be marked
// have already been marked. We just return.
@@ -477,9 +478,10 @@ public class ApkBuilder extends BaseBuilder {
String classesDexPath = osBinPath + File.separator +
AndroidConstants.FN_CLASSES_DEX;
- if (helper.finalPackage(osBinPath + File.separator + AndroidConstants.FN_RESOURCES_AP_,
- classesDexPath, osFinalPackagePath, javaProject, libProjects,
- referencedJavaProjects, debuggable) == false) {
+ if (helper.finalPackage(
+ osBinPath + File.separator + AndroidConstants.FN_RESOURCES_AP_,
+ classesDexPath, osFinalPackagePath, javaProject, libProjects,
+ referencedJavaProjects, null /*abiFilter*/, debuggable) == false) {
return allRefProjects;
}
@@ -537,25 +539,6 @@ public class ApkBuilder extends BaseBuilder {
mBuildFinalPackage = loadProjectBooleanProperty(PROPERTY_BUILD_APK, true);
}
- /**
- * Returns an array of {@link IJavaProject} matching the provided {@link IProject} objects.
- * @param projects the IProject objects.
- * @return an array, always. Can be empty.
- * @throws CoreException
- */
- private IJavaProject[] getJavaProjects(IProject[] projects) throws CoreException {
- ArrayList<IJavaProject> list = new ArrayList<IJavaProject>();
-
- for (IProject p : projects) {
- if (p.isOpen() && p.hasNature(JavaCore.NATURE_ID)) {
-
- list.add(JavaCore.create(p));
- }
- }
-
- return list.toArray(new IJavaProject[list.size()]);
- }
-
@Override
protected void abortOnBadSetup(IJavaProject javaProject) throws CoreException {
super.abortOnBadSetup(javaProject);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilderHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilderHelper.java
index fa5993e..954e2ed 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilderHelper.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilderHelper.java
@@ -66,7 +66,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-class ApkBuilderHelper {
+public class ApkBuilderHelper {
final static String GDBSERVER_NAME = "gdbserver"; //$NON-NLS-1$
@@ -121,15 +121,26 @@ class ApkBuilderHelper {
private final JavaAndNativeResourceFilter mResourceFilter = new JavaAndNativeResourceFilter();
- ApkBuilderHelper(IProject project, PrintStream outStream, PrintStream errStream) {
+ public ApkBuilderHelper(IProject project, PrintStream outStream, PrintStream errStream) {
mProject = project;
mOutStream = outStream;
mErrStream = errStream;
}
-
- boolean packageResources(IFile manifestFile, IProject[] libProjects,
- String outputFolder, String outputFilename) {
+ /**
+ * Packages the resources of the projet into a .ap_ file.
+ * @param manifestFile the manifest of the project.
+ * @param libProjects the list of library projects that this project depends on.
+ * @param resFilter an optional resource filter to be used with the -c option of aapt. If null
+ * no filters are used.
+ * @param versionCode an optional versionCode to be inserted in the manifest during packaging.
+ * If the value is <=0, no values are inserted.
+ * @param outputFolder where to write the resource ap_ file.
+ * @param outputFilename the name of the resource ap_ file.
+ * @return true if success.
+ */
+ public boolean packageResources(IFile manifestFile, IProject[] libProjects, String resFilter,
+ int versionCode, String outputFolder, String outputFilename) {
// need to figure out some path before we can execute aapt;
// get the resource folder
@@ -170,8 +181,8 @@ class ApkBuilderHelper {
// build the default resource package
if (executeAapt(osManifestPath, osResPaths, osAssetsPath,
- outputFolder + File.separator + outputFilename,
- null /*configFilter*/) == false) {
+ outputFolder + File.separator + outputFilename, resFilter,
+ versionCode) == false) {
// aapt failed. Whatever files that needed to be marked
// have already been marked. We just return.
return false;
@@ -191,13 +202,15 @@ class ApkBuilderHelper {
* @param javaProject the java project being compiled
* @param libProjects an optional list of library projects (can be null)
* @param referencedJavaProjects referenced projects.
+ * @param abiFilter an optional filter. If not null, then only the matching ABI is included in
+ * the final archive
* @param debuggable whether the project manifest has debuggable==true. If true, any gdbserver
* executables will be packaged with the native libraries.
* @return true if success, false otherwise.
*/
- boolean finalPackage(String intermediateApk, String dex, String output,
+ public boolean finalPackage(String intermediateApk, String dex, String output,
final IJavaProject javaProject, IProject[] libProjects,
- IJavaProject[] referencedJavaProjects, boolean debuggable) {
+ IJavaProject[] referencedJavaProjects, String abiFilter, boolean debuggable) {
FileOutputStream fos = null;
try {
@@ -327,7 +340,7 @@ class ApkBuilderHelper {
if (libFolder != null && libFolder.exists() &&
libFolder.getType() == IResource.FOLDER) {
// look inside and put .so in lib/* by keeping the relative folder path.
- writeNativeLibraries((IFolder) libFolder, builder, debuggable);
+ writeNativeLibraries((IFolder) libFolder, builder, abiFilter, debuggable);
}
// write the native libraries for the library projects.
@@ -337,7 +350,7 @@ class ApkBuilderHelper {
if (libFolder != null && libFolder.exists() &&
libFolder.getType() == IResource.FOLDER) {
// look inside and put .so in lib/* by keeping the relative folder path.
- writeNativeLibraries((IFolder) libFolder, builder, debuggable);
+ writeNativeLibraries((IFolder) libFolder, builder, abiFilter, debuggable);
}
}
}
@@ -505,11 +518,13 @@ class ApkBuilderHelper {
* @param configFilter The configuration filter for the resources to include
* (used with -c option, for example "port,en,fr" to include portrait, English and French
* resources.)
+ * @param versionCode optional version code to insert in the manifest during packaging. If <=0
+ * then no value is inserted
* @return true if success, false otherwise.
*/
private boolean executeAapt(String osManifestPath,
List<String> osResPaths, String osAssetsPath, String osOutFilePath,
- String configFilter) {
+ String configFilter, int versionCode) {
IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
// Create the command line.
@@ -527,6 +542,11 @@ class ApkBuilderHelper {
commandArray.add("--auto-add-overlay"); //$NON-NLS-1$
}
+ if (versionCode > 0) {
+ commandArray.add("--version-code"); //$NON-NLS-1$
+ commandArray.add(Integer.toString(versionCode));
+ }
+
if (configFilter != null) {
commandArray.add("-c"); //$NON-NLS-1$
commandArray.add(configFilter);
@@ -631,19 +651,26 @@ class ApkBuilderHelper {
*
* @param rootFolder The folder containing the native libraries.
* @param jarBuilder the {@link SignedJarBuilder} used to create the archive.
+ * @param abiFilter an optional filter. If not null, then only the matching ABI is included in
+ * the final archive
* @param debuggable whether the application is debuggable. If <code>true</code> then gdbserver
* executables will be packaged as well.
* @throws CoreException
* @throws IOException
*/
private void writeNativeLibraries(IFolder rootFolder, SignedJarBuilder jarBuilder,
- boolean debuggable)
- throws CoreException, IOException {
+ String abiFilter, boolean debuggable) throws CoreException, IOException {
// the native files must be under a single sub-folder under the main root folder.
// the sub-folder represents the abi for the native libs
IResource[] abis = rootFolder.members();
for (IResource abi : abis) {
if (abi.getType() == IResource.FOLDER) { // ignore non folders.
+
+ // check the abi filter and reject all other ABIs
+ if (abiFilter != null && abiFilter.equals(abi.getName()) == false) {
+ continue;
+ }
+
IResource[] libs = ((IFolder)abi).members();
for (IResource lib : libs) {
@@ -908,4 +935,24 @@ class ApkBuilderHelper {
return JavaResourceFilter.checkFolderForPackaging(name);
}
+ /**
+ * Returns an array of {@link IJavaProject} matching the provided {@link IProject} objects.
+ * @param projects the IProject objects.
+ * @return an array, always. Can be empty.
+ * @throws CoreException
+ */
+ public static IJavaProject[] getJavaProjects(IProject[] projects) throws CoreException {
+ ArrayList<IJavaProject> list = new ArrayList<IJavaProject>();
+
+ for (IProject p : projects) {
+ if (p.isOpen() && p.hasNature(JavaCore.NATURE_ID)) {
+
+ list.add(JavaCore.create(p));
+ }
+ }
+
+ return list.toArray(new IJavaProject[list.size()]);
+ }
+
+
}