1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ant; 18 19 import com.android.annotations.NonNull; 20 import com.android.manifmerger.ICallback; 21 import com.android.manifmerger.ManifestMerger; 22 import com.android.manifmerger.MergerLog; 23 import com.android.sdklib.IAndroidTarget; 24 import com.android.sdklib.SdkManager; 25 import com.android.sdklib.io.FileOp; 26 import com.android.utils.StdLogger; 27 28 import org.apache.tools.ant.BuildException; 29 import org.apache.tools.ant.types.Path; 30 31 import java.io.File; 32 import java.io.IOException; 33 import java.util.ArrayList; 34 import java.util.List; 35 36 public class ManifestMergerTask extends SingleDependencyTask { 37 38 private String mAppManifest; 39 private String mOutManifest; 40 41 private ArrayList<Path> mLibraryPaths; 42 private boolean mEnabled = false; 43 setAppManifest(Path appManifest)44 public void setAppManifest(Path appManifest) { 45 mAppManifest = TaskHelper.checkSinglePath("appManifest", appManifest); 46 } 47 setOutManifest(Path outManifest)48 public void setOutManifest(Path outManifest) { 49 mOutManifest = TaskHelper.checkSinglePath("outManifest", outManifest); 50 } 51 setEnabled(boolean enabled)52 public void setEnabled(boolean enabled) { 53 mEnabled = enabled; 54 } 55 56 /** 57 * Returns an object representing a nested <var>library</var> element. 58 */ createLibrary()59 public Object createLibrary() { 60 if (mLibraryPaths == null) { 61 mLibraryPaths = new ArrayList<Path>(); 62 } 63 64 Path path = new Path(getProject()); 65 mLibraryPaths.add(path); 66 67 return path; 68 } 69 70 @Override execute()71 public void execute() throws BuildException { 72 if (mAppManifest == null) { 73 throw new BuildException("Missing attribute appManifest"); 74 } 75 if (mOutManifest == null) { 76 throw new BuildException("Missing attribute outManifest"); 77 } 78 79 // if we merge, then get the rest of the input paths. 80 List<File> libraries = new ArrayList<File>(); 81 if (mLibraryPaths != null) { 82 for (Path pathList : mLibraryPaths) { 83 for (String path : pathList.list()) { 84 libraries.add(new File(path)); 85 } 86 } 87 } 88 89 // prepare input files 90 ArrayList<File> allInputs = new ArrayList<File>(libraries.size() + 1); 91 92 // always: the input manifest. 93 File appManifestFile = new File(mAppManifest); 94 allInputs.add(appManifestFile); 95 96 // if enabled: add the libraries 97 if (mEnabled) { 98 allInputs.addAll(libraries); 99 } 100 101 // figure out the path to the dependency file. 102 String depFile = mOutManifest + ".d"; 103 104 // get InputPath with no extension restrictions 105 List<InputPath> inputPaths = getInputPaths(allInputs, null /*extensionsToCheck*/, 106 null /*factory*/); 107 108 if (initDependencies(depFile, inputPaths) && dependenciesHaveChanged() == false) { 109 System.out.println( 110 "No changes in the AndroidManifest files."); 111 return; 112 } 113 114 System.out.println("Merging AndroidManifest files into one."); 115 116 if (mEnabled == false || libraries.size() == 0) { 117 if (mEnabled == false) { 118 System.out.println("Manifest merger disabled. Using project manifest only."); 119 } else { 120 System.out.println("No libraries. Using project manifest only."); 121 } 122 // no merge (disabled or nothing to merge)? do a simple copy. 123 try { 124 new FileOp().copyFile(appManifestFile, new File(mOutManifest)); 125 } catch (IOException e) { 126 throw new BuildException(e); 127 } 128 } else { 129 System.out.println(String.format("Merging manifests from project and %d libraries.", 130 libraries.size())); 131 ManifestMerger merger = new ManifestMerger( 132 MergerLog.wrapSdkLog(new StdLogger(StdLogger.Level.VERBOSE)), 133 new ICallback() { 134 SdkManager mManager; 135 @Override 136 public int queryCodenameApiLevel(@NonNull String codename) { 137 if (mManager == null) { 138 File sdkDir = TaskHelper.getSdkLocation(getProject()); 139 mManager = SdkManager.createManager(sdkDir.getPath(), 140 new StdLogger(StdLogger.Level.VERBOSE)); 141 } 142 if (mManager != null) { 143 IAndroidTarget t = mManager.getTargetFromHashString( 144 IAndroidTarget.PLATFORM_HASH_PREFIX + codename); 145 if (t != null) { 146 return t.getVersion().getApiLevel(); 147 } 148 } 149 return ICallback.UNKNOWN_CODENAME; 150 } 151 }); 152 if (merger.process( 153 new File(mOutManifest), 154 appManifestFile, 155 libraries.toArray(new File[libraries.size()])) == false) { 156 throw new BuildException(); 157 } 158 } 159 160 // generate the dependency file. 161 generateDependencyFile(depFile, inputPaths, mOutManifest); 162 } 163 164 @Override getExecTaskName()165 protected String getExecTaskName() { 166 return "ManifestMerger"; 167 } 168 } 169