SDK Updater: support sample packages.
TODO: needs an icon and scanning /samples folders not matching
any current platform (in next CL)
BUG: 2384690
Change-Id: I07d55a8e1ff897bde10c475050d0e18ae3ca7da8
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
index 0dec3bb..af83e9c 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
@@ -35,7 +35,8 @@
/**
* Represents an add-on XML node in an SDK repository.
*/
-public class AddonPackage extends Package implements IPackageVersion {
+public class AddonPackage extends Package
+ implements IPackageVersion, IPlatformDependency {
private static final String PROP_NAME = "Addon.Name"; //$NON-NLS-1$
private static final String PROP_VENDOR = "Addon.Vendor"; //$NON-NLS-1$
@@ -177,7 +178,11 @@
return mName;
}
- /** Returns the version, for platform, add-on and doc packages. */
+ /**
+ * Returns the version of the platform dependency of this package.
+ * <p/>
+ * An add-on has the same {@link AndroidVersion} as the platform it depends on.
+ */
public AndroidVersion getVersion() {
return mVersion;
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java
index ef5d2c3..8765905 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java
@@ -37,8 +37,7 @@
/**
* A {@link Archive} is the base class for "something" that can be downloaded from
- * the SDK repository -- subclasses include {@link PlatformPackage}, {@link AddonPackage},
- * {@link DocPackage} and {@link ToolPackage}.
+ * the SDK repository.
* <p/>
* A package has some attributes (revision, description) and a list of archives
* which represent the downloadable bits.
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java
index edc4276..b91d7bd 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java
@@ -31,6 +31,10 @@
/**
* Represents a doc XML node in an SDK repository.
+ * <p/>
+ * Note that a doc package has a version and thus implements {@link IPackageVersion}.
+ * However there is no mandatory dependency that limits installation so this does not
+ * implement {@link IPlatformDependency}.
*/
public class DocPackage extends Package implements IPackageVersion {
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java
index faa7c26..e62586a 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java
@@ -31,7 +31,8 @@
/**
* Represents a extra XML node in an SDK repository.
*/
-public class ExtraPackage extends MinToolsPackage {
+public class ExtraPackage extends MinToolsPackage
+ implements IMinApiLevelDependency {
private static final String PROP_PATH = "Extra.Path"; //$NON-NLS-1$
private static final String PROP_MIN_API_LEVEL = "Extra.MinApiLevel"; //$NON-NLS-1$
@@ -51,12 +52,6 @@
private final int mMinApiLevel;
/**
- * The value of {@link #mMinApiLevel} when the {@link SdkRepository#NODE_MIN_TOOLS_REV}
- * was not specified in the XML source.
- */
- public static final int MIN_API_LEVEL_NOT_SPECIFIED = 0;
-
- /**
* Creates a new tool package from the attributes and elements of the given XML node.
* <p/>
* This constructor should throw an exception if the package cannot be created.
@@ -104,10 +99,6 @@
getProperty(props, PROP_MIN_API_LEVEL, Integer.toString(MIN_API_LEVEL_NOT_SPECIFIED)));
}
- public int getMinApiLevel() {
- return mMinApiLevel;
- }
-
/**
* Save the properties of the current packages in the given {@link Properties} object.
* These properties will later be give the constructor that takes a {@link Properties} object.
@@ -124,6 +115,14 @@
}
/**
+ * Returns the minimal API level required by this extra package, if > 0,
+ * or {@link #MIN_API_LEVEL_NOT_SPECIFIED} if there is no such requirement.
+ */
+ public int getMinApiLevel() {
+ return mMinApiLevel;
+ }
+
+ /**
* Static helper to check if a given path is acceptable for an "extra" package.
*/
public boolean isPathValid() {
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IMinApiLevelDependency.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IMinApiLevelDependency.java
new file mode 100755
index 0000000..76c1955
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IMinApiLevelDependency.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.sdklib.internal.repository;
+
+import com.android.sdklib.repository.SdkRepository;
+
+/**
+ * Interface used to decorate a {@link Package} that has a dependency
+ * on a minimal API level, e.g. which XML has a <code><min-api-level></code> element.
+ * <p/>
+ * A package that has this dependency can only be installed if a platform with at least the
+ * requested API level is present or installed at the same time.
+ */
+public interface IMinApiLevelDependency {
+
+ /**
+ * The value of {@link #getMinApiLevel()} when the {@link SdkRepository#NODE_MIN_API_LEVEL}
+ * was not specified in the XML source.
+ */
+ public static final int MIN_API_LEVEL_NOT_SPECIFIED = 0;
+
+ /**
+ * Returns the minimal API level required by this extra package, if > 0,
+ * or {@link #MIN_API_LEVEL_NOT_SPECIFIED} if there is no such requirement.
+ */
+ public abstract int getMinApiLevel();
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IMinToolsDependency.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IMinToolsDependency.java
new file mode 100755
index 0000000..669806b
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IMinToolsDependency.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.sdklib.internal.repository;
+
+import com.android.sdklib.repository.SdkRepository;
+
+/**
+ * Interface used to decorate a {@link Package} that has a dependency
+ * on a minimal tools revision, e.g. which XML has a <code><min-tools-rev></code> element.
+ * <p/>
+ * A package that has this dependency can only be installed if the requested tools revision
+ * is present or installed at the same time.
+ */
+public interface IMinToolsDependency {
+
+ /**
+ * The value of {@link #getMinToolsRevision()} when the {@link SdkRepository#NODE_MIN_TOOLS_REV}
+ * was not specified in the XML source.
+ */
+ public static final int MIN_TOOLS_REV_NOT_SPECIFIED = 0;
+
+ /**
+ * The minimal revision of the tools package required by this extra package if > 0,
+ * or {@link #MIN_TOOLS_REV_NOT_SPECIFIED} if there is no such requirement.
+ */
+ public abstract int getMinToolsRevision();
+
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IPackageVersion.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IPackageVersion.java
index 46d7b5d..911ba8d 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IPackageVersion.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IPackageVersion.java
@@ -20,6 +20,11 @@
/**
* Interface for packages that provide an {@link AndroidVersion}.
+ * <p/>
+ * Note that {@link IPlatformDependency} is a similar interface, but with a different semantic.
+ * The {@link IPlatformDependency} denotes that a given package can only be installed if the
+ * requested platform is present, whereas this interface denotes that the given package simply
+ * has a version, which is not necessarily a dependency.
*/
public interface IPackageVersion {
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IPlatformDependency.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IPlatformDependency.java
new file mode 100755
index 0000000..3aba333
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IPlatformDependency.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.sdklib.internal.repository;
+
+import com.android.sdklib.AndroidVersion;
+
+/**
+ * Interface used to decorate a {@link Package} that has a dependency
+ * on a specific platform (API level and/or code name).
+ * <p/>
+ * A package that has this dependency can only be installed if a platform with at least the
+ * requested API level is present or installed at the same time.
+ * <p/>
+ * Note that although this interface looks like {@link IPackageVersion}, it does not convey
+ * the same semantic, that is {@link IPackageVersion} does <em>not</em> imply any dependency being
+ * a limiting factor as far as installation is concerned.
+ */
+public interface IPlatformDependency {
+
+ /** Returns the version of the platform dependency of this package. */
+ AndroidVersion getVersion();
+
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java
index c547d46..b92f771 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java
@@ -90,7 +90,9 @@
visited.add(dir);
}
- // for platforms and add-ons, rely on the SdkManager parser
+ File samplesRoot = new File(osSdkRoot, SdkConstants.FD_SAMPLES);
+
+ // for platforms, add-ons and samples, rely on the SdkManager parser
for(IAndroidTarget target : sdkManager.getTargets()) {
Properties props = parseProperties(new File(target.getLocation(),
@@ -99,6 +101,22 @@
try {
if (target.isPlatform()) {
pkg = new PlatformPackage(target, props);
+
+ if (samplesRoot.isDirectory()) {
+ // Get the samples dir for a platform if it is located in the new
+ // root /samples dir. We purposely ignore "old" samples that are
+ // located under the platform dir.
+ String s = target.getPath(IAndroidTarget.SAMPLES);
+ File f = new File(s);
+ if (f.exists() && f.getParentFile().equals(samplesRoot)) {
+ Properties props2 = parseProperties(
+ new File(f, SdkConstants.FN_SOURCE_PROP));
+ SamplePackage pkg2 = new SamplePackage(target, props2);
+ packages.add(pkg2);
+ visited.add(f);
+ }
+ }
+
} else {
pkg = new AddonPackage(target, props);
}
@@ -114,6 +132,9 @@
scanExtra(osSdkRoot, visited, packages, log);
+ // TODO scanSample folder for samples that have not been visited yet
+ // (e.g. for platforms that are not installed)
+
mPackages = packages.toArray(new Package[packages.size()]);
return mPackages;
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/MinToolsPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/MinToolsPackage.java
index 43d0a1e..4779a1f 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/MinToolsPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/MinToolsPackage.java
@@ -27,9 +27,9 @@
/**
* Represents an XML node in an SDK repository that has a min-tools-rev requirement.
- * This is either a {@link PlatformPackage} or an {@link ExtraPackage}.
*/
-public abstract class MinToolsPackage extends Package {
+public abstract class MinToolsPackage extends Package
+ implements IMinToolsDependency {
protected static final String PROP_MIN_TOOLS_REV = "Platform.MinToolsRev"; //$NON-NLS-1$
@@ -40,12 +40,6 @@
private final int mMinToolsRevision;
/**
- * The value of {@link #mMinToolsRevision} when the {@link SdkRepository#NODE_MIN_TOOLS_REV}
- * was not specified in the XML source.
- */
- public static final int MIN_TOOLS_REV_NOT_SPECIFIED = 0;
-
- /**
* Creates a new package from the attributes and elements of the given XML node.
* <p/>
* This constructor should throw an exception if the package cannot be created.
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
index 355bde4..e30e8a2 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
@@ -31,8 +31,7 @@
/**
* A {@link Package} is the base class for "something" that can be downloaded from
- * the SDK repository -- subclasses include {@link PlatformPackage}, {@link AddonPackage},
- * {@link DocPackage} and {@link ToolPackage}.
+ * the SDK repository.
* <p/>
* A package has some attributes (revision, description) and a list of archives
* which represent the downloadable bits.
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java
index 430839e..415cba5 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java
@@ -723,6 +723,8 @@
p = new DocPackage(this, child, licenses);
} else if (SdkRepository.NODE_TOOL.equals(name)) {
p = new ToolPackage(this, child, licenses);
+ } else if (SdkRepository.NODE_SAMPLE.equals(name)) {
+ p = new SamplePackage(this, child, licenses);
}
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SamplePackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SamplePackage.java
new file mode 100755
index 0000000..f4c64a2
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SamplePackage.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.sdklib.internal.repository;
+
+import com.android.sdklib.AndroidVersion;
+import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.SdkConstants;
+import com.android.sdklib.SdkManager;
+import com.android.sdklib.AndroidVersion.AndroidVersionException;
+import com.android.sdklib.internal.repository.Archive.Arch;
+import com.android.sdklib.internal.repository.Archive.Os;
+import com.android.sdklib.repository.SdkRepository;
+
+import org.w3c.dom.Node;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Represents a sample XML node in an SDK repository.
+ */
+public class SamplePackage extends MinToolsPackage
+ implements IPackageVersion, IMinApiLevelDependency, IMinToolsDependency {
+
+ private static final String PROP_MIN_API_LEVEL = "Sample.MinApiLevel"; //$NON-NLS-1$
+
+ /** The matching platform version. */
+ private final AndroidVersion mVersion;
+
+ /**
+ * The minimal API level required by this extra package, if > 0,
+ * or {@link #MIN_API_LEVEL_NOT_SPECIFIED} if there is no such requirement.
+ */
+ private final int mMinApiLevel;
+
+ /**
+ * Creates a new sample package from the attributes and elements of the given XML node.
+ * <p/>
+ * This constructor should throw an exception if the package cannot be created.
+ */
+ SamplePackage(RepoSource source, Node packageNode, Map<String,String> licenses) {
+ super(source, packageNode, licenses);
+
+ int apiLevel = XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
+ String codeName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_CODENAME);
+ if (codeName.length() == 0) {
+ codeName = null;
+ }
+ mVersion = new AndroidVersion(apiLevel, codeName);
+
+ mMinApiLevel = XmlParserUtils.getXmlInt(packageNode, SdkRepository.NODE_MIN_API_LEVEL,
+ MIN_API_LEVEL_NOT_SPECIFIED);
+ }
+
+ /**
+ * Creates a new sample package based on an actual {@link IAndroidTarget} (which
+ * must have {@link IAndroidTarget#isPlatform()} true) from the {@link SdkManager}.
+ * <p/>
+ * The target <em>must</em> have an existing sample directory that uses the /samples
+ * root form rather than the old form where the samples dir was located under the
+ * platform dir.
+ * <p/>
+ * This is used to list local SDK folders in which case there is one archive which
+ * URL is the actual samples path location.
+ * <p/>
+ * By design, this creates a package with one and only one archive.
+ */
+ SamplePackage(IAndroidTarget target, Properties props) {
+ super( null, //source
+ props, //properties
+ 0, //revision will be taken from props
+ null, //license
+ null, //description
+ null, //descUrl
+ Os.ANY, //archiveOs
+ Arch.ANY, //archiveArch
+ target.getPath(IAndroidTarget.SAMPLES) //archiveOsPath
+ );
+
+ mVersion = target.getVersion();
+
+ mMinApiLevel = Integer.parseInt(
+ getProperty(props, PROP_MIN_API_LEVEL, Integer.toString(MIN_API_LEVEL_NOT_SPECIFIED)));
+ }
+
+ /**
+ * Creates a new sample package from an actual directory path and previously
+ * saved properties.
+ * <p/>
+ * This is used to list local SDK folders in which case there is one archive which
+ * URL is the actual samples path location.
+ * <p/>
+ * By design, this creates a package with one and only one archive.
+ *
+ * @throws AndroidVersionException if the {@link AndroidVersion} can't be restored
+ * from properties.
+ */
+ SamplePackage(String archiveOsPath, Properties props) throws AndroidVersionException {
+ super( null, //source
+ props, //properties
+ 0, //revision will be taken from props
+ null, //license
+ null, //description
+ null, //descUrl
+ Os.ANY, //archiveOs
+ Arch.ANY, //archiveArch
+ archiveOsPath //archiveOsPath
+ );
+
+ mVersion = new AndroidVersion(props);
+
+ mMinApiLevel = Integer.parseInt(
+ getProperty(props, PROP_MIN_API_LEVEL, Integer.toString(MIN_API_LEVEL_NOT_SPECIFIED)));
+ }
+
+ /**
+ * Save the properties of the current packages in the given {@link Properties} object.
+ * These properties will later be given to a constructor that takes a {@link Properties} object.
+ */
+ @Override
+ void saveProperties(Properties props) {
+ super.saveProperties(props);
+
+ mVersion.saveProperties(props);
+
+ if (getMinApiLevel() != MIN_API_LEVEL_NOT_SPECIFIED) {
+ props.setProperty(PROP_MIN_API_LEVEL, Integer.toString(getMinApiLevel()));
+ }
+ }
+
+ /**
+ * Returns the minimal API level required by this extra package, if > 0,
+ * or {@link #MIN_API_LEVEL_NOT_SPECIFIED} if there is no such requirement.
+ */
+ public int getMinApiLevel() {
+ return mMinApiLevel;
+ }
+
+ /** Returns the matching platform version. */
+ public AndroidVersion getVersion() {
+ return mVersion;
+ }
+
+ /** Returns a short description for an {@link IDescription}. */
+ @Override
+ public String getShortDescription() {
+ String s = String.format("Samples for SDK API %1$s%2$s, revision %3$d",
+ mVersion.getApiString(),
+ mVersion.isPreview() ? " Preview" : "",
+ getRevision());
+ return s;
+ }
+
+ /**
+ * Returns a long description for an {@link IDescription}.
+ *
+ * The long description is whatever the XML contains for the <description> field,
+ * or the short description if the former is empty.
+ */
+ @Override
+ public String getLongDescription() {
+ String s = getDescription();
+ if (s == null || s.length() == 0) {
+ s = getShortDescription();
+ }
+
+ if (s.indexOf("revision") == -1) {
+ s += String.format("\nRevision %1$d", getRevision());
+ }
+
+ return s;
+ }
+
+ /**
+ * Computes a potential installation folder if an archive of this package were
+ * to be installed right away in the given SDK root.
+ * <p/>
+ * A sample package is typically installed in SDK/samples/android-"version".
+ * However if we can find a different directory that already has this sample
+ * version installed, we'll use that one.
+ *
+ * @param osSdkRoot The OS path of the SDK root folder.
+ * @param suggestedDir A suggestion for the installation folder name, based on the root
+ * folder used in the zip archive.
+ * @param sdkManager An existing SDK manager to list current platforms and addons.
+ * @return A new {@link File} corresponding to the directory to use to install this package.
+ */
+ @Override
+ public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {
+
+ // First find if this platform is already installed. If so, reuse the same directory.
+ for (IAndroidTarget target : sdkManager.getTargets()) {
+ if (target.isPlatform() &&
+ target.getVersion().equals(mVersion)) {
+ String p = target.getPath(IAndroidTarget.SAMPLES);
+ File f = new File(p);
+ if (f.isDirectory()) {
+ return f;
+ }
+ }
+ }
+
+ // Otherwise, get a suitable default
+ File samples = new File(osSdkRoot, SdkConstants.FD_SAMPLES);
+ File folder = new File(samples,
+ String.format("android-%d", getVersion().getApiLevel())); //$NON-NLS-1$
+
+ for (int n = 1; folder.exists(); n++) {
+ // Keep trying till we find an unused directory.
+ folder = new File(samples,
+ String.format("android-%d_%d", getVersion().getApiLevel(), n)); //$NON-NLS-1$
+ }
+
+ return folder;
+ }
+
+ @Override
+ public boolean sameItemAs(Package pkg) {
+ if (pkg instanceof SamplePackage) {
+ SamplePackage newPkg = (SamplePackage)pkg;
+
+ // check they are the same platform.
+ return newPkg.getVersion().equals(this.getVersion());
+ }
+
+ return false;
+ }
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java
index be9384a..fd5cf9e 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java
@@ -56,6 +56,8 @@
public static final String NODE_TOOL = "tool"; //$NON-NLS-1$
/** A doc package. */
public static final String NODE_DOC = "doc"; //$NON-NLS-1$
+ /** A sample package. */
+ public static final String NODE_SAMPLE = "sample"; //$NON-NLS-1$
/** An extra package. */
public static final String NODE_EXTRA = "extra"; //$NON-NLS-1$
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository-2.xsd b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository-2.xsd
index 37038c3..9bcc1bc 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository-2.xsd
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository-2.xsd
@@ -47,6 +47,7 @@
<xsd:element name="add-on" type="sr2:addonType" />
<xsd:element name="tool" type="sr2:toolType" />
<xsd:element name="doc" type="sr2:docType" />
+ <xsd:element name="sample" type="sr2:sampleType" />
<xsd:element name="extra" type="sr2:extraType" />
<xsd:element name="license" type="sr2:licenseType" />
</xsd:choice>
@@ -203,6 +204,41 @@
</xsd:complexType>
+ <!-- The definition of an SDK sample package. -->
+
+ <xsd:complexType name="sampleType" >
+ <xsd:annotation>
+ <xsd:documentation>An SDK sample package.</xsd:documentation>
+ </xsd:annotation>
+ <xsd:all>
+ <!-- The Android API Level for the documentation. An int > 0. -->
+ <xsd:element name="api-level" type="xsd:positiveInteger" />
+ <!-- The optional codename for this doc, if it's a preview. -->
+ <xsd:element name="codename" type="xsd:string" minOccurs="0" />
+
+ <!-- The revision, an int > 0, incremented each time a new
+ package is generated. -->
+ <xsd:element name="revision" type="xsd:positiveInteger" />
+ <!-- The optional license of this package. If present, users will have
+ to agree to it before downloading. -->
+ <xsd:element name="uses-license" type="sr2:usesLicenseType" minOccurs="0" />
+ <!-- The optional description of this package. -->
+ <xsd:element name="description" type="xsd:string" minOccurs="0" />
+ <!-- The optional description URL of this package -->
+ <xsd:element name="desc-url" type="xsd:token" minOccurs="0" />
+ <!-- The optional release note for this package. -->
+ <xsd:element name="release-note" type="xsd:string" minOccurs="0" />
+ <!-- The optional release note URL of this package -->
+ <xsd:element name="release-url" type="xsd:token" minOccurs="0" />
+ <!-- A list of file archives for this package. -->
+ <xsd:element name="archives" type="sr2:archivesType" />
+ <!-- The minimal revision of tools required by this package.
+ Optional. If present, must be an int > 0. -->
+ <xsd:element name="min-tools-rev" type="xsd:positiveInteger" minOccurs="0" />
+ </xsd:all>
+ </xsd:complexType>
+
+
<!-- The definition of an SDK extra package. This kind of package is for
"free" content and specifies in which fixed root directory it must be
installed.
diff --git a/sdkmanager/libs/sdklib/tests/com/android/sdklib/testdata/repository_sample_2.xml b/sdkmanager/libs/sdklib/tests/com/android/sdklib/testdata/repository_sample_2.xml
index 6259794..bf571d2 100755
--- a/sdkmanager/libs/sdklib/tests/com/android/sdklib/testdata/repository_sample_2.xml
+++ b/sdkmanager/libs/sdklib/tests/com/android/sdklib/testdata/repository_sample_2.xml
@@ -289,4 +289,19 @@
<sdk:min-api-level>42</sdk:min-api-level>
</sdk:extra>
+ <sdk:sample>
+ <sdk:api-level>14</sdk:api-level>
+ <sdk:revision>24</sdk:revision>
+ <sdk:archives>
+ <sdk:archive os="any" arch="any">
+ <sdk:size>65537</sdk:size>
+ <sdk:checksum type="sha1">3822ae37115ebf13412bbef91339ee0d9454525e</sdk:checksum>
+ <sdk:url>distrib/sample_duff.zip</sdk:url>
+ </sdk:archive>
+ </sdk:archives>
+ <sdk:description>Some sample package</sdk:description>
+ <sdk:desc-url>http://www.example.com/sample.html</sdk:desc-url>
+ <sdk:min-tools-rev>5</sdk:min-tools-rev>
+ </sdk:sample>
+
</sdk:sdk-repository>
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterLogic.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterLogic.java
index 192eb3e..36f277b 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterLogic.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterLogic.java
@@ -21,12 +21,16 @@
import com.android.sdklib.internal.repository.Archive;
import com.android.sdklib.internal.repository.DocPackage;
import com.android.sdklib.internal.repository.ExtraPackage;
+import com.android.sdklib.internal.repository.IMinApiLevelDependency;
+import com.android.sdklib.internal.repository.IMinToolsDependency;
import com.android.sdklib.internal.repository.IPackageVersion;
+import com.android.sdklib.internal.repository.IPlatformDependency;
import com.android.sdklib.internal.repository.MinToolsPackage;
import com.android.sdklib.internal.repository.Package;
import com.android.sdklib.internal.repository.PlatformPackage;
import com.android.sdklib.internal.repository.RepoSource;
import com.android.sdklib.internal.repository.RepoSources;
+import com.android.sdklib.internal.repository.SamplePackage;
import com.android.sdklib.internal.repository.ToolPackage;
import com.android.sdklib.internal.repository.Package.UpdateInfo;
@@ -80,7 +84,7 @@
}
/**
- * Finds new platforms that the user does not have in his/her local SDK
+ * Finds new packages that the user does not have in his/her local SDK
* and adds them to the list of archives to install.
*/
public void addNewPlatforms(ArrayList<ArchiveInfo> archives,
@@ -92,6 +96,7 @@
// Find the highest platform installed
float currentPlatformScore = 0;
+ float currentSampleScore = 0;
float currentAddonScore = 0;
float currentDocScore = 0;
HashMap<String, Float> currentExtraScore = new HashMap<String, Float>();
@@ -99,7 +104,7 @@
int rev = p.getRevision();
int api = 0;
boolean isPreview = false;
- if (p instanceof IPackageVersion) {
+ if (p instanceof IPackageVersion) {
AndroidVersion vers = ((IPackageVersion) p).getVersion();
api = vers.getApiLevel();
isPreview = vers.isPreview();
@@ -112,6 +117,8 @@
if (p instanceof PlatformPackage) {
currentPlatformScore = Math.max(currentPlatformScore, score);
+ } else if (p instanceof SamplePackage) {
+ currentSampleScore = Math.max(currentSampleScore, score);
} else if (p instanceof AddonPackage) {
currentAddonScore = Math.max(currentAddonScore, score);
} else if (p instanceof ExtraPackage) {
@@ -142,6 +149,8 @@
boolean shouldAdd = false;
if (p instanceof PlatformPackage) {
shouldAdd = score > currentPlatformScore;
+ } else if (p instanceof SamplePackage) {
+ shouldAdd = score > currentSampleScore;
} else if (p instanceof AddonPackage) {
shouldAdd = score > currentAddonScore;
} else if (p instanceof ExtraPackage) {
@@ -186,7 +195,6 @@
}
}
}
-
}
/**
@@ -314,6 +322,13 @@
return ai;
}
+ /**
+ * Resolves dependencies for a given package.
+ *
+ * Returns null if no dependencies were found.
+ * Otherwise return an array of {@link ArchiveInfo}, which is guaranteed to have
+ * at least size 1 and contain no null elements.
+ */
private ArchiveInfo[] findDependency(Package pkg,
ArrayList<ArchiveInfo> outArchives,
Collection<Archive> selectedArchives,
@@ -326,11 +341,11 @@
// - platform: *might* depends on tools of rev >= min-tools-rev
// - extra: *might* depends on platform with api >= min-api-level
- if (pkg instanceof AddonPackage) {
- AddonPackage addon = (AddonPackage) pkg;
+ ArrayList<ArchiveInfo> list = new ArrayList<ArchiveInfo>();
+ if (pkg instanceof IPlatformDependency) {
ArchiveInfo ai = findPlatformDependency(
- addon,
+ (IPlatformDependency) pkg,
outArchives,
selectedArchives,
remotePkgs,
@@ -338,44 +353,44 @@
localArchives);
if (ai != null) {
- return new ArchiveInfo[] { ai };
+ list.add(ai);
}
+ }
- } else if (pkg instanceof MinToolsPackage) {
- MinToolsPackage platformOrExtra = (MinToolsPackage) pkg;
+ if (pkg instanceof IMinToolsDependency) {
- int n = 0;
- ArchiveInfo ai1 = findToolsDependency(
- platformOrExtra,
+ ArchiveInfo ai = findToolsDependency(
+ (IMinToolsDependency) pkg,
outArchives,
selectedArchives,
remotePkgs,
remoteSources,
localArchives);
- n += ai1 == null ? 0 : 1;
-
- ArchiveInfo ai2 = null;
- if (pkg instanceof ExtraPackage) {
- ai2 = findExtraPlatformDependency(
- (ExtraPackage) pkg,
- outArchives,
- selectedArchives,
- remotePkgs,
- remoteSources,
- localArchives);
+ if (ai != null) {
+ list.add(ai);
}
+ }
- n += ai2 == null ? 0 : 1;
+ if (pkg instanceof IMinApiLevelDependency) {
- if (n > 0) {
- ArchiveInfo[] ais = new ArchiveInfo[n];
- ais[0] = ai1 != null ? ai1 : ai2;
- if (n > 1) ais[1] = ai2;
- return ais;
+ ArchiveInfo ai = findMinApiLevelDependency(
+ (IMinApiLevelDependency) pkg,
+ outArchives,
+ selectedArchives,
+ remotePkgs,
+ remoteSources,
+ localArchives);
+
+ if (ai != null) {
+ list.add(ai);
}
}
+ if (list.size() > 0) {
+ return list.toArray(new ArchiveInfo[list.size()]);
+ }
+
return null;
}
@@ -387,14 +402,15 @@
* Finds the tools dependency. If found, add it to the list of things to install.
* Returns the archive info dependency, if any.
*/
- protected ArchiveInfo findToolsDependency(MinToolsPackage platformOrExtra,
+ protected ArchiveInfo findToolsDependency(
+ IMinToolsDependency pkg,
ArrayList<ArchiveInfo> outArchives,
Collection<Archive> selectedArchives,
ArrayList<Package> remotePkgs,
RepoSource[] remoteSources,
ArchiveInfo[] localArchives) {
// This is the requirement to match.
- int rev = platformOrExtra.getMinToolsRevision();
+ int rev = pkg.getMinToolsRevision();
if (rev == MinToolsPackage.MIN_TOOLS_REV_NOT_SPECIFIED) {
// Well actually there's no requirement.
@@ -485,14 +501,14 @@
* Returns the archive info dependency, if any.
*/
protected ArchiveInfo findPlatformDependency(
- AddonPackage addon,
+ IPlatformDependency pkg,
ArrayList<ArchiveInfo> outArchives,
Collection<Archive> selectedArchives,
ArrayList<Package> remotePkgs,
RepoSource[] remoteSources,
ArchiveInfo[] localArchives) {
// This is the requirement to match.
- AndroidVersion v = addon.getVersion();
+ AndroidVersion v = pkg.getVersion();
// Find a platform that would satisfy the requirement.
@@ -568,7 +584,7 @@
// We end up here if nothing matches. We don't have a good platform to match.
// We need to indicate this addon depends on a missing platform archive
// so that it can be impossible to install later on.
- return new MissingPlatformArchiveInfo(addon.getVersion());
+ return new MissingPlatformArchiveInfo(pkg.getVersion());
}
/**
@@ -583,15 +599,15 @@
* Finds the platform dependency. If found, add it to the list of things to install.
* Returns the archive info dependency, if any.
*/
- protected ArchiveInfo findExtraPlatformDependency(
- ExtraPackage extra,
+ protected ArchiveInfo findMinApiLevelDependency(
+ IMinApiLevelDependency pkg,
ArrayList<ArchiveInfo> outArchives,
Collection<Archive> selectedArchives,
ArrayList<Package> remotePkgs,
RepoSource[] remoteSources,
ArchiveInfo[] localArchives) {
- int api = extra.getMinApiLevel();
+ int api = pkg.getMinApiLevel();
if (api == ExtraPackage.MIN_API_LEVEL_NOT_SPECIFIED) {
return null;