2 * Copyright (C) 2009 The Android Open Source Project
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
17 package com.android.sdklib.internal.repository;
\r
19 import com.android.sdklib.AndroidVersion;
\r
20 import com.android.sdklib.IAndroidTarget;
\r
21 import com.android.sdklib.SdkConstants;
\r
22 import com.android.sdklib.SdkManager;
\r
23 import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
\r
24 import com.android.sdklib.internal.repository.Archive.Arch;
\r
25 import com.android.sdklib.internal.repository.Archive.Os;
\r
26 import com.android.sdklib.repository.SdkRepository;
\r
28 import org.w3c.dom.Node;
\r
30 import java.io.File;
\r
31 import java.util.ArrayList;
\r
32 import java.util.Map;
\r
33 import java.util.Properties;
\r
36 * Represents an add-on XML node in an SDK repository.
\r
38 public class AddonPackage extends Package {
\r
40 private static final String PROP_NAME = "Addon.Name"; //$NON-NLS-1$
\r
41 private static final String PROP_VENDOR = "Addon.Vendor"; //$NON-NLS-1$
\r
43 private final String mVendor;
\r
44 private final String mName;
\r
45 private final AndroidVersion mVersion;
\r
47 /** An add-on library. */
\r
48 public static class Lib {
\r
49 private final String mName;
\r
50 private final String mDescription;
\r
52 public Lib(String name, String description) {
\r
54 mDescription = description;
\r
57 public String getName() {
\r
61 public String getDescription() {
\r
62 return mDescription;
\r
66 private final Lib[] mLibs;
\r
69 * Creates a new add-on package from the attributes and elements of the given XML node.
\r
71 * This constructor should throw an exception if the package cannot be created.
\r
73 AddonPackage(RepoSource source, Node packageNode, Map<String,String> licenses) {
\r
74 super(source, packageNode, licenses);
\r
75 mVendor = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VENDOR);
\r
76 mName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_NAME);
\r
77 int apiLevel = XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
\r
78 String codeName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_CODENAME);
\r
79 if (codeName.length() == 0) {
\r
82 mVersion = new AndroidVersion(apiLevel, codeName);
\r
84 mLibs = parseLibs(XmlParserUtils.getFirstChild(packageNode, SdkRepository.NODE_LIBS));
\r
88 * Creates a new platform package based on an actual {@link IAndroidTarget} (which
\r
89 * {@link IAndroidTarget#isPlatform()} false) from the {@link SdkManager}.
\r
90 * This is used to list local SDK folders in which case there is one archive which
\r
91 * URL is the actual target location.
\r
93 AddonPackage(IAndroidTarget target, Properties props) {
\r
94 super( null, //source
\r
96 target.getRevision(), //revision
\r
98 target.getDescription(), //description
\r
100 Os.getCurrentOs(), //archiveOs
\r
101 Arch.getCurrentArch(), //archiveArch
\r
102 target.getLocation() //archiveOsPath
\r
105 mVersion = target.getVersion();
\r
106 mName = target.getName();
\r
107 mVendor = target.getVendor();
\r
109 IOptionalLibrary[] optLibs = target.getOptionalLibraries();
\r
110 if (optLibs == null || optLibs.length == 0) {
\r
111 mLibs = new Lib[0];
\r
113 mLibs = new Lib[optLibs.length];
\r
114 for (int i = 0; i < optLibs.length; i++) {
\r
115 mLibs[i] = new Lib(optLibs[i].getName(), optLibs[i].getDescription());
\r
121 * Save the properties of the current packages in the given {@link Properties} object.
\r
122 * These properties will later be given to a constructor that takes a {@link Properties} object.
\r
125 void saveProperties(Properties props) {
\r
126 super.saveProperties(props);
\r
128 mVersion.saveProperties(props);
\r
129 if (mName != null) {
\r
130 props.setProperty(PROP_NAME, mName);
\r
132 if (mVendor != null) {
\r
133 props.setProperty(PROP_VENDOR, mVendor);
\r
138 * Parses a <libs> element.
\r
140 private Lib[] parseLibs(Node libsNode) {
\r
141 ArrayList<Lib> libs = new ArrayList<Lib>();
\r
143 if (libsNode != null) {
\r
144 for(Node child = libsNode.getFirstChild();
\r
146 child = child.getNextSibling()) {
\r
148 if (child.getNodeType() == Node.ELEMENT_NODE &&
\r
149 SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI()) &&
\r
150 SdkRepository.NODE_LIB.equals(child.getLocalName())) {
\r
151 libs.add(parseLib(child));
\r
156 return libs.toArray(new Lib[libs.size()]);
\r
160 * Parses a <lib> element from a <libs> container.
\r
162 private Lib parseLib(Node libNode) {
\r
163 return new Lib(XmlParserUtils.getXmlString(libNode, SdkRepository.NODE_NAME),
\r
164 XmlParserUtils.getXmlString(libNode, SdkRepository.NODE_DESCRIPTION));
\r
167 /** Returns the vendor, a string, for add-on packages. */
\r
168 public String getVendor() {
\r
172 /** Returns the name, a string, for add-on packages or for libraries. */
\r
173 public String getName() {
\r
177 /** Returns the version, for platform, add-on and doc packages. */
\r
178 public AndroidVersion getVersion() {
\r
182 /** Returns the libs defined in this add-on. Can be an empty array but not null. */
\r
183 public Lib[] getLibs() {
\r
187 /** Returns a short description for an {@link IDescription}. */
\r
189 public String getShortDescription() {
\r
190 return String.format("%1$s by %2$s for Android API %3$s",
\r
193 mVersion.getApiString());
\r
196 /** Returns a long description for an {@link IDescription}. */
\r
198 public String getLongDescription() {
\r
199 return String.format("%1$s.\n%2$s",
\r
200 getShortDescription(),
\r
201 super.getLongDescription());
\r
205 * Computes a potential installation folder if an archive of this package were
\r
206 * to be installed right away in the given SDK root.
\r
208 * An add-on package is typically installed in SDK/add-ons/"addon-name"-"api-level".
\r
209 * The name needs to be sanitized to be acceptable as a directory name.
\r
210 * However if we can find a different directory under SDK/add-ons that already
\r
211 * has this add-ons installed, we'll use that one.
\r
213 * @param osSdkRoot The OS path of the SDK root folder.
\r
214 * @param suggestedDir A suggestion for the installation folder name, based on the root
\r
215 * folder used in the zip archive.
\r
216 * @param sdkManager An existing SDK manager to list current platforms and addons.
\r
217 * @return A new {@link File} corresponding to the directory to use to install this package.
\r
220 public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {
\r
221 File addons = new File(osSdkRoot, SdkConstants.FD_ADDONS);
\r
223 // First find if this add-on is already installed. If so, reuse the same directory.
\r
224 for (IAndroidTarget target : sdkManager.getTargets()) {
\r
225 if (!target.isPlatform() &&
\r
226 target.getVersion().equals(mVersion) &&
\r
227 target.getName().equals(getName()) &&
\r
228 target.getVendor().equals(getVendor())) {
\r
229 return new File(target.getLocation());
\r
233 // Otherwise, see about reusing the suggestedDir. It must not be already used or
\r
234 // add some index to it, or we try to make up one.
\r
235 String name = suggestedDir;
\r
237 if (suggestedDir == null || suggestedDir.length() == 0) {
\r
238 name = String.format("addon-%s-%s-%s", getName(), getVendor(), //$NON-NLS-1$
\r
239 mVersion.getApiString());
\r
240 name = name.toLowerCase();
\r
241 name = name.replaceAll("[^a-z0-9_-]+", "_"); //$NON-NLS-1$ //$NON-NLS-2$
\r
242 name = name.replaceAll("_+", "_"); //$NON-NLS-1$ //$NON-NLS-2$
\r
245 for (int i = 0; i < 100; i++) {
\r
246 String name2 = i == 0 ? name : String.format("%s-%d", name, i); //$NON-NLS-1$
\r
247 File folder = new File(addons, name2);
\r
248 if (!folder.exists()) {
\r
253 // We shouldn't really get here. I mean, seriously, we tried hard enough.
\r
258 public boolean sameItemAs(Package pkg) {
\r
259 if (pkg instanceof AddonPackage) {
\r
260 AddonPackage newPkg = (AddonPackage)pkg;
\r
262 // check they are the same add-on.
\r
263 return getName().equals(newPkg.getName()) &&
\r
264 getVendor().equals(newPkg.getVendor()) &&
\r
265 getVersion().equals(newPkg.getVersion());
\r