Merge change 2771 into donut
* changes: SDK Updater: parse local packages, download and install remote packages.
This commit is contained in:
@@ -90,7 +90,7 @@ public class AndroidConstants {
|
|||||||
|
|
||||||
/** Name of the android sources directory */
|
/** Name of the android sources directory */
|
||||||
public static final String FD_ANDROID_SOURCES = "sources"; //$NON-NLS-1$
|
public static final String FD_ANDROID_SOURCES = "sources"; //$NON-NLS-1$
|
||||||
|
|
||||||
/** Resource java class filename, i.e. "R.java" */
|
/** Resource java class filename, i.e. "R.java" */
|
||||||
public final static String FN_RESOURCE_CLASS = "R.java"; //$NON-NLS-1$
|
public final static String FN_RESOURCE_CLASS = "R.java"; //$NON-NLS-1$
|
||||||
/** Resource class file filename, i.e. "R.class" */
|
/** Resource class file filename, i.e. "R.class" */
|
||||||
@@ -104,15 +104,11 @@ public class AndroidConstants {
|
|||||||
/** Temporary packaged resources file name for a specific set of configuration */
|
/** Temporary packaged resources file name for a specific set of configuration */
|
||||||
public final static String FN_RESOURCES_S_AP_ = "resources-%s.ap_"; //$NON-NLS-1$
|
public final static String FN_RESOURCES_S_AP_ = "resources-%s.ap_"; //$NON-NLS-1$
|
||||||
public final static Pattern PATTERN_RESOURCES_S_AP_ =
|
public final static Pattern PATTERN_RESOURCES_S_AP_ =
|
||||||
Pattern.compile("resources-.*\\.ap_", Pattern.CASE_INSENSITIVE);
|
Pattern.compile("resources-.*\\.ap_", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
|
||||||
|
|
||||||
public final static String FN_ADB =
|
public final static String FN_ADB = SdkConstants.FN_ADB;
|
||||||
(SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
|
|
||||||
"adb.exe" : "adb"; //$NON-NLS-1$ //$NON-NLS-2$
|
|
||||||
|
|
||||||
public final static String FN_EMULATOR =
|
public final static String FN_EMULATOR = SdkConstants.FN_EMULATOR;
|
||||||
(SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
|
|
||||||
"emulator.exe" : "emulator"; //$NON-NLS-1$ //$NON-NLS-2$
|
|
||||||
|
|
||||||
public final static String FN_TRACEVIEW =
|
public final static String FN_TRACEVIEW =
|
||||||
(SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
|
(SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
|
||||||
@@ -128,8 +124,8 @@ public class AndroidConstants {
|
|||||||
public final static String WS_ASSETS = WS_SEP + SdkConstants.FD_ASSETS;
|
public final static String WS_ASSETS = WS_SEP + SdkConstants.FD_ASSETS;
|
||||||
|
|
||||||
/** Leaf of the javaDoc folder. Does not start with a separator. */
|
/** Leaf of the javaDoc folder. Does not start with a separator. */
|
||||||
public final static String WS_JAVADOC_FOLDER_LEAF = SdkConstants.FD_DOCS + "/" +
|
public final static String WS_JAVADOC_FOLDER_LEAF = SdkConstants.FD_DOCS + "/" + //$NON-NLS-1$
|
||||||
SdkConstants.FD_DOCS_REFERENCE; //$NON-NLS-1$
|
SdkConstants.FD_DOCS_REFERENCE;
|
||||||
|
|
||||||
/** Path of the samples directory relative to the sdk folder.
|
/** Path of the samples directory relative to the sdk folder.
|
||||||
* This is an OS path, ending with a separator.
|
* This is an OS path, ending with a separator.
|
||||||
@@ -159,10 +155,10 @@ public class AndroidConstants {
|
|||||||
|
|
||||||
/** aidl marker error. */
|
/** aidl marker error. */
|
||||||
public final static String MARKER_AIDL = COMMON_PLUGIN_ID + ".aidlProblem"; //$NON-NLS-1$
|
public final static String MARKER_AIDL = COMMON_PLUGIN_ID + ".aidlProblem"; //$NON-NLS-1$
|
||||||
|
|
||||||
/** android marker error */
|
/** android marker error */
|
||||||
public final static String MARKER_ANDROID = COMMON_PLUGIN_ID + ".androidProblem"; //$NON-NLS-1$
|
public final static String MARKER_ANDROID = COMMON_PLUGIN_ID + ".androidProblem"; //$NON-NLS-1$
|
||||||
|
|
||||||
/** Name for the "type" marker attribute */
|
/** Name for the "type" marker attribute */
|
||||||
public final static String MARKER_ATTR_TYPE = "android.type"; //$NON-NLS-1$
|
public final static String MARKER_ATTR_TYPE = "android.type"; //$NON-NLS-1$
|
||||||
/** Name for the "class" marker attribute */
|
/** Name for the "class" marker attribute */
|
||||||
@@ -176,9 +172,9 @@ public class AndroidConstants {
|
|||||||
/** provider value for marker attribute "type" */
|
/** provider value for marker attribute "type" */
|
||||||
public final static String MARKER_ATTR_TYPE_PROVIDER = "provider"; //$NON-NLS-1$
|
public final static String MARKER_ATTR_TYPE_PROVIDER = "provider"; //$NON-NLS-1$
|
||||||
|
|
||||||
public final static String CLASS_ACTIVITY = "android.app.Activity"; //$NON-NLS-1$
|
public final static String CLASS_ACTIVITY = "android.app.Activity"; //$NON-NLS-1$
|
||||||
public final static String CLASS_SERVICE = "android.app.Service"; //$NON-NLS-1$
|
public final static String CLASS_SERVICE = "android.app.Service"; //$NON-NLS-1$
|
||||||
public final static String CLASS_BROADCASTRECEIVER = "android.content.BroadcastReceiver"; //$NON-NLS-1$
|
public final static String CLASS_BROADCASTRECEIVER = "android.content.BroadcastReceiver"; //$NON-NLS-1$
|
||||||
public final static String CLASS_CONTENTPROVIDER = "android.content.ContentProvider"; //$NON-NLS-1$
|
public final static String CLASS_CONTENTPROVIDER = "android.content.ContentProvider"; //$NON-NLS-1$
|
||||||
public final static String CLASS_INSTRUMENTATION = "android.app.Instrumentation"; //$NON-NLS-1$
|
public final static String CLASS_INSTRUMENTATION = "android.app.Instrumentation"; //$NON-NLS-1$
|
||||||
public final static String CLASS_INSTRUMENTATION_RUNNER =
|
public final static String CLASS_INSTRUMENTATION_RUNNER =
|
||||||
@@ -202,7 +198,7 @@ public class AndroidConstants {
|
|||||||
"android.preference." + CLASS_NAME_PREFERENCE_SCREEN; //$NON-NLS-1$
|
"android.preference." + CLASS_NAME_PREFERENCE_SCREEN; //$NON-NLS-1$
|
||||||
public final static String CLASS_PREFERENCEGROUP = "android.preference.PreferenceGroup"; //$NON-NLS-1$
|
public final static String CLASS_PREFERENCEGROUP = "android.preference.PreferenceGroup"; //$NON-NLS-1$
|
||||||
public final static String CLASS_PARCELABLE = "android.os.Parcelable"; //$NON-NLS-1$
|
public final static String CLASS_PARCELABLE = "android.os.Parcelable"; //$NON-NLS-1$
|
||||||
|
|
||||||
public final static String CLASS_BRIDGE = "com.android.layoutlib.bridge.Bridge"; //$NON-NLS-1$
|
public final static String CLASS_BRIDGE = "com.android.layoutlib.bridge.Bridge"; //$NON-NLS-1$
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -219,6 +215,6 @@ public class AndroidConstants {
|
|||||||
|
|
||||||
/** The base URL where to find the Android class & manifest documentation */
|
/** The base URL where to find the Android class & manifest documentation */
|
||||||
public static final String CODESITE_BASE_URL = "http://code.google.com/android"; //$NON-NLS-1$
|
public static final String CODESITE_BASE_URL = "http://code.google.com/android"; //$NON-NLS-1$
|
||||||
|
|
||||||
public static final String LIBRARY_TEST_RUNNER = "android.test.runner"; // $NON-NLS-1$
|
public static final String LIBRARY_TEST_RUNNER = "android.test.runner"; // $NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,18 +82,26 @@ public final class SdkConstants {
|
|||||||
/** dex.jar file */
|
/** dex.jar file */
|
||||||
public static final String FN_DX_JAR = "dx.jar"; //$NON-NLS-1$
|
public static final String FN_DX_JAR = "dx.jar"; //$NON-NLS-1$
|
||||||
|
|
||||||
/** dx executable */
|
/** dx executable (with extension for the current OS) */
|
||||||
public final static String FN_DX = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
|
public final static String FN_DX = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
|
||||||
"dx.bat" : "dx"; //$NON-NLS-1$ //$NON-NLS-2$
|
"dx.bat" : "dx"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
/** aapt executable */
|
/** aapt executable (with extension for the current OS) */
|
||||||
public final static String FN_AAPT = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
|
public final static String FN_AAPT = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
|
||||||
"aapt.exe" : "aapt"; //$NON-NLS-1$ //$NON-NLS-2$
|
"aapt.exe" : "aapt"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
/** aidl executable */
|
/** aidl executable (with extension for the current OS) */
|
||||||
public final static String FN_AIDL = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
|
public final static String FN_AIDL = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
|
||||||
"aidl.exe" : "aidl"; //$NON-NLS-1$ //$NON-NLS-2$
|
"aidl.exe" : "aidl"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
/** adb executable (with extension for the current OS) */
|
||||||
|
public final static String FN_ADB = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
|
||||||
|
"adb.exe" : "adb"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
/** emulator executable (with extension for the current OS) */
|
||||||
|
public final static String FN_EMULATOR = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
|
||||||
|
"emulator.exe" : "emulator"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
/* Folder Names for Android Projects . */
|
/* Folder Names for Android Projects . */
|
||||||
|
|
||||||
/** Resources folder name, i.e. "res". */
|
/** Resources folder name, i.e. "res". */
|
||||||
|
|||||||
@@ -16,10 +16,17 @@
|
|||||||
|
|
||||||
package com.android.sdklib.internal.repository;
|
package com.android.sdklib.internal.repository;
|
||||||
|
|
||||||
|
import com.android.sdklib.IAndroidTarget;
|
||||||
|
import com.android.sdklib.SdkConstants;
|
||||||
|
import com.android.sdklib.SdkManager;
|
||||||
|
import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
|
||||||
|
import com.android.sdklib.internal.repository.Archive.Arch;
|
||||||
|
import com.android.sdklib.internal.repository.Archive.Os;
|
||||||
import com.android.sdklib.repository.SdkRepository;
|
import com.android.sdklib.repository.SdkRepository;
|
||||||
|
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,8 +64,8 @@ public class AddonPackage extends Package {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* This constructor should throw an exception if the package cannot be created.
|
* This constructor should throw an exception if the package cannot be created.
|
||||||
*/
|
*/
|
||||||
AddonPackage(Node packageNode) {
|
AddonPackage(RepoSource source, Node packageNode) {
|
||||||
super(packageNode);
|
super(source, packageNode);
|
||||||
mVendor = getXmlString(packageNode, SdkRepository.NODE_VENDOR);
|
mVendor = getXmlString(packageNode, SdkRepository.NODE_VENDOR);
|
||||||
mName = getXmlString(packageNode, SdkRepository.NODE_NAME);
|
mName = getXmlString(packageNode, SdkRepository.NODE_NAME);
|
||||||
mApiLevel = getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
|
mApiLevel = getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
|
||||||
@@ -66,6 +73,41 @@ public class AddonPackage extends Package {
|
|||||||
mLibs = parseLibs(getFirstChild(packageNode, SdkRepository.NODE_LIBS));
|
mLibs = parseLibs(getFirstChild(packageNode, SdkRepository.NODE_LIBS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new platform package based on an actual {@link IAndroidTarget} (with
|
||||||
|
* {@link IAndroidTarget#isPlatform()} false) from the {@link SdkManager}.
|
||||||
|
* This is used to list local SDK folders.
|
||||||
|
*/
|
||||||
|
AddonPackage(IAndroidTarget target) {
|
||||||
|
super( null, //source
|
||||||
|
0, //revision
|
||||||
|
target.getDescription(), //description
|
||||||
|
null, //descUrl
|
||||||
|
Os.getCurrentOs(), //archiveOs
|
||||||
|
Arch.getCurrentArch(), //archiveArch
|
||||||
|
"", //archiveUrl //$NON-NLS-1$
|
||||||
|
0, //archiveSize
|
||||||
|
null //archiveChecksum
|
||||||
|
);
|
||||||
|
|
||||||
|
mApiLevel = target.getApiVersionNumber();
|
||||||
|
mName = target.getName();
|
||||||
|
mVendor = target.getVendor();
|
||||||
|
|
||||||
|
IOptionalLibrary[] optLibs = target.getOptionalLibraries();
|
||||||
|
if (optLibs == null || optLibs.length == 0) {
|
||||||
|
mLibs = new Lib[0];
|
||||||
|
} else {
|
||||||
|
mLibs = new Lib[optLibs.length];
|
||||||
|
for (int i = 0; i < optLibs.length; i++) {
|
||||||
|
mLibs[i] = new Lib(optLibs[i].getName(), optLibs[i].getDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a <libs> element.
|
||||||
|
*/
|
||||||
private Lib[] parseLibs(Node libsNode) {
|
private Lib[] parseLibs(Node libsNode) {
|
||||||
ArrayList<Lib> libs = new ArrayList<Lib>();
|
ArrayList<Lib> libs = new ArrayList<Lib>();
|
||||||
|
|
||||||
@@ -85,6 +127,9 @@ public class AddonPackage extends Package {
|
|||||||
return libs.toArray(new Lib[libs.size()]);
|
return libs.toArray(new Lib[libs.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a <lib> element from a <libs> container.
|
||||||
|
*/
|
||||||
private Lib parseLib(Node libNode) {
|
private Lib parseLib(Node libNode) {
|
||||||
return new Lib(getXmlString(libNode, SdkRepository.NODE_NAME),
|
return new Lib(getXmlString(libNode, SdkRepository.NODE_NAME),
|
||||||
getXmlString(libNode, SdkRepository.NODE_DESCRIPTION));
|
getXmlString(libNode, SdkRepository.NODE_DESCRIPTION));
|
||||||
@@ -126,4 +171,31 @@ public class AddonPackage extends Package {
|
|||||||
getShortDescription(),
|
getShortDescription(),
|
||||||
super.getLongDescription());
|
super.getLongDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a potential installation folder if an archive of this package were
|
||||||
|
* to be installed right away in the given SDK root.
|
||||||
|
* <p/>
|
||||||
|
* An add-on package is typically installed in SDK/add-ons/"addon-name"-"api-level".
|
||||||
|
* The name needs to be sanitized to be acceptable as a directory name.
|
||||||
|
* However if we can find a different directory under SDK/add-ons that already
|
||||||
|
* has this add-ons installed, we'll use that one.
|
||||||
|
*
|
||||||
|
* @param osSdkRoot The OS path of the SDK root folder.
|
||||||
|
* @return A new {@link File} corresponding to the directory to use to install this package.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public File getInstallFolder(String osSdkRoot) {
|
||||||
|
File addons = new File(osSdkRoot, SdkConstants.FD_ADDONS);
|
||||||
|
|
||||||
|
String name = String.format("%s-%d", getName(), getApiLevel()); // $NON-NLS-1$
|
||||||
|
|
||||||
|
name = name.replaceAll("[^a-zA-Z0-9_-]+", "_"); // $NON-NLS-1$
|
||||||
|
name = name.replaceAll("_+", "_"); // $NON-NLS-1$
|
||||||
|
|
||||||
|
File folder = new File(addons, name);
|
||||||
|
|
||||||
|
// TODO find similar existing addon in addons folder
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.android.sdklib.internal.repository;
|
package com.android.sdklib.internal.repository;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link Archive} is the base class for "something" that can be downloaded from
|
* A {@link Archive} is the base class for "something" that can be downloaded from
|
||||||
@@ -32,23 +35,106 @@ public class Archive implements IDescription {
|
|||||||
/** The checksum type. */
|
/** The checksum type. */
|
||||||
public enum ChecksumType {
|
public enum ChecksumType {
|
||||||
/** A SHA1 checksum, represented as a 40-hex string. */
|
/** A SHA1 checksum, represented as a 40-hex string. */
|
||||||
SHA1
|
SHA1("SHA-1"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
private final String mAlgorithmName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a {@link ChecksumType} with the algorigth name
|
||||||
|
* suitable for {@link MessageDigest#getInstance(String)}.
|
||||||
|
* <p/>
|
||||||
|
* These names are officially documented at
|
||||||
|
* http://java.sun.com/javase/6/docs/technotes/guides/security/StandardNames.html#MessageDigest
|
||||||
|
*/
|
||||||
|
private ChecksumType(String algorithmName) {
|
||||||
|
mAlgorithmName = algorithmName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link MessageDigest} instance for this checksum type.
|
||||||
|
* @throws NoSuchAlgorithmException if this algorithm is not available.
|
||||||
|
*/
|
||||||
|
public MessageDigest getMessageDigest() throws NoSuchAlgorithmException {
|
||||||
|
return MessageDigest.getInstance(mAlgorithmName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The OS that this archive can be downloaded on. */
|
/** The OS that this archive can be downloaded on. */
|
||||||
public enum Os {
|
public enum Os {
|
||||||
ANY,
|
ANY("Any"),
|
||||||
LINUX,
|
LINUX("Linux"),
|
||||||
MACOSX,
|
MACOSX("MacOS X"),
|
||||||
WINDOWS
|
WINDOWS("Windows");
|
||||||
|
|
||||||
|
private final String mUiName;
|
||||||
|
|
||||||
|
private Os(String uiName) {
|
||||||
|
mUiName = uiName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mUiName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current OS as one of the {@link Os} enum values or null.
|
||||||
|
*/
|
||||||
|
public static Os getCurrentOs() {
|
||||||
|
String os = System.getProperty("os.name"); //$NON-NLS-1$
|
||||||
|
if (os.startsWith("Mac OS")) { //$NON-NLS-1$
|
||||||
|
return Os.MACOSX;
|
||||||
|
|
||||||
|
} else if (os.startsWith("Windows")) { //$NON-NLS-1$
|
||||||
|
return Os.WINDOWS;
|
||||||
|
|
||||||
|
} else if (os.startsWith("Linux")) { //$NON-NLS-1$
|
||||||
|
return Os.LINUX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The Architecture that this archvie can be downloaded on. */
|
/** The Architecture that this archive can be downloaded on. */
|
||||||
public enum Arch {
|
public enum Arch {
|
||||||
ANY,
|
ANY("Any"),
|
||||||
PPC,
|
PPC("PowerPC"),
|
||||||
X86,
|
X86("x86"),
|
||||||
X86_64
|
X86_64("x86_64");
|
||||||
|
|
||||||
|
private final String mUiName;
|
||||||
|
|
||||||
|
private Arch(String uiName) {
|
||||||
|
mUiName = uiName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mUiName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current architecture as one of the {@link Arch} enum values or null.
|
||||||
|
*/
|
||||||
|
public static Arch getCurrentArch() {
|
||||||
|
// Values listed from http://lopica.sourceforge.net/os.html
|
||||||
|
String arch = System.getProperty("os.arch");
|
||||||
|
|
||||||
|
if (arch.equalsIgnoreCase("x86_64") || arch.equalsIgnoreCase("amd64")) {
|
||||||
|
return Arch.X86_64;
|
||||||
|
|
||||||
|
} else if (arch.equalsIgnoreCase("x86")
|
||||||
|
|| arch.equalsIgnoreCase("i386")
|
||||||
|
|| arch.equalsIgnoreCase("i686")) {
|
||||||
|
return Arch.X86;
|
||||||
|
|
||||||
|
} else if (arch.equalsIgnoreCase("ppc") || arch.equalsIgnoreCase("PowerPC")) {
|
||||||
|
return Arch.PPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Os mOs;
|
private final Os mOs;
|
||||||
@@ -57,11 +143,13 @@ public class Archive implements IDescription {
|
|||||||
private final long mSize;
|
private final long mSize;
|
||||||
private final String mChecksum;
|
private final String mChecksum;
|
||||||
private final ChecksumType mChecksumType = ChecksumType.SHA1;
|
private final ChecksumType mChecksumType = ChecksumType.SHA1;
|
||||||
|
private final Package mPackage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new archive.
|
* Creates a new archive.
|
||||||
*/
|
*/
|
||||||
Archive(Os os, Arch arch, String url, long size, String checksum) {
|
Archive(Package pkg, Os os, Arch arch, String url, long size, String checksum) {
|
||||||
|
mPackage = pkg;
|
||||||
mOs = os;
|
mOs = os;
|
||||||
mArch = arch;
|
mArch = arch;
|
||||||
mUrl = url;
|
mUrl = url;
|
||||||
@@ -69,63 +157,117 @@ public class Archive implements IDescription {
|
|||||||
mChecksum = checksum;
|
mChecksum = checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the archive size, an int > 0. */
|
/**
|
||||||
|
* Returns the package that created and owns this archive.
|
||||||
|
* It should generally not be null.
|
||||||
|
*/
|
||||||
|
public Package getParentPackage() {
|
||||||
|
return mPackage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the archive size, an int > 0.
|
||||||
|
* Size will be 0 if this a local installed folder of unknown size.
|
||||||
|
*/
|
||||||
public long getSize() {
|
public long getSize() {
|
||||||
return mSize;
|
return mSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the SHA1 archive checksum, as a 40-char hex. */
|
/**
|
||||||
|
* Returns the SHA1 archive checksum, as a 40-char hex.
|
||||||
|
* Can be empty but not null for local installed folders.
|
||||||
|
*/
|
||||||
public String getChecksum() {
|
public String getChecksum() {
|
||||||
return mChecksum;
|
return mChecksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the checksum type, always {@link ChecksumType#SHA1} right now. */
|
/**
|
||||||
|
* Returns the checksum type, always {@link ChecksumType#SHA1} right now.
|
||||||
|
*/
|
||||||
public ChecksumType getChecksumType() {
|
public ChecksumType getChecksumType() {
|
||||||
return mChecksumType;
|
return mChecksumType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the optional description URL for all packages (platform, add-on, tool, doc).
|
/**
|
||||||
* Can be empty but not null. */
|
* Returns the download archive URL, either absolute or relative to the repository xml.
|
||||||
public String getDescUrl() {
|
* For a local installed folder, an URL is frabricated from the folder path.
|
||||||
|
*/
|
||||||
|
public String getUrl() {
|
||||||
return mUrl;
|
return mUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the archive {@link Os} enum. */
|
/**
|
||||||
|
* Returns the archive {@link Os} enum.
|
||||||
|
* Can be null for a local installed folder on an unknown OS.
|
||||||
|
*/
|
||||||
public Os getOs() {
|
public Os getOs() {
|
||||||
return mOs;
|
return mOs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the archive {@link Arch} enum. */
|
/**
|
||||||
|
* Returns the archive {@link Arch} enum.
|
||||||
|
* Can be null for a local installed folder on an unknown architecture.
|
||||||
|
*/
|
||||||
public Arch getArch() {
|
public Arch getArch() {
|
||||||
return mArch;
|
return mArch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a short description for this archive.
|
||||||
|
*/
|
||||||
public String getShortDescription() {
|
public String getShortDescription() {
|
||||||
String os = "any OS";
|
String os;
|
||||||
if (mOs != Os.ANY) {
|
if (mOs == null) {
|
||||||
os = capitalize(mOs.toString());
|
os = "unknown OS";
|
||||||
|
} else if (mOs == Os.ANY) {
|
||||||
|
os = "any OS";
|
||||||
|
} else {
|
||||||
|
os = mOs.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
String arch = "";
|
String arch = "";
|
||||||
if (mArch != Arch.ANY) {
|
if (mArch != null && mArch != Arch.ANY) {
|
||||||
arch = mArch.toString().toLowerCase();
|
arch = mArch.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return String.format("Archive for %1$s %2$s", os, arch);
|
return String.format("Archive for %1$s %2$s", os, arch);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String capitalize(String string) {
|
/**
|
||||||
if (string.length() > 1) {
|
* Generates a longer description for this archive.
|
||||||
return string.substring(0, 1).toUpperCase() + string.substring(1).toLowerCase();
|
*/
|
||||||
} else {
|
|
||||||
return string.toUpperCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLongDescription() {
|
public String getLongDescription() {
|
||||||
return String.format("%1$s\nSize: %2$d MiB\nSHA1: %3$s",
|
return String.format("%1$s\nSize: %2$d MiB\nSHA1: %3$s",
|
||||||
getShortDescription(),
|
getShortDescription(),
|
||||||
Math.round(getSize() / (1024*1024)),
|
Math.round(getSize() / (1024*1024)),
|
||||||
getChecksum());
|
getChecksum());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this archive can be installed on the current platform.
|
||||||
|
*/
|
||||||
|
public boolean isCompatible() {
|
||||||
|
// Check OS
|
||||||
|
Os os = getOs();
|
||||||
|
|
||||||
|
if (os != Os.ANY) {
|
||||||
|
Os os2 = Os.getCurrentOs();
|
||||||
|
if (os2 != os) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Arch
|
||||||
|
Arch arch = getArch();
|
||||||
|
|
||||||
|
if (arch != Arch.ANY) {
|
||||||
|
Arch arch2 = Arch.getCurrentArch();
|
||||||
|
if (arch2 != arch) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,15 @@
|
|||||||
|
|
||||||
package com.android.sdklib.internal.repository;
|
package com.android.sdklib.internal.repository;
|
||||||
|
|
||||||
|
import com.android.sdklib.SdkConstants;
|
||||||
|
import com.android.sdklib.internal.repository.Archive.Arch;
|
||||||
|
import com.android.sdklib.internal.repository.Archive.Os;
|
||||||
import com.android.sdklib.repository.SdkRepository;
|
import com.android.sdklib.repository.SdkRepository;
|
||||||
|
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a doc XML node in an SDK repository.
|
* Represents a doc XML node in an SDK repository.
|
||||||
*/
|
*/
|
||||||
@@ -32,12 +37,39 @@ public class DocPackage extends Package {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* This constructor should throw an exception if the package cannot be created.
|
* This constructor should throw an exception if the package cannot be created.
|
||||||
*/
|
*/
|
||||||
DocPackage(Node packageNode) {
|
DocPackage(RepoSource source, Node packageNode) {
|
||||||
super(packageNode);
|
super(source, packageNode);
|
||||||
mApiLevel = getXmlInt(packageNode, SdkRepository.NODE_API_LEVEL, 0);
|
mApiLevel = getXmlInt(packageNode, SdkRepository.NODE_API_LEVEL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the api-level, an int > 0, for platform, add-on and doc packages. */
|
/**
|
||||||
|
* Manually create a new package with one archive and the given attributes.
|
||||||
|
* This is used to create packages from local directories.
|
||||||
|
*/
|
||||||
|
DocPackage(RepoSource source,
|
||||||
|
int apiLevel,
|
||||||
|
int revision,
|
||||||
|
String description,
|
||||||
|
String descUrl,
|
||||||
|
Os archiveOs,
|
||||||
|
Arch archiveArch,
|
||||||
|
String archiveUrl,
|
||||||
|
long archiveSize,
|
||||||
|
String archiveChecksum) {
|
||||||
|
super(source,
|
||||||
|
revision,
|
||||||
|
description,
|
||||||
|
descUrl,
|
||||||
|
archiveOs,
|
||||||
|
archiveArch,
|
||||||
|
archiveUrl,
|
||||||
|
archiveSize,
|
||||||
|
archiveChecksum);
|
||||||
|
mApiLevel = apiLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the api-level, an int > 0, for platform, add-on and doc packages.
|
||||||
|
* Can be 0 if this is a local package of unknown api-level. */
|
||||||
public int getApiLevel() {
|
public int getApiLevel() {
|
||||||
return mApiLevel;
|
return mApiLevel;
|
||||||
}
|
}
|
||||||
@@ -45,7 +77,11 @@ public class DocPackage extends Package {
|
|||||||
/** Returns a short description for an {@link IDescription}. */
|
/** Returns a short description for an {@link IDescription}. */
|
||||||
@Override
|
@Override
|
||||||
public String getShortDescription() {
|
public String getShortDescription() {
|
||||||
return String.format("Documentation for SDK Android API %1$d", getApiLevel());
|
if (mApiLevel != 0) {
|
||||||
|
return String.format("Documentation for Android SDK, API %1$d", mApiLevel);
|
||||||
|
} else {
|
||||||
|
return String.format("Documentation for Android SDK");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a long description for an {@link IDescription}. */
|
/** Returns a long description for an {@link IDescription}. */
|
||||||
@@ -55,4 +91,18 @@ public class DocPackage extends Package {
|
|||||||
getShortDescription(),
|
getShortDescription(),
|
||||||
super.getLongDescription());
|
super.getLongDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a potential installation folder if an archive of this package were
|
||||||
|
* to be installed right away in the given SDK root.
|
||||||
|
* <p/>
|
||||||
|
* A "doc" package should always be located in SDK/docs.
|
||||||
|
*
|
||||||
|
* @param osSdkRoot The OS path of the SDK root folder.
|
||||||
|
* @return A new {@link File} corresponding to the directory to use to install this package.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public File getInstallFolder(String osSdkRoot) {
|
||||||
|
return new File(osSdkRoot, SdkConstants.FD_DOCS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,13 +34,13 @@ public interface ITaskMonitor {
|
|||||||
* Sets the description in the current task dialog.
|
* Sets the description in the current task dialog.
|
||||||
* This method can be invoked from a non-UI thread.
|
* This method can be invoked from a non-UI thread.
|
||||||
*/
|
*/
|
||||||
public void setDescription(String description);
|
public void setDescription(String descriptionFormat, Object...args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the result text in the current task dialog.
|
* Sets the result text in the current task dialog.
|
||||||
* This method can be invoked from a non-UI thread.
|
* This method can be invoked from a non-UI thread.
|
||||||
*/
|
*/
|
||||||
public void setResult(String result);
|
public void setResult(String resultFormat, Object...args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the max value of the progress bar.
|
* Sets the max value of the progress bar.
|
||||||
|
|||||||
@@ -0,0 +1,415 @@
|
|||||||
|
/*
|
||||||
|
* 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.IAndroidTarget;
|
||||||
|
import com.android.sdklib.ISdkLog;
|
||||||
|
import com.android.sdklib.SdkConstants;
|
||||||
|
import com.android.sdklib.SdkManager;
|
||||||
|
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.Document;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
import javax.xml.validation.SchemaFactory;
|
||||||
|
import javax.xml.validation.Validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans a local SDK to find which packages are currently installed.
|
||||||
|
*/
|
||||||
|
public class LocalSdkParser {
|
||||||
|
|
||||||
|
private static final String SOURCE_XML = "source.xml"; //$NON-NLS-1$ // TODO move to global constants
|
||||||
|
private Package[] mPackages;
|
||||||
|
|
||||||
|
public LocalSdkParser() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the packages found by the last call to {@link #parseSdk(String)}.
|
||||||
|
*/
|
||||||
|
public Package[] getPackages() {
|
||||||
|
return mPackages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the internal packages list. After this call, {@link #getPackages()} will return
|
||||||
|
* null till {@link #parseSdk(String)} is called.
|
||||||
|
*/
|
||||||
|
public void clearPackages() {
|
||||||
|
mPackages = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan the give SDK to find all the packages already installed at this location.
|
||||||
|
* <p/>
|
||||||
|
* Store the packages internally. You can use {@link #getPackages()} to retrieve them
|
||||||
|
* at any time later.
|
||||||
|
*
|
||||||
|
* @param osSdkRoot The path to the SDK folder.
|
||||||
|
* @return The packages found. Can be retrieved later using {@link #getPackages()}.
|
||||||
|
*/
|
||||||
|
public Package[] parseSdk(String osSdkRoot) {
|
||||||
|
ArrayList<Package> packages = new ArrayList<Package>();
|
||||||
|
|
||||||
|
Package pkg = scanDoc(new File(osSdkRoot, SdkConstants.FD_DOCS));
|
||||||
|
if (pkg != null) {
|
||||||
|
packages.add(pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg = scanTools(new File(osSdkRoot, SdkConstants.FD_TOOLS));
|
||||||
|
if (pkg != null) {
|
||||||
|
packages.add(pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for platforms and add-ons, rely on the SdkManager parser
|
||||||
|
SdkManager sdkman = SdkManager.createManager(osSdkRoot, new ISdkLog() {
|
||||||
|
// A dummy sdk logger that doesn't log anything.
|
||||||
|
public void error(Throwable t, String errorFormat, Object... args) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
public void printf(String msgFormat, Object... args) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
public void warning(String warningFormat, Object... args) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for(IAndroidTarget target : sdkman.getTargets()) {
|
||||||
|
pkg = null;
|
||||||
|
|
||||||
|
if (target.isPlatform()) {
|
||||||
|
pkg = parseXml(new File(target.getLocation(), SOURCE_XML),
|
||||||
|
SdkRepository.NODE_PLATFORM);
|
||||||
|
if (pkg == null) {
|
||||||
|
pkg = new PlatformPackage(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pkg = parseXml(new File(target.getLocation(), SOURCE_XML),
|
||||||
|
SdkRepository.NODE_ADD_ON);
|
||||||
|
|
||||||
|
if (pkg == null) {
|
||||||
|
pkg = new AddonPackage(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkg != null) {
|
||||||
|
packages.add(pkg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mPackages = packages.toArray(new Package[packages.size()]);
|
||||||
|
return mPackages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to find a tools package at the given location.
|
||||||
|
* Returns null if not found.
|
||||||
|
*/
|
||||||
|
private Package scanTools(File toolFolder) {
|
||||||
|
// Can we find a source.xml?
|
||||||
|
Package pkg = parseXml(new File(toolFolder, SOURCE_XML), SdkRepository.NODE_TOOL);
|
||||||
|
|
||||||
|
// We're not going to check that all tools are present. At the very least
|
||||||
|
// we should expect to find adb, android and an emulator adapted to the current OS.
|
||||||
|
Set<String> names = new HashSet<String>();
|
||||||
|
for (File file : toolFolder.listFiles()) {
|
||||||
|
names.add(file.getName());
|
||||||
|
}
|
||||||
|
if (!names.contains(SdkConstants.FN_ADB) ||
|
||||||
|
!names.contains(SdkConstants.androidCmdName()) ||
|
||||||
|
!names.contains(SdkConstants.FN_EMULATOR)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we don't have the package info, make one up
|
||||||
|
if (pkg == null) {
|
||||||
|
pkg = new ToolPackage(
|
||||||
|
null, //source
|
||||||
|
0, //revision
|
||||||
|
"Tools", //description
|
||||||
|
null, //descUrl
|
||||||
|
Os.getCurrentOs(), //archiveOs
|
||||||
|
Arch.getCurrentArch(), //archiveArch
|
||||||
|
"", //archiveUrl //$NON-NLS-1$
|
||||||
|
0, //archiveSize
|
||||||
|
null //archiveChecksum
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to find a docs package at the given location.
|
||||||
|
* Returns null if not found.
|
||||||
|
*/
|
||||||
|
private Package scanDoc(File docFolder) {
|
||||||
|
// Can we find a source.xml?
|
||||||
|
Package pkg = parseXml(new File(docFolder, SOURCE_XML), SdkRepository.NODE_DOC);
|
||||||
|
|
||||||
|
// To start with, a doc folder should have an "index.html" to be acceptable.
|
||||||
|
String html = readFile(new File(docFolder, "index.html"));
|
||||||
|
if (html != null) {
|
||||||
|
// Try to find something that looks like this line:
|
||||||
|
// <a href="./sdk/1.5_r1/index.html">
|
||||||
|
// We should find one or more of these and we want the highest version
|
||||||
|
// and release numbers. Note that unfortunately that doesn't give us
|
||||||
|
// the api-level we care about for the doc package.
|
||||||
|
|
||||||
|
String found = null;
|
||||||
|
Pattern re = Pattern.compile(
|
||||||
|
"<a\\s+href=\"./sdk/(\\d\\.\\d_r\\d)/index.html\">",
|
||||||
|
Pattern.DOTALL);
|
||||||
|
Matcher m = re.matcher(html);
|
||||||
|
while(m.find()) {
|
||||||
|
String v = m.group(1);
|
||||||
|
if (found == null || v.compareTo(found) == 1) {
|
||||||
|
found = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found == null) {
|
||||||
|
// That doesn't look like a doc folder.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found the line, so it seems like an SDK doc.
|
||||||
|
// Create a pkg if we don't have one yet.
|
||||||
|
|
||||||
|
if (pkg == null) {
|
||||||
|
String url = null;
|
||||||
|
try {
|
||||||
|
url = docFolder.toURI().toURL().toString();
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg = new DocPackage(
|
||||||
|
null, //source
|
||||||
|
0, //apiLevel
|
||||||
|
0, //revision
|
||||||
|
String.format("Documentation for %1$s", found), //description
|
||||||
|
null, //descUrl
|
||||||
|
Os.getCurrentOs(), //archiveOs
|
||||||
|
Arch.getCurrentArch(), //archiveArch
|
||||||
|
url, //archiveUrl
|
||||||
|
0, //archiveSize
|
||||||
|
null //archiveChecksum
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the given XML file for the specific element filter.
|
||||||
|
* The element must one of the package type local names: doc, tool, platform or addon.
|
||||||
|
* Returns null if no such package was found.
|
||||||
|
*/
|
||||||
|
private Package parseXml(File sourceXmlFile, String elementFilter) {
|
||||||
|
|
||||||
|
String xml = readFile(sourceXmlFile);
|
||||||
|
if (xml != null) {
|
||||||
|
if (validateXml(xml)) {
|
||||||
|
return parsePackages(xml, elementFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the given XML to find the specific element filter.
|
||||||
|
* The element must one of the package type local names: doc, tool, platform or addon.
|
||||||
|
* Returns null if no such package was found.
|
||||||
|
*/
|
||||||
|
private Package parsePackages(String xml, String elementFilter) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
Document doc = getDocument(xml);
|
||||||
|
|
||||||
|
Node root = getFirstChild(doc, SdkRepository.NODE_SDK_REPOSITORY);
|
||||||
|
if (root != null) {
|
||||||
|
|
||||||
|
for (Node child = root.getFirstChild();
|
||||||
|
child != null;
|
||||||
|
child = child.getNextSibling()) {
|
||||||
|
if (child.getNodeType() == Node.ELEMENT_NODE &&
|
||||||
|
SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI()) &&
|
||||||
|
elementFilter.equals(child.getLocalName())) {
|
||||||
|
String name = child.getLocalName();
|
||||||
|
Package p = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (SdkRepository.NODE_ADD_ON.equals(name)) {
|
||||||
|
return new AddonPackage(null /*source*/, child);
|
||||||
|
|
||||||
|
} else if (SdkRepository.NODE_PLATFORM.equals(name)) {
|
||||||
|
return new PlatformPackage(null /*source*/, child);
|
||||||
|
|
||||||
|
} else if (SdkRepository.NODE_DOC.equals(name)) {
|
||||||
|
return new DocPackage(null /*source*/, child);
|
||||||
|
|
||||||
|
} else if (SdkRepository.NODE_TOOL.equals(name)) {
|
||||||
|
return new ToolPackage(null /*source*/, child);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Ignore invalid packages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a file as a string.
|
||||||
|
* Returns null if the file could not be read.
|
||||||
|
*/
|
||||||
|
private String readFile(File sourceXmlFile) {
|
||||||
|
FileReader fr = null;
|
||||||
|
try {
|
||||||
|
fr = new FileReader(sourceXmlFile);
|
||||||
|
BufferedReader br = new BufferedReader(fr);
|
||||||
|
StringBuilder dest = new StringBuilder();
|
||||||
|
char[] buf = new char[65536];
|
||||||
|
int n;
|
||||||
|
while ((n = br.read(buf)) > 0) {
|
||||||
|
if (n > 0) {
|
||||||
|
dest.append(buf, 0, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dest.toString();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
// ignore
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (fr != null) {
|
||||||
|
try {
|
||||||
|
fr.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates this XML against the SDK Repository schema.
|
||||||
|
* Returns true if the XML was correctly validated.
|
||||||
|
*/
|
||||||
|
private boolean validateXml(String xml) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
Validator validator = getValidator();
|
||||||
|
validator.validate(new StreamSource(new StringReader(xml)));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (SAXException e) {
|
||||||
|
// ignore
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method that returns a validator for our XSD
|
||||||
|
*/
|
||||||
|
private Validator getValidator() throws SAXException {
|
||||||
|
InputStream xsdStream = SdkRepository.getXsdStream();
|
||||||
|
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||||
|
|
||||||
|
// This may throw a SAX Exception if the schema itself is not a valid XSD
|
||||||
|
Schema schema = factory.newSchema(new StreamSource(xsdStream));
|
||||||
|
|
||||||
|
Validator validator = schema.newValidator();
|
||||||
|
|
||||||
|
return validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first child element with the given XML local name.
|
||||||
|
* If xmlLocalName is null, returns the very first child element.
|
||||||
|
*/
|
||||||
|
private Node getFirstChild(Node node, String xmlLocalName) {
|
||||||
|
|
||||||
|
for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||||
|
if (child.getNodeType() == Node.ELEMENT_NODE &&
|
||||||
|
SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI())) {
|
||||||
|
if (xmlLocalName == null || child.getLocalName().equals(xmlLocalName)) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes an XML document as a string as parameter and returns a DOM for it.
|
||||||
|
*/
|
||||||
|
private Document getDocument(String xml)
|
||||||
|
throws ParserConfigurationException, SAXException, IOException {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
factory.setIgnoringComments(true);
|
||||||
|
factory.setNamespaceAware(true);
|
||||||
|
|
||||||
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
Document doc = builder.parse(new InputSource(new StringReader(xml)));
|
||||||
|
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ import com.android.sdklib.repository.SdkRepository;
|
|||||||
|
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,13 +43,15 @@ public abstract class Package implements IDescription {
|
|||||||
private final String mDescription;
|
private final String mDescription;
|
||||||
private final String mDescUrl;
|
private final String mDescUrl;
|
||||||
private final Archive[] mArchives;
|
private final Archive[] mArchives;
|
||||||
|
private final RepoSource mSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new package from the attributes and elements of the given XML node.
|
* Creates a new package from the attributes and elements of the given XML node.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This constructor should throw an exception if the package cannot be created.
|
* This constructor should throw an exception if the package cannot be created.
|
||||||
*/
|
*/
|
||||||
Package(Node packageNode) {
|
Package(RepoSource source, Node packageNode) {
|
||||||
|
mSource = source;
|
||||||
mRevision = getXmlInt (packageNode, SdkRepository.NODE_REVISION, 0);
|
mRevision = getXmlInt (packageNode, SdkRepository.NODE_REVISION, 0);
|
||||||
mDescription = getXmlString(packageNode, SdkRepository.NODE_DESCRIPTION);
|
mDescription = getXmlString(packageNode, SdkRepository.NODE_DESCRIPTION);
|
||||||
mDescUrl = getXmlString(packageNode, SdkRepository.NODE_DESC_URL);
|
mDescUrl = getXmlString(packageNode, SdkRepository.NODE_DESC_URL);
|
||||||
@@ -56,6 +59,35 @@ public abstract class Package implements IDescription {
|
|||||||
mArchives = parseArchives(getFirstChild(packageNode, SdkRepository.NODE_ARCHIVES));
|
mArchives = parseArchives(getFirstChild(packageNode, SdkRepository.NODE_ARCHIVES));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually create a new package with one archive and the given attributes.
|
||||||
|
* This is used to create packages from local directories.
|
||||||
|
*/
|
||||||
|
public Package(RepoSource source,
|
||||||
|
int revision,
|
||||||
|
String description,
|
||||||
|
String descUrl,
|
||||||
|
Os archiveOs,
|
||||||
|
Arch archiveArch,
|
||||||
|
String archiveUrl,
|
||||||
|
long archiveSize,
|
||||||
|
String archiveChecksum) {
|
||||||
|
mSource = source;
|
||||||
|
mRevision = revision;
|
||||||
|
mDescription = description;
|
||||||
|
mDescUrl = descUrl;
|
||||||
|
mArchives = new Archive[1];
|
||||||
|
mArchives[0] = new Archive(this,
|
||||||
|
archiveOs,
|
||||||
|
archiveArch,
|
||||||
|
archiveUrl,
|
||||||
|
archiveSize,
|
||||||
|
archiveChecksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an XML node to process the <archives> element.
|
||||||
|
*/
|
||||||
private Archive[] parseArchives(Node archivesNode) {
|
private Archive[] parseArchives(Node archivesNode) {
|
||||||
ArrayList<Archive> archives = new ArrayList<Archive>();
|
ArrayList<Archive> archives = new ArrayList<Archive>();
|
||||||
|
|
||||||
@@ -75,52 +107,99 @@ public abstract class Package implements IDescription {
|
|||||||
return archives.toArray(new Archive[archives.size()]);
|
return archives.toArray(new Archive[archives.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses one <archive> element from an <archives> container.
|
||||||
|
*/
|
||||||
private Archive parseArchive(Node archiveNode) {
|
private Archive parseArchive(Node archiveNode) {
|
||||||
Archive a = new Archive(
|
Archive a = new Archive(
|
||||||
|
this,
|
||||||
(Os) getEnumAttribute(archiveNode, SdkRepository.ATTR_OS,
|
(Os) getEnumAttribute(archiveNode, SdkRepository.ATTR_OS,
|
||||||
Os.values(), null),
|
Os.values(), null),
|
||||||
(Arch) getEnumAttribute(archiveNode, SdkRepository.ATTR_ARCH,
|
(Arch) getEnumAttribute(archiveNode, SdkRepository.ATTR_ARCH,
|
||||||
Arch.values(), Arch.ANY),
|
Arch.values(), Arch.ANY),
|
||||||
getXmlString(archiveNode, SdkRepository.NODE_URL),
|
getXmlString(archiveNode, SdkRepository.NODE_URL),
|
||||||
getXmlInt(archiveNode, SdkRepository.NODE_SIZE, 0),
|
getXmlLong(archiveNode, SdkRepository.NODE_SIZE, 0),
|
||||||
getXmlString(archiveNode, SdkRepository.NODE_CHECKSUM)
|
getXmlString(archiveNode, SdkRepository.NODE_CHECKSUM)
|
||||||
);
|
);
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the revision, an int > 0, for all packages (platform, add-on, tool, doc). */
|
/**
|
||||||
|
* Returns the source that created (and owns) this package. Can be null.
|
||||||
|
*/
|
||||||
|
public RepoSource getParentSource() {
|
||||||
|
return mSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the revision, an int > 0, for all packages (platform, add-on, tool, doc).
|
||||||
|
* Can be 0 if this is a local package of unknown revision.
|
||||||
|
*/
|
||||||
public int getRevision() {
|
public int getRevision() {
|
||||||
return mRevision;
|
return mRevision;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the optional description for all packages (platform, add-on, tool, doc) or
|
/**
|
||||||
* for a lib. */
|
* Returns the optional description for all packages (platform, add-on, tool, doc) or
|
||||||
|
* for a lib. Can be empty but not null.
|
||||||
|
*/
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return mDescription;
|
return mDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the optional description URL for all packages (platform, add-on, tool, doc).
|
/**
|
||||||
* Can be empty but not null. */
|
* Returns the optional description URL for all packages (platform, add-on, tool, doc).
|
||||||
|
* Can be empty but not null.
|
||||||
|
*/
|
||||||
public String getDescUrl() {
|
public String getDescUrl() {
|
||||||
return mDescUrl;
|
return mDescUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the archives defined in this package. Can be an empty array but not null. */
|
/**
|
||||||
|
* Returns the archives defined in this package.
|
||||||
|
* Can be an empty array but not null.
|
||||||
|
*/
|
||||||
public Archive[] getArchives() {
|
public Archive[] getArchives() {
|
||||||
return mArchives;
|
return mArchives;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a short description for an {@link IDescription}. */
|
/**
|
||||||
|
* Returns a short description for an {@link IDescription}.
|
||||||
|
* Can be empty but not null.
|
||||||
|
*/
|
||||||
public abstract String getShortDescription();
|
public abstract String getShortDescription();
|
||||||
|
|
||||||
/** Returns a long description for an {@link IDescription}. */
|
/**
|
||||||
|
* Returns a long description for an {@link IDescription}.
|
||||||
|
* Can be empty but not null.
|
||||||
|
*/
|
||||||
public String getLongDescription() {
|
public String getLongDescription() {
|
||||||
return String.format("%1$s\nRevision %2$d", getDescription(), getRevision());
|
return String.format("%1$s\nRevision %2$d", getDescription(), getRevision());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a potential installation folder if an archive of this package were
|
||||||
|
* to be installed right away in the given SDK root.
|
||||||
|
* <p/>
|
||||||
|
* Some types of packages install in a fix location, for example docs and tools.
|
||||||
|
* In this case the returned folder may already exist with a different archive installed
|
||||||
|
* at the desired location.
|
||||||
|
* For other packages types, such as add-on or platform, the folder name is only partially
|
||||||
|
* relevant to determine the content and thus a real check will be done to provide an
|
||||||
|
* existing or new folder depending on the current content of the SDK.
|
||||||
|
*
|
||||||
|
* @param osSdkRoot The OS path of the SDK root folder.
|
||||||
|
* @return A new {@link File} corresponding to the directory to use to install this package.
|
||||||
|
*/
|
||||||
|
public abstract File getInstallFolder(String osSdkRoot);
|
||||||
|
|
||||||
//---
|
//---
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first child element with the given XML local name.
|
||||||
|
* If xmlLocalName is null, returns the very first child element.
|
||||||
|
*/
|
||||||
protected static Node getFirstChild(Node node, String xmlLocalName) {
|
protected static Node getFirstChild(Node node, String xmlLocalName) {
|
||||||
|
|
||||||
for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
|
for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||||
@@ -158,6 +237,19 @@ public abstract class Package implements IDescription {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the value of that XML element as a long.
|
||||||
|
* Returns the default value when the element is missing or is not an integer.
|
||||||
|
*/
|
||||||
|
protected static long getXmlLong(Node node, String xmlLocalName, long defaultValue) {
|
||||||
|
String s = getXmlString(node, xmlLocalName);
|
||||||
|
try {
|
||||||
|
return Long.parseLong(s);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve an attribute which value must match one of the given enums using a
|
* Retrieve an attribute which value must match one of the given enums using a
|
||||||
* case-insensitive name match.
|
* case-insensitive name match.
|
||||||
|
|||||||
@@ -16,10 +16,17 @@
|
|||||||
|
|
||||||
package com.android.sdklib.internal.repository;
|
package com.android.sdklib.internal.repository;
|
||||||
|
|
||||||
|
import com.android.sdklib.IAndroidTarget;
|
||||||
|
import com.android.sdklib.SdkConstants;
|
||||||
|
import com.android.sdklib.SdkManager;
|
||||||
|
import com.android.sdklib.internal.repository.Archive.Arch;
|
||||||
|
import com.android.sdklib.internal.repository.Archive.Os;
|
||||||
import com.android.sdklib.repository.SdkRepository;
|
import com.android.sdklib.repository.SdkRepository;
|
||||||
|
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a platform XML node in an SDK repository.
|
* Represents a platform XML node in an SDK repository.
|
||||||
*/
|
*/
|
||||||
@@ -33,12 +40,33 @@ public class PlatformPackage extends Package {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* This constructor should throw an exception if the package cannot be created.
|
* This constructor should throw an exception if the package cannot be created.
|
||||||
*/
|
*/
|
||||||
PlatformPackage(Node packageNode) {
|
PlatformPackage(RepoSource source, Node packageNode) {
|
||||||
super(packageNode);
|
super(source, packageNode);
|
||||||
mVersion = getXmlString(packageNode, SdkRepository.NODE_VERSION);
|
mVersion = getXmlString(packageNode, SdkRepository.NODE_VERSION);
|
||||||
mApiLevel = getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
|
mApiLevel = getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new platform package based on an actual {@link IAndroidTarget} (with
|
||||||
|
* must have {@link IAndroidTarget#isPlatform()} true) from the {@link SdkManager}.
|
||||||
|
* This is used to list local SDK folders.
|
||||||
|
*/
|
||||||
|
PlatformPackage(IAndroidTarget target) {
|
||||||
|
super( null, //source
|
||||||
|
0, //revision
|
||||||
|
target.getDescription(), //description
|
||||||
|
null, //descUrl
|
||||||
|
Os.getCurrentOs(), //archiveOs
|
||||||
|
Arch.getCurrentArch(), //archiveArch
|
||||||
|
"", //archiveUrl //$NON-NLS-1$
|
||||||
|
0, //archiveSize
|
||||||
|
null //archiveChecksum
|
||||||
|
);
|
||||||
|
|
||||||
|
mApiLevel = target.getApiVersionNumber();
|
||||||
|
mVersion = target.getApiVersionName();
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the version, a string, for platform packages. */
|
/** Returns the version, a string, for platform packages. */
|
||||||
public String getVersion() {
|
public String getVersion() {
|
||||||
return mVersion;
|
return mVersion;
|
||||||
@@ -64,4 +92,23 @@ public class PlatformPackage extends Package {
|
|||||||
getShortDescription(),
|
getShortDescription(),
|
||||||
super.getLongDescription());
|
super.getLongDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a potential installation folder if an archive of this package were
|
||||||
|
* to be installed right away in the given SDK root.
|
||||||
|
* <p/>
|
||||||
|
* A platform package is typically installed in SDK/platforms/android-"version".
|
||||||
|
* However if we can find a different directory under SDK/platform that already
|
||||||
|
* has this platform version installed, we'll use that one.
|
||||||
|
*
|
||||||
|
* @param osSdkRoot The OS path of the SDK root folder.
|
||||||
|
* @return A new {@link File} corresponding to the directory to use to install this package.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public File getInstallFolder(String osSdkRoot) {
|
||||||
|
File platforms = new File(osSdkRoot, SdkConstants.FD_PLATFORMS);
|
||||||
|
File folder = new File(platforms, String.format("android-%s", getVersion())); //$NON-NLS-1$
|
||||||
|
// TODO find similar existing platform in platforms folder
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,12 +68,21 @@ public class RepoSource implements IDescription {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of known packages. This is null when the source hasn't been loaded yet.
|
* Returns the list of known packages found by the last call to {@link #load(ITaskFactory)}.
|
||||||
|
* This is null when the source hasn't been loaded yet.
|
||||||
*/
|
*/
|
||||||
public Package[] getPackages() {
|
public Package[] getPackages() {
|
||||||
return mPackages;
|
return mPackages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the internal packages list. After this call, {@link #getPackages()} will return
|
||||||
|
* null till {@link #load(ITaskFactory)} is called.
|
||||||
|
*/
|
||||||
|
public void clearPackages() {
|
||||||
|
mPackages = null;
|
||||||
|
}
|
||||||
|
|
||||||
public String getShortDescription() {
|
public String getShortDescription() {
|
||||||
return mUrl;
|
return mUrl;
|
||||||
}
|
}
|
||||||
@@ -93,7 +102,7 @@ public class RepoSource implements IDescription {
|
|||||||
|
|
||||||
setDefaultDescription();
|
setDefaultDescription();
|
||||||
|
|
||||||
monitor.setDescription(String.format("Fetching %1$s", mUrl));
|
monitor.setDescription("Fetching %1$s", mUrl);
|
||||||
monitor.incProgress(1);
|
monitor.incProgress(1);
|
||||||
|
|
||||||
String xml = fetchUrl(mUrl, monitor);
|
String xml = fetchUrl(mUrl, monitor);
|
||||||
@@ -136,7 +145,10 @@ public class RepoSource implements IDescription {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* Fetches the document at the given URL and returns it as a string.
|
||||||
|
* Returns null if anything wrong happens and write errors to the monitor.
|
||||||
|
*
|
||||||
* References:
|
* References:
|
||||||
* Java URL Connection: http://java.sun.com/docs/books/tutorial/networking/urls/readingWriting.html
|
* Java URL Connection: http://java.sun.com/docs/books/tutorial/networking/urls/readingWriting.html
|
||||||
* Java URL Reader: http://java.sun.com/docs/books/tutorial/networking/urls/readingURL.html
|
* Java URL Reader: http://java.sun.com/docs/books/tutorial/networking/urls/readingURL.html
|
||||||
@@ -186,6 +198,10 @@ public class RepoSource implements IDescription {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates this XML against the SDK Repository schema.
|
||||||
|
* Returns true if the XML was correctly validated.
|
||||||
|
*/
|
||||||
private boolean validateXml(String xml, ITaskMonitor monitor) {
|
private boolean validateXml(String xml, ITaskMonitor monitor) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -203,7 +219,9 @@ public class RepoSource implements IDescription {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Helper method that returns a validator for our XSD */
|
/**
|
||||||
|
* Helper method that returns a validator for our XSD
|
||||||
|
*/
|
||||||
private Validator getValidator() throws SAXException {
|
private Validator getValidator() throws SAXException {
|
||||||
InputStream xsdStream = SdkRepository.getXsdStream();
|
InputStream xsdStream = SdkRepository.getXsdStream();
|
||||||
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||||
@@ -217,6 +235,10 @@ public class RepoSource implements IDescription {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse all packages defined in the SDK Repository XML and creates
|
||||||
|
* a new mPackages array with them.
|
||||||
|
*/
|
||||||
private boolean parsePackages(String xml, ITaskMonitor monitor) {
|
private boolean parsePackages(String xml, ITaskMonitor monitor) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -237,22 +259,21 @@ public class RepoSource implements IDescription {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (SdkRepository.NODE_ADD_ON.equals(name)) {
|
if (SdkRepository.NODE_ADD_ON.equals(name)) {
|
||||||
p = new AddonPackage(child);
|
p = new AddonPackage(this, child);
|
||||||
|
|
||||||
} else if (!mAddonOnly) {
|
} else if (!mAddonOnly) {
|
||||||
if (SdkRepository.NODE_PLATFORM.equals(name)) {
|
if (SdkRepository.NODE_PLATFORM.equals(name)) {
|
||||||
p = new PlatformPackage(child);
|
p = new PlatformPackage(this, child);
|
||||||
} else if (SdkRepository.NODE_DOC.equals(name)) {
|
} else if (SdkRepository.NODE_DOC.equals(name)) {
|
||||||
p = new DocPackage(child);
|
p = new DocPackage(this, child);
|
||||||
} else if (SdkRepository.NODE_TOOL.equals(name)) {
|
} else if (SdkRepository.NODE_TOOL.equals(name)) {
|
||||||
p = new ToolPackage(child);
|
p = new ToolPackage(this, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
packages.add(p);
|
packages.add(p);
|
||||||
monitor.setDescription(
|
monitor.setDescription("Found %1$s", p.getShortDescription());
|
||||||
String.format("Found %1$s", p.getShortDescription()));
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Ignore invalid packages
|
// Ignore invalid packages
|
||||||
@@ -278,6 +299,10 @@ public class RepoSource implements IDescription {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first child element with the given XML local name.
|
||||||
|
* If xmlLocalName is null, returns the very first child element.
|
||||||
|
*/
|
||||||
private Node getFirstChild(Node node, String xmlLocalName) {
|
private Node getFirstChild(Node node, String xmlLocalName) {
|
||||||
|
|
||||||
for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
|
for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||||
@@ -292,6 +317,9 @@ public class RepoSource implements IDescription {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes an XML document as a string as parameter and returns a DOM for it.
|
||||||
|
*/
|
||||||
private Document getDocument(String xml)
|
private Document getDocument(String xml)
|
||||||
throws ParserConfigurationException, SAXException, IOException {
|
throws ParserConfigurationException, SAXException, IOException {
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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 java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of sdk-repository sources.
|
||||||
|
*/
|
||||||
|
public class RepoSources {
|
||||||
|
|
||||||
|
private ArrayList<RepoSource> mSources = new ArrayList<RepoSource>();
|
||||||
|
private ITaskFactory mTaskFactory;
|
||||||
|
|
||||||
|
public RepoSources() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTaskFactory(ITaskFactory taskFactory) {
|
||||||
|
mTaskFactory = taskFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITaskFactory getTaskFactory() {
|
||||||
|
return mTaskFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(RepoSource source) {
|
||||||
|
mSources.add(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<RepoSource> getSources() {
|
||||||
|
return mSources;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,8 +16,14 @@
|
|||||||
|
|
||||||
package com.android.sdklib.internal.repository;
|
package com.android.sdklib.internal.repository;
|
||||||
|
|
||||||
|
import com.android.sdklib.SdkConstants;
|
||||||
|
import com.android.sdklib.internal.repository.Archive.Arch;
|
||||||
|
import com.android.sdklib.internal.repository.Archive.Os;
|
||||||
|
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a tool XML node in an SDK repository.
|
* Represents a tool XML node in an SDK repository.
|
||||||
*/
|
*/
|
||||||
@@ -28,8 +34,32 @@ public class ToolPackage extends Package {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* This constructor should throw an exception if the package cannot be created.
|
* This constructor should throw an exception if the package cannot be created.
|
||||||
*/
|
*/
|
||||||
ToolPackage(Node packageNode) {
|
ToolPackage(RepoSource source, Node packageNode) {
|
||||||
super(packageNode);
|
super(source, packageNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually create a new package with one archive and the given attributes.
|
||||||
|
* This is used to create packages from local directories.
|
||||||
|
*/
|
||||||
|
ToolPackage(RepoSource source,
|
||||||
|
int revision,
|
||||||
|
String description,
|
||||||
|
String descUrl,
|
||||||
|
Os archiveOs,
|
||||||
|
Arch archiveArch,
|
||||||
|
String archiveUrl,
|
||||||
|
long archiveSize,
|
||||||
|
String archiveChecksum) {
|
||||||
|
super(source,
|
||||||
|
revision,
|
||||||
|
description,
|
||||||
|
descUrl,
|
||||||
|
archiveOs,
|
||||||
|
archiveArch,
|
||||||
|
archiveUrl,
|
||||||
|
archiveSize,
|
||||||
|
archiveChecksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a short description for an {@link IDescription}. */
|
/** Returns a short description for an {@link IDescription}. */
|
||||||
@@ -45,4 +75,18 @@ public class ToolPackage extends Package {
|
|||||||
getRevision(),
|
getRevision(),
|
||||||
super.getLongDescription());
|
super.getLongDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a potential installation folder if an archive of this package were
|
||||||
|
* to be installed right away in the given SDK root.
|
||||||
|
* <p/>
|
||||||
|
* A "tool" package should always be located in SDK/tools.
|
||||||
|
*
|
||||||
|
* @param osSdkRoot The OS path of the SDK root folder.
|
||||||
|
* @return A new {@link File} corresponding to the directory to use to install this package.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public File getInstallFolder(String osSdkRoot) {
|
||||||
|
return new File(osSdkRoot, SdkConstants.FD_TOOLS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.sdklib.repository;
|
package com.android.sdklib.repository;
|
||||||
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,6 +24,10 @@ import java.io.InputStream;
|
|||||||
*/
|
*/
|
||||||
public class SdkRepository {
|
public class SdkRepository {
|
||||||
|
|
||||||
|
/** The URL of the official Google sdk-repository site. */
|
||||||
|
public static final String URL_GOOGLE_SDK_REPO_SITE =
|
||||||
|
"https://dl.google.com/android/eclipse/repository/index.xml"; //$NON-NLS-1$
|
||||||
|
|
||||||
/** The XML namespace of the sdk-repository XML. */
|
/** The XML namespace of the sdk-repository XML. */
|
||||||
public static final String NS_SDK_REPOSITORY =
|
public static final String NS_SDK_REPOSITORY =
|
||||||
"http://schemas.android.com/sdk/android/repository/1"; //$NON-NLS-1$
|
"http://schemas.android.com/sdk/android/repository/1"; //$NON-NLS-1$
|
||||||
|
|||||||
@@ -21,8 +21,11 @@ import com.android.sdklib.internal.repository.ITaskMonitor;
|
|||||||
|
|
||||||
import org.eclipse.jface.viewers.TableViewer;
|
import org.eclipse.jface.viewers.TableViewer;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.events.ControlAdapter;
|
||||||
|
import org.eclipse.swt.events.ControlEvent;
|
||||||
import org.eclipse.swt.events.SelectionAdapter;
|
import org.eclipse.swt.events.SelectionAdapter;
|
||||||
import org.eclipse.swt.events.SelectionEvent;
|
import org.eclipse.swt.events.SelectionEvent;
|
||||||
|
import org.eclipse.swt.graphics.Rectangle;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.Button;
|
import org.eclipse.swt.widgets.Button;
|
||||||
@@ -44,25 +47,22 @@ import org.eclipse.swt.widgets.Text;
|
|||||||
* - refresh callback
|
* - refresh callback
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class InstalledPackagesPage extends Composite {
|
public class LocalPackagesPage extends Composite {
|
||||||
private UpdaterData mUpdaterData;
|
private UpdaterData mUpdaterData;
|
||||||
|
|
||||||
private Label mSdkLocLabel;
|
private Label mSdkLocLabel;
|
||||||
private Text mSdkLocText;
|
private Text mSdkLocText;
|
||||||
private Button mSdkLocBrowse;
|
private Button mSdkLocBrowse;
|
||||||
private Label mInstalledPkgLabel;
|
private TableViewer mTableViewerPackages;
|
||||||
private TableViewer mTableViewerInstPkg;
|
private Table mTablePackages;
|
||||||
private Table mTableInstPkg;
|
private TableColumn mColumnPackages;
|
||||||
private TableColumn mColumnInstSummary;
|
|
||||||
private TableColumn mColumnInstApiLevel;
|
|
||||||
private TableColumn mColumnInstRevision;
|
|
||||||
private Group mDescriptionContainer;
|
private Group mDescriptionContainer;
|
||||||
private Composite mInstButtons;
|
private Composite mContainerButtons;
|
||||||
private Button mInstUpdate;
|
private Button mUpdateButton;
|
||||||
private Label mPlaceholder1;
|
private Label mPlaceholder1;
|
||||||
private Button mInstDelete;
|
private Button mDeleteButton;
|
||||||
private Label mPlaceholder2;
|
private Label mPlaceholder2;
|
||||||
private Button mInstHomePage;
|
private Button mHomePageButton;
|
||||||
private Label mDescriptionLabel;
|
private Label mDescriptionLabel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,12 +71,13 @@ public class InstalledPackagesPage extends Composite {
|
|||||||
* @param updaterData An instance of {@link UpdaterData}. If null, a local
|
* @param updaterData An instance of {@link UpdaterData}. If null, a local
|
||||||
* one will be allocated just to help with the SWT Designer.
|
* one will be allocated just to help with the SWT Designer.
|
||||||
*/
|
*/
|
||||||
public InstalledPackagesPage(Composite parent, UpdaterData updaterData) {
|
public LocalPackagesPage(Composite parent, UpdaterData updaterData) {
|
||||||
super(parent, SWT.BORDER);
|
super(parent, SWT.BORDER);
|
||||||
|
|
||||||
mUpdaterData = updaterData != null ? updaterData : new UpdaterData();
|
mUpdaterData = updaterData != null ? updaterData : new UpdaterData();
|
||||||
|
|
||||||
createContents(this);
|
createContents(this);
|
||||||
|
postCreate(); //$hide$
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createContents(Composite parent) {
|
private void createContents(Composite parent) {
|
||||||
@@ -84,26 +85,14 @@ public class InstalledPackagesPage extends Composite {
|
|||||||
|
|
||||||
createSdkLocation(parent);
|
createSdkLocation(parent);
|
||||||
|
|
||||||
mInstalledPkgLabel = new Label(parent, SWT.NONE);
|
mTableViewerPackages = new TableViewer(parent, SWT.BORDER | SWT.FULL_SELECTION);
|
||||||
mInstalledPkgLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
|
mTablePackages = mTableViewerPackages.getTable();
|
||||||
mInstalledPkgLabel.setText("Installed Packages:");
|
mTablePackages.setHeaderVisible(true);
|
||||||
|
mTablePackages.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
|
||||||
|
|
||||||
mTableViewerInstPkg = new TableViewer(parent, SWT.BORDER | SWT.FULL_SELECTION);
|
mColumnPackages = new TableColumn(mTablePackages, SWT.NONE);
|
||||||
mTableInstPkg = mTableViewerInstPkg.getTable();
|
mColumnPackages.setWidth(377);
|
||||||
mTableInstPkg.setHeaderVisible(true);
|
mColumnPackages.setText("Installed Packages");
|
||||||
mTableInstPkg.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
|
|
||||||
|
|
||||||
mColumnInstSummary = new TableColumn(mTableInstPkg, SWT.NONE);
|
|
||||||
mColumnInstSummary.setWidth(377);
|
|
||||||
mColumnInstSummary.setText("Summary");
|
|
||||||
|
|
||||||
mColumnInstApiLevel = new TableColumn(mTableInstPkg, SWT.NONE);
|
|
||||||
mColumnInstApiLevel.setWidth(100);
|
|
||||||
mColumnInstApiLevel.setText("API Level");
|
|
||||||
|
|
||||||
mColumnInstRevision = new TableColumn(mTableInstPkg, SWT.NONE);
|
|
||||||
mColumnInstRevision.setWidth(100);
|
|
||||||
mColumnInstRevision.setText("Revision");
|
|
||||||
|
|
||||||
mDescriptionContainer = new Group(parent, SWT.NONE);
|
mDescriptionContainer = new Group(parent, SWT.NONE);
|
||||||
mDescriptionContainer.setLayout(new GridLayout(1, false));
|
mDescriptionContainer.setLayout(new GridLayout(1, false));
|
||||||
@@ -114,32 +103,32 @@ public class InstalledPackagesPage extends Composite {
|
|||||||
mDescriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true, 1, 1));
|
mDescriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true, 1, 1));
|
||||||
mDescriptionLabel.setText("Line1\nLine2\nLine3");
|
mDescriptionLabel.setText("Line1\nLine2\nLine3");
|
||||||
|
|
||||||
mInstButtons = new Composite(parent, SWT.NONE);
|
mContainerButtons = new Composite(parent, SWT.NONE);
|
||||||
mInstButtons.setLayout(new GridLayout(5, false));
|
mContainerButtons.setLayout(new GridLayout(5, false));
|
||||||
mInstButtons.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
|
mContainerButtons.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
|
||||||
|
|
||||||
mInstUpdate = new Button(mInstButtons, SWT.NONE);
|
mUpdateButton = new Button(mContainerButtons, SWT.NONE);
|
||||||
mInstUpdate.addSelectionListener(new SelectionAdapter() {
|
mUpdateButton.addSelectionListener(new SelectionAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void widgetSelected(SelectionEvent e) {
|
public void widgetSelected(SelectionEvent e) {
|
||||||
onUpdateInstalledPackage(); //$hide$ (hide from SWT designer)
|
onUpdateInstalledPackage(); //$hide$ (hide from SWT designer)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mInstUpdate.setText("Update...");
|
mUpdateButton.setText("Update...");
|
||||||
|
|
||||||
mPlaceholder1 = new Label(mInstButtons, SWT.NONE);
|
mPlaceholder1 = new Label(mContainerButtons, SWT.NONE);
|
||||||
mPlaceholder1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
|
mPlaceholder1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
|
||||||
|
|
||||||
mInstDelete = new Button(mInstButtons, SWT.NONE);
|
mDeleteButton = new Button(mContainerButtons, SWT.NONE);
|
||||||
mInstDelete.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
|
mDeleteButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
|
||||||
mInstDelete.setText("Delete...");
|
mDeleteButton.setText("Delete...");
|
||||||
|
|
||||||
mPlaceholder2 = new Label(mInstButtons, SWT.NONE);
|
mPlaceholder2 = new Label(mContainerButtons, SWT.NONE);
|
||||||
mPlaceholder2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
|
mPlaceholder2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
|
||||||
|
|
||||||
mInstHomePage = new Button(mInstButtons, SWT.NONE);
|
mHomePageButton = new Button(mContainerButtons, SWT.NONE);
|
||||||
mInstHomePage.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
|
mHomePageButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
|
||||||
mInstHomePage.setText("Home Page...");
|
mHomePageButton.setText("Home Page...");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createSdkLocation(Composite parent) {
|
private void createSdkLocation(Composite parent) {
|
||||||
@@ -175,7 +164,36 @@ public class InstalledPackagesPage extends Composite {
|
|||||||
// Hide everything down-below from SWT designer
|
// Hide everything down-below from SWT designer
|
||||||
//$hide>>$
|
//$hide>>$
|
||||||
|
|
||||||
|
private void postCreate() {
|
||||||
|
adjustColumnsWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener to adjust the columns width when the parent is resized.
|
||||||
|
* <p/>
|
||||||
|
* If we need something more fancy, we might want to use this:
|
||||||
|
* http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet77.java?view=co
|
||||||
|
*/
|
||||||
|
private void adjustColumnsWidth() {
|
||||||
|
// Add a listener to resize the column to the full width of the table
|
||||||
|
mTablePackages.addControlListener(new ControlAdapter() {
|
||||||
|
@Override
|
||||||
|
public void controlResized(ControlEvent e) {
|
||||||
|
Rectangle r = mTablePackages.getClientArea();
|
||||||
|
mColumnPackages.setWidth(r.width);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInput(LocalSdkAdapter localSdkAdapter) {
|
||||||
|
mTableViewerPackages.setLabelProvider( localSdkAdapter.getLabelProvider());
|
||||||
|
mTableViewerPackages.setContentProvider(localSdkAdapter.getContentProvider());
|
||||||
|
mTableViewerPackages.setInput(localSdkAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
protected void onUpdateInstalledPackage() {
|
protected void onUpdateInstalledPackage() {
|
||||||
|
// TODO just a test, needs to be removed later.
|
||||||
ProgressTask.start(getShell(), "Test", new ITask() {
|
ProgressTask.start(getShell(), "Test", new ITask() {
|
||||||
public void run(ITaskMonitor monitor) {
|
public void run(ITaskMonitor monitor) {
|
||||||
monitor.setDescription("Test");
|
monitor.setDescription("Test");
|
||||||
@@ -189,6 +207,7 @@ public class InstalledPackagesPage extends Composite {
|
|||||||
try {
|
try {
|
||||||
Thread.sleep(5);
|
Thread.sleep(5);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* 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.sdkuilib.internal.repository;
|
||||||
|
|
||||||
|
import com.android.sdklib.internal.repository.IDescription;
|
||||||
|
import com.android.sdklib.internal.repository.LocalSdkParser;
|
||||||
|
import com.android.sdklib.internal.repository.Package;
|
||||||
|
import com.android.sdklib.internal.repository.RepoSource;
|
||||||
|
|
||||||
|
import org.eclipse.jface.viewers.IContentProvider;
|
||||||
|
import org.eclipse.jface.viewers.ILabelProvider;
|
||||||
|
import org.eclipse.jface.viewers.IStructuredContentProvider;
|
||||||
|
import org.eclipse.jface.viewers.LabelProvider;
|
||||||
|
import org.eclipse.jface.viewers.Viewer;
|
||||||
|
import org.eclipse.swt.graphics.Image;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table adapters to use the local SDK list.
|
||||||
|
*/
|
||||||
|
class LocalSdkAdapter {
|
||||||
|
|
||||||
|
private final LocalSdkParser mLocalSdkParser;
|
||||||
|
private String mOsSdkRoot;
|
||||||
|
|
||||||
|
public LocalSdkAdapter(LocalSdkParser localSdkParser) {
|
||||||
|
mLocalSdkParser = localSdkParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSdkRoot(String osSdkRoot) {
|
||||||
|
mOsSdkRoot = osSdkRoot;
|
||||||
|
mLocalSdkParser.clearPackages();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ILabelProvider getLabelProvider() {
|
||||||
|
return new ViewerLabelProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public IContentProvider getContentProvider() {
|
||||||
|
return new TableContentProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------
|
||||||
|
|
||||||
|
public static class ViewerLabelProvider extends LabelProvider {
|
||||||
|
/** Returns null by default */
|
||||||
|
@Override
|
||||||
|
public Image getImage(Object element) {
|
||||||
|
return super.getImage(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the toString of the element. */
|
||||||
|
@Override
|
||||||
|
public String getText(Object element) {
|
||||||
|
if (element instanceof IDescription) {
|
||||||
|
return ((IDescription) element).getShortDescription();
|
||||||
|
}
|
||||||
|
return super.getText(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------
|
||||||
|
|
||||||
|
private static class TableContentProvider implements IStructuredContentProvider {
|
||||||
|
|
||||||
|
// Called when the viewer is disposed
|
||||||
|
public void dispose() {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the input is set or changed on the provider
|
||||||
|
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to collect the root elements for the given input.
|
||||||
|
* The input here is a {@link LocalSdkAdapter} object, this returns an array
|
||||||
|
* of {@link RepoSource}.
|
||||||
|
*/
|
||||||
|
public Object[] getElements(Object inputElement) {
|
||||||
|
if (inputElement instanceof LocalSdkAdapter) {
|
||||||
|
LocalSdkAdapter adapter = (LocalSdkAdapter) inputElement;
|
||||||
|
LocalSdkParser parser = adapter.mLocalSdkParser;
|
||||||
|
|
||||||
|
Package[] packages = parser.getPackages();
|
||||||
|
|
||||||
|
if (packages == null) {
|
||||||
|
// load on demand the first time
|
||||||
|
packages = parser.parseSdk(adapter.mOsSdkRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packages != null) {
|
||||||
|
return packages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Object[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -152,11 +152,11 @@ class ProgressTask extends Dialog
|
|||||||
* Sets the description in the current task dialog.
|
* Sets the description in the current task dialog.
|
||||||
* This method can be invoke from a non-UI thread.
|
* This method can be invoke from a non-UI thread.
|
||||||
*/
|
*/
|
||||||
public void setDescription(final String description) {
|
public void setDescription(final String descriptionFormat, final Object...args) {
|
||||||
mDialogShell.getDisplay().asyncExec(new Runnable() {
|
mDialogShell.getDisplay().asyncExec(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!mLabel.isDisposed()) {
|
if (!mLabel.isDisposed()) {
|
||||||
mLabel.setText(description);
|
mLabel.setText(String.format(descriptionFormat, args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -166,14 +166,14 @@ class ProgressTask extends Dialog
|
|||||||
* Sets the description in the current task dialog.
|
* Sets the description in the current task dialog.
|
||||||
* This method can be invoke from a non-UI thread.
|
* This method can be invoke from a non-UI thread.
|
||||||
*/
|
*/
|
||||||
public void setResult(final String result) {
|
public void setResult(final String resultFormat, final Object...args) {
|
||||||
mAutomaticallyCloseOnTaskCompletion = false;
|
mAutomaticallyCloseOnTaskCompletion = false;
|
||||||
if (!mDialogShell.isDisposed()) {
|
if (!mDialogShell.isDisposed()) {
|
||||||
mDialogShell.getDisplay().asyncExec(new Runnable() {
|
mDialogShell.getDisplay().asyncExec(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!mResultText.isDisposed()) {
|
if (!mResultText.isDisposed()) {
|
||||||
mResultText.setVisible(true);
|
mResultText.setVisible(true);
|
||||||
mResultText.setText(result);
|
mResultText.setText(String.format(resultFormat, args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,9 +17,14 @@
|
|||||||
package com.android.sdkuilib.internal.repository;
|
package com.android.sdkuilib.internal.repository;
|
||||||
|
|
||||||
|
|
||||||
|
import com.android.sdklib.internal.repository.Archive;
|
||||||
import com.android.sdklib.internal.repository.IDescription;
|
import com.android.sdklib.internal.repository.IDescription;
|
||||||
|
|
||||||
|
import org.eclipse.jface.viewers.CheckStateChangedEvent;
|
||||||
import org.eclipse.jface.viewers.CheckboxTreeViewer;
|
import org.eclipse.jface.viewers.CheckboxTreeViewer;
|
||||||
|
import org.eclipse.jface.viewers.DoubleClickEvent;
|
||||||
|
import org.eclipse.jface.viewers.ICheckStateListener;
|
||||||
|
import org.eclipse.jface.viewers.IDoubleClickListener;
|
||||||
import org.eclipse.jface.viewers.ISelection;
|
import org.eclipse.jface.viewers.ISelection;
|
||||||
import org.eclipse.jface.viewers.ITreeSelection;
|
import org.eclipse.jface.viewers.ITreeSelection;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
@@ -36,10 +41,8 @@ import org.eclipse.swt.widgets.Group;
|
|||||||
import org.eclipse.swt.widgets.Label;
|
import org.eclipse.swt.widgets.Label;
|
||||||
import org.eclipse.swt.widgets.Tree;
|
import org.eclipse.swt.widgets.Tree;
|
||||||
import org.eclipse.swt.widgets.TreeColumn;
|
import org.eclipse.swt.widgets.TreeColumn;
|
||||||
import org.eclipse.jface.viewers.ICheckStateListener;
|
|
||||||
import org.eclipse.jface.viewers.CheckStateChangedEvent;
|
import java.util.ArrayList;
|
||||||
import org.eclipse.jface.viewers.IDoubleClickListener;
|
|
||||||
import org.eclipse.jface.viewers.DoubleClickEvent;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO list
|
* TODO list
|
||||||
@@ -54,8 +57,9 @@ import org.eclipse.jface.viewers.DoubleClickEvent;
|
|||||||
* - install selected callback
|
* - install selected callback
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class AvailablePackagesPage extends Composite {
|
public class RemotePackagesPage extends Composite {
|
||||||
|
|
||||||
|
private final UpdaterWindowImpl mUpdaterWindow;
|
||||||
private final UpdaterData mUpdaterData;
|
private final UpdaterData mUpdaterData;
|
||||||
|
|
||||||
private CheckboxTreeViewer mTreeViewerSources;
|
private CheckboxTreeViewer mTreeViewerSources;
|
||||||
@@ -70,14 +74,18 @@ public class AvailablePackagesPage extends Composite {
|
|||||||
private Label mDescriptionLabel;
|
private Label mDescriptionLabel;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the composite.
|
* Create the composite.
|
||||||
* @param parent The parent of the composite.
|
* @param parent The parent of the composite.
|
||||||
* @param updaterData An instance of {@link UpdaterData}. If null, a local
|
* @param updaterData An instance of {@link UpdaterData}. If null, a local
|
||||||
* one will be allocated just to help with the SWT Designer.
|
* one will be allocated just to help with the SWT Designer.
|
||||||
*/
|
*/
|
||||||
public AvailablePackagesPage(Composite parent, UpdaterData updaterData) {
|
public RemotePackagesPage(UpdaterWindowImpl updaterWindow,
|
||||||
|
Composite parent,
|
||||||
|
UpdaterData updaterData) {
|
||||||
super(parent, SWT.BORDER);
|
super(parent, SWT.BORDER);
|
||||||
|
mUpdaterWindow = updaterWindow;
|
||||||
|
|
||||||
mUpdaterData = updaterData != null ? updaterData : new UpdaterData();
|
mUpdaterData = updaterData != null ? updaterData : new UpdaterData();
|
||||||
|
|
||||||
@@ -91,16 +99,14 @@ public class AvailablePackagesPage extends Composite {
|
|||||||
mTreeViewerSources = new CheckboxTreeViewer(parent, SWT.BORDER);
|
mTreeViewerSources = new CheckboxTreeViewer(parent, SWT.BORDER);
|
||||||
mTreeViewerSources.addDoubleClickListener(new IDoubleClickListener() {
|
mTreeViewerSources.addDoubleClickListener(new IDoubleClickListener() {
|
||||||
public void doubleClick(DoubleClickEvent event) {
|
public void doubleClick(DoubleClickEvent event) {
|
||||||
doTreeDoubleClick(event); //$hide$
|
onTreeDoubleClick(event); //$hide$
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mTreeViewerSources.addCheckStateListener(new ICheckStateListener() {
|
mTreeViewerSources.addCheckStateListener(new ICheckStateListener() {
|
||||||
public void checkStateChanged(CheckStateChangedEvent event) {
|
public void checkStateChanged(CheckStateChangedEvent event) {
|
||||||
doTreeCeckStateChanged(event); //$hide$
|
onTreeCheckStateChanged(event); //$hide$
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mTreeViewerSources.setContentProvider(mUpdaterData.getSources().getContentProvider());
|
|
||||||
mTreeViewerSources.setLabelProvider(mUpdaterData.getSources().getLabelProvider());
|
|
||||||
mTreeSources = mTreeViewerSources.getTree();
|
mTreeSources = mTreeViewerSources.getTree();
|
||||||
mTreeSources.addSelectionListener(new SelectionAdapter() {
|
mTreeSources.addSelectionListener(new SelectionAdapter() {
|
||||||
@Override
|
@Override
|
||||||
@@ -137,6 +143,12 @@ public class AvailablePackagesPage extends Composite {
|
|||||||
mRefreshButton.setText("Refresh");
|
mRefreshButton.setText("Refresh");
|
||||||
|
|
||||||
mInstallSelectedButton = new Button(parent, SWT.NONE);
|
mInstallSelectedButton = new Button(parent, SWT.NONE);
|
||||||
|
mInstallSelectedButton.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
onInstallSelectedArchives(); //$hide$
|
||||||
|
}
|
||||||
|
});
|
||||||
mInstallSelectedButton.setText("Install Selected");
|
mInstallSelectedButton.setText("Install Selected");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +183,9 @@ public class AvailablePackagesPage extends Composite {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInput(RepoSources sources) {
|
public void setInput(RepoSourcesAdapter sources) {
|
||||||
|
mTreeViewerSources.setContentProvider(sources.getContentProvider());
|
||||||
|
mTreeViewerSources.setLabelProvider( sources.getLabelProvider());
|
||||||
mTreeViewerSources.setInput(sources);
|
mTreeViewerSources.setInput(sources);
|
||||||
onTreeSelected();
|
onTreeSelected();
|
||||||
}
|
}
|
||||||
@@ -189,13 +203,27 @@ public class AvailablePackagesPage extends Composite {
|
|||||||
mDescriptionLabel.setText(""); //$NON-NLS1-$
|
mDescriptionLabel.setText(""); //$NON-NLS1-$
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doTreeCeckStateChanged(CheckStateChangedEvent event) {
|
private void onTreeCheckStateChanged(CheckStateChangedEvent event) {
|
||||||
boolean b = event.getChecked();
|
boolean b = event.getChecked();
|
||||||
Object elem = event.getElement();
|
Object elem = event.getElement(); // Will be Archive or Package or RepoSource
|
||||||
Object src = event.getSource();
|
Object src = event.getSource();
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doTreeDoubleClick(DoubleClickEvent event) {
|
private void onTreeDoubleClick(DoubleClickEvent event) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onInstallSelectedArchives() {
|
||||||
|
|
||||||
|
ArrayList<Archive> archives = new ArrayList<Archive>();
|
||||||
|
for (Object element : mTreeViewerSources.getCheckedElements()) {
|
||||||
|
if (element instanceof Archive) {
|
||||||
|
archives.add((Archive) element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mUpdaterWindow.installArchives(archives);
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of hiding from SWT Designer
|
// End of hiding from SWT Designer
|
||||||
@@ -18,9 +18,9 @@ package com.android.sdkuilib.internal.repository;
|
|||||||
|
|
||||||
import com.android.sdklib.internal.repository.Archive;
|
import com.android.sdklib.internal.repository.Archive;
|
||||||
import com.android.sdklib.internal.repository.IDescription;
|
import com.android.sdklib.internal.repository.IDescription;
|
||||||
import com.android.sdklib.internal.repository.ITaskFactory;
|
|
||||||
import com.android.sdklib.internal.repository.Package;
|
import com.android.sdklib.internal.repository.Package;
|
||||||
import com.android.sdklib.internal.repository.RepoSource;
|
import com.android.sdklib.internal.repository.RepoSource;
|
||||||
|
import com.android.sdklib.internal.repository.RepoSources;
|
||||||
|
|
||||||
import org.eclipse.jface.viewers.IContentProvider;
|
import org.eclipse.jface.viewers.IContentProvider;
|
||||||
import org.eclipse.jface.viewers.ILabelProvider;
|
import org.eclipse.jface.viewers.ILabelProvider;
|
||||||
@@ -29,27 +29,17 @@ import org.eclipse.jface.viewers.LabelProvider;
|
|||||||
import org.eclipse.jface.viewers.Viewer;
|
import org.eclipse.jface.viewers.Viewer;
|
||||||
import org.eclipse.swt.graphics.Image;
|
import org.eclipse.swt.graphics.Image;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of sdk-repository sources.
|
* A list of sdk-repository sources.
|
||||||
*
|
*
|
||||||
* This implementation is UI dependent.
|
* This implementation is UI dependent.
|
||||||
*/
|
*/
|
||||||
class RepoSources {
|
class RepoSourcesAdapter {
|
||||||
|
|
||||||
private ArrayList<RepoSource> mSources = new ArrayList<RepoSource>();
|
private final RepoSources mRepoSources;
|
||||||
private ITaskFactory mTaskFactory;
|
|
||||||
|
|
||||||
public RepoSources() {
|
public RepoSourcesAdapter(RepoSources repoSources) {
|
||||||
}
|
mRepoSources = repoSources;
|
||||||
|
|
||||||
public void setTaskFactory(ITaskFactory taskFactory) {
|
|
||||||
mTaskFactory = taskFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(RepoSource source) {
|
|
||||||
mSources.add(source);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ILabelProvider getLabelProvider() {
|
public ILabelProvider getLabelProvider() {
|
||||||
@@ -63,7 +53,7 @@ class RepoSources {
|
|||||||
|
|
||||||
// ------------
|
// ------------
|
||||||
|
|
||||||
public class ViewerLabelProvider extends LabelProvider {
|
public static class ViewerLabelProvider extends LabelProvider {
|
||||||
/** Returns null by default */
|
/** Returns null by default */
|
||||||
@Override
|
@Override
|
||||||
public Image getImage(Object element) {
|
public Image getImage(Object element) {
|
||||||
@@ -82,9 +72,9 @@ class RepoSources {
|
|||||||
|
|
||||||
// ------------
|
// ------------
|
||||||
|
|
||||||
private class TreeContentProvider implements ITreeContentProvider {
|
private static class TreeContentProvider implements ITreeContentProvider {
|
||||||
|
|
||||||
private Object mInput;
|
private RepoSourcesAdapter mInput;
|
||||||
|
|
||||||
// Called when the viewer is disposed
|
// Called when the viewer is disposed
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
@@ -93,13 +83,14 @@ class RepoSources {
|
|||||||
|
|
||||||
// Called when the input is set or changed on the provider
|
// Called when the input is set or changed on the provider
|
||||||
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||||
mInput = newInput;
|
assert newInput == null || newInput instanceof RepoSourcesAdapter;
|
||||||
|
mInput = (RepoSourcesAdapter) newInput;
|
||||||
// pass
|
// pass
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to collect the root elements for the given input.
|
* Called to collect the root elements for the given input.
|
||||||
* The input here is a {@link RepoSources} object, this returns an array
|
* The input here is a {@link RepoSourcesAdapter} object, this returns an array
|
||||||
* of {@link RepoSource}.
|
* of {@link RepoSource}.
|
||||||
*/
|
*/
|
||||||
public Object[] getElements(Object inputElement) {
|
public Object[] getElements(Object inputElement) {
|
||||||
@@ -110,20 +101,20 @@ class RepoSources {
|
|||||||
* Get the children of the given parent. This is requested on-demand as
|
* Get the children of the given parent. This is requested on-demand as
|
||||||
* nodes are expanded.
|
* nodes are expanded.
|
||||||
*
|
*
|
||||||
* For a {@link RepoSources} object, returns an array of {@link RepoSource}s.
|
* For a {@link RepoSourcesAdapter} object, returns an array of {@link RepoSource}s.
|
||||||
* For a {@link RepoSource}, returns an array of {@link Package}s.
|
* For a {@link RepoSource}, returns an array of {@link Package}s.
|
||||||
* For a {@link Package}, returns an array of {@link Archive}s.
|
* For a {@link Package}, returns an array of {@link Archive}s.
|
||||||
*/
|
*/
|
||||||
public Object[] getChildren(Object parentElement) {
|
public Object[] getChildren(Object parentElement) {
|
||||||
if (parentElement instanceof RepoSources) {
|
if (parentElement instanceof RepoSourcesAdapter) {
|
||||||
return ((RepoSources) parentElement).mSources.toArray();
|
return ((RepoSourcesAdapter) parentElement).mRepoSources.getSources().toArray();
|
||||||
|
|
||||||
} else if (parentElement instanceof RepoSource) {
|
} else if (parentElement instanceof RepoSource) {
|
||||||
RepoSource source = (RepoSource) parentElement;
|
RepoSource source = (RepoSource) parentElement;
|
||||||
Package[] packages = source.getPackages();
|
Package[] packages = source.getPackages();
|
||||||
|
|
||||||
if (packages == null) {
|
if (packages == null) {
|
||||||
source.load(mTaskFactory);
|
source.load(mInput.mRepoSources.getTaskFactory());
|
||||||
packages = source.getPackages();
|
packages = source.getPackages();
|
||||||
}
|
}
|
||||||
if (packages != null) {
|
if (packages != null) {
|
||||||
@@ -134,17 +125,20 @@ class RepoSources {
|
|||||||
return ((Package) parentElement).getArchives();
|
return ((Package) parentElement).getArchives();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return new Object[0];
|
return new Object[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the parent of a given element.
|
* Returns the parent of a given element.
|
||||||
* The input {@link RepoSources} is the parent of all {@link RepoSource} elements.
|
* The input {@link RepoSourcesAdapter} is the parent of all {@link RepoSource} elements.
|
||||||
*/
|
*/
|
||||||
public Object getParent(Object element) {
|
public Object getParent(Object element) {
|
||||||
|
|
||||||
if (element instanceof RepoSource) {
|
if (element instanceof RepoSource) {
|
||||||
return mInput;
|
return mInput;
|
||||||
|
|
||||||
|
} else if (element instanceof Package) {
|
||||||
|
return ((Package) element).getParentSource();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -152,7 +146,8 @@ class RepoSources {
|
|||||||
/**
|
/**
|
||||||
* Returns true if a given element has children, which is used to display a
|
* Returns true if a given element has children, which is used to display a
|
||||||
* "+/expand" box next to the tree node.
|
* "+/expand" box next to the tree node.
|
||||||
* All {@link RepoSource} are expandable, whether they actually have any childre or not.
|
* All {@link RepoSource} and {@link Package} are expandable, whether they actually
|
||||||
|
* have any children or not.
|
||||||
*/
|
*/
|
||||||
public boolean hasChildren(Object element) {
|
public boolean hasChildren(Object element) {
|
||||||
return element instanceof RepoSource || element instanceof Package;
|
return element instanceof RepoSource || element instanceof Package;
|
||||||
@@ -16,13 +16,21 @@
|
|||||||
|
|
||||||
package com.android.sdkuilib.internal.repository;
|
package com.android.sdkuilib.internal.repository;
|
||||||
|
|
||||||
|
import com.android.sdklib.internal.repository.LocalSdkParser;
|
||||||
|
import com.android.sdklib.internal.repository.RepoSources;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data shared between {@link UpdaterWindowImpl} and its pages.
|
* Data shared between {@link UpdaterWindowImpl} and its pages.
|
||||||
*/
|
*/
|
||||||
class UpdaterData {
|
class UpdaterData {
|
||||||
private String mOsSdkRoot;
|
private String mOsSdkRoot;
|
||||||
private boolean mUserCanChangeSdkRoot;
|
private boolean mUserCanChangeSdkRoot;
|
||||||
private RepoSources mSources = new RepoSources();
|
|
||||||
|
private final LocalSdkParser mLocalSdkParser = new LocalSdkParser();
|
||||||
|
private final RepoSources mSources = new RepoSources();
|
||||||
|
|
||||||
|
private final LocalSdkAdapter mLocalSdkAdapter = new LocalSdkAdapter(mLocalSdkParser);
|
||||||
|
private final RepoSourcesAdapter mSourcesAdapter = new RepoSourcesAdapter(mSources);
|
||||||
|
|
||||||
public void setOsSdkRoot(String osSdkRoot) {
|
public void setOsSdkRoot(String osSdkRoot) {
|
||||||
mOsSdkRoot = osSdkRoot;
|
mOsSdkRoot = osSdkRoot;
|
||||||
@@ -40,12 +48,20 @@ class UpdaterData {
|
|||||||
return mUserCanChangeSdkRoot;
|
return mUserCanChangeSdkRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSources(RepoSources sources) {
|
|
||||||
mSources = sources;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RepoSources getSources() {
|
public RepoSources getSources() {
|
||||||
return mSources;
|
return mSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RepoSourcesAdapter getSourcesAdapter() {
|
||||||
|
return mSourcesAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalSdkParser getLocalSdkParser() {
|
||||||
|
return mLocalSdkParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalSdkAdapter getLocalSdkAdapter() {
|
||||||
|
return mLocalSdkAdapter;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,12 @@
|
|||||||
package com.android.sdkuilib.internal.repository;
|
package com.android.sdkuilib.internal.repository;
|
||||||
|
|
||||||
|
|
||||||
|
import com.android.sdklib.internal.repository.Archive;
|
||||||
|
import com.android.sdklib.internal.repository.ITask;
|
||||||
|
import com.android.sdklib.internal.repository.ITaskMonitor;
|
||||||
|
import com.android.sdklib.internal.repository.Package;
|
||||||
import com.android.sdklib.internal.repository.RepoSource;
|
import com.android.sdklib.internal.repository.RepoSource;
|
||||||
|
import com.android.sdklib.repository.SdkRepository;
|
||||||
|
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.SWTException;
|
import org.eclipse.swt.SWTException;
|
||||||
@@ -36,14 +41,22 @@ import org.eclipse.swt.widgets.Display;
|
|||||||
import org.eclipse.swt.widgets.List;
|
import org.eclipse.swt.widgets.List;
|
||||||
import org.eclipse.swt.widgets.Shell;
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.MessageDigest;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the private implementation of the UpdateWindow.
|
* This is the private implementation of the UpdateWindow.
|
||||||
*/
|
*/
|
||||||
public class UpdaterWindowImpl {
|
public class UpdaterWindowImpl {
|
||||||
|
|
||||||
|
private static final int NUM_FETCH_URL_MONITOR_INC = 10;
|
||||||
|
|
||||||
private final UpdaterData mUpdaterData = new UpdaterData();
|
private final UpdaterData mUpdaterData = new UpdaterData();
|
||||||
private ArrayList<Composite> mPages = new ArrayList<Composite>();
|
private ArrayList<Composite> mPages = new ArrayList<Composite>();
|
||||||
private boolean mInternalPageChange;
|
private boolean mInternalPageChange;
|
||||||
@@ -54,10 +67,11 @@ public class UpdaterWindowImpl {
|
|||||||
private SashForm mSashForm;
|
private SashForm mSashForm;
|
||||||
private List mPageList;
|
private List mPageList;
|
||||||
private Composite mPagesRootComposite;
|
private Composite mPagesRootComposite;
|
||||||
private InstalledPackagesPage mInstalledPackagePage;
|
private LocalPackagesPage mLocalPackagePage;
|
||||||
private AvailablePackagesPage mAvailablePackagesPage;
|
private RemotePackagesPage mRemotePackagesPage;
|
||||||
private StackLayout mStackLayout;
|
private StackLayout mStackLayout;
|
||||||
private Image mIconImage;
|
private Image mIconImage;
|
||||||
|
private ProgressTaskFactory mTaskFactory;
|
||||||
|
|
||||||
public UpdaterWindowImpl(String osSdkRoot, boolean userCanChangeSdkRoot) {
|
public UpdaterWindowImpl(String osSdkRoot, boolean userCanChangeSdkRoot) {
|
||||||
mUpdaterData.setOsSdkRoot(osSdkRoot);
|
mUpdaterData.setOsSdkRoot(osSdkRoot);
|
||||||
@@ -114,8 +128,8 @@ public class UpdaterWindowImpl {
|
|||||||
mStackLayout = new StackLayout();
|
mStackLayout = new StackLayout();
|
||||||
mPagesRootComposite.setLayout(mStackLayout);
|
mPagesRootComposite.setLayout(mStackLayout);
|
||||||
|
|
||||||
mInstalledPackagePage = new InstalledPackagesPage(mPagesRootComposite, mUpdaterData);
|
mLocalPackagePage = new LocalPackagesPage(mPagesRootComposite, mUpdaterData);
|
||||||
mAvailablePackagesPage = new AvailablePackagesPage(mPagesRootComposite, mUpdaterData);
|
mRemotePackagesPage = new RemotePackagesPage(this, mPagesRootComposite, mUpdaterData);
|
||||||
mSashForm.setWeights(new int[] {150, 576});
|
mSashForm.setWeights(new int[] {150, 576});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,8 +172,10 @@ public class UpdaterWindowImpl {
|
|||||||
* Once the UI has been created, initialize the content
|
* Once the UI has been created, initialize the content
|
||||||
*/
|
*/
|
||||||
private void firstInit() {
|
private void firstInit() {
|
||||||
addPage(mInstalledPackagePage, "Installed Packages");
|
mTaskFactory = new ProgressTaskFactory(getShell());
|
||||||
addPage(mAvailablePackagesPage, "Available Packages");
|
|
||||||
|
addPage(mLocalPackagePage, "Installed Packages");
|
||||||
|
addPage(mRemotePackagesPage, "Available Packages");
|
||||||
displayPage(0);
|
displayPage(0);
|
||||||
mPageList.setSelection(0);
|
mPageList.setSelection(0);
|
||||||
|
|
||||||
@@ -199,23 +215,214 @@ public class UpdaterWindowImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupSources() {
|
private void setupSources() {
|
||||||
mUpdaterData.getSources().setTaskFactory(new ProgressTaskFactory(getShell()));
|
mUpdaterData.getSources().setTaskFactory(mTaskFactory);
|
||||||
|
|
||||||
mUpdaterData.getSources().add(new RepoSource(
|
mUpdaterData.getSources().add(
|
||||||
"https://dl.google.com/android/eclipse/repository/index.xml", //$NON-NLS-1$
|
new RepoSource(SdkRepository.URL_GOOGLE_SDK_REPO_SITE, false /* addonOnly */));
|
||||||
false /* addonOnly */));
|
|
||||||
|
|
||||||
String url = System.getenv("TEMP_SDK_URL"); // TODO STOPSHIP temporary remove before shipping
|
String url = System.getenv("TEMP_SDK_URL"); // TODO STOPSHIP temporary remove before shipping
|
||||||
if (url != null) {
|
if (url != null) {
|
||||||
mUpdaterData.getSources().add(new RepoSource(url, false /* addonOnly */));
|
mUpdaterData.getSources().add(new RepoSource(url, false /* addonOnly */));
|
||||||
}
|
}
|
||||||
|
|
||||||
mAvailablePackagesPage.setInput(mUpdaterData.getSources());
|
mRemotePackagesPage.setInput(mUpdaterData.getSourcesAdapter());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scanLocalSdkFolders() {
|
private void scanLocalSdkFolders() {
|
||||||
// TODO Auto-generated method stub
|
mUpdaterData.getLocalSdkAdapter().setSdkRoot(mUpdaterData.getOsSdkRoot());
|
||||||
|
|
||||||
|
mLocalPackagePage.setInput(mUpdaterData.getLocalSdkAdapter());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void installArchives(final Collection<Archive> archives) {
|
||||||
|
// TODO move most parts to SdkLib, maybe as part of Archive, making archives self-installing.
|
||||||
|
mTaskFactory.start("Installing Archives", new ITask() {
|
||||||
|
public void run(ITaskMonitor monitor) {
|
||||||
|
|
||||||
|
monitor.setProgressMax(archives.size() * (NUM_FETCH_URL_MONITOR_INC + 3));
|
||||||
|
monitor.setDescription("Preparing to install archives");
|
||||||
|
|
||||||
|
int num_installed = 0;
|
||||||
|
for (Archive archive : archives) {
|
||||||
|
|
||||||
|
if (!archive.isCompatible()) {
|
||||||
|
monitor.setResult("Skipping incompatible archive: %1$s",
|
||||||
|
archive.getShortDescription());
|
||||||
|
monitor.incProgress(3);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
File archiveFile = null;
|
||||||
|
try {
|
||||||
|
archiveFile = downloadArchive(archive, monitor);
|
||||||
|
monitor.incProgress(1);
|
||||||
|
if (archiveFile != null) {
|
||||||
|
if (installArchive(archive, archiveFile, monitor)) {
|
||||||
|
num_installed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
monitor.incProgress(1);
|
||||||
|
} finally {
|
||||||
|
if (archiveFile != null) {
|
||||||
|
if (!archiveFile.delete()) {
|
||||||
|
archiveFile.deleteOnExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_installed == 0) {
|
||||||
|
monitor.setResult("Nothing was installed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads an archive and returns the temp file with it.
|
||||||
|
* Caller is responsible with deleting the temp file when done.
|
||||||
|
*/
|
||||||
|
private File downloadArchive(Archive archive, ITaskMonitor monitor) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
File tmpFile = File.createTempFile("sdkupload", "bin"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
monitor.setDescription("Downloading %1$s", archive.getShortDescription());
|
||||||
|
|
||||||
|
String link = archive.getUrl();
|
||||||
|
if (!link.startsWith("http://") //$NON-NLS-1$
|
||||||
|
&& !link.startsWith("https://") //$NON-NLS-1$
|
||||||
|
&& !link.startsWith("ftp://")) { //$NON-NLS-1$
|
||||||
|
// Make the URL absolute by prepending the source
|
||||||
|
Package pkg = archive.getParentPackage();
|
||||||
|
RepoSource src = pkg.getParentSource();
|
||||||
|
if (src == null) {
|
||||||
|
monitor.setResult("Internal error: no source for archive %1$s",
|
||||||
|
archive.getShortDescription());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String base = src.getUrl();
|
||||||
|
if (!base.endsWith("/") && !link.startsWith("/")) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
base += "/"; //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
link = base + link;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchUrl(tmpFile, archive, link, monitor);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
monitor.setResult(e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actually performs the download.
|
||||||
|
* Also computes the SHA1 of the file on the fly.
|
||||||
|
* <p/>
|
||||||
|
* Success is defined as downloading as many bytes as was expected and having the same
|
||||||
|
* SHA1 as expected. Returns true on success or false if any of those checks fail.
|
||||||
|
* <p/>
|
||||||
|
* Increments the monitor by {@link #NUM_FETCH_URL_MONITOR_INC} (which is 10).
|
||||||
|
*/
|
||||||
|
private boolean fetchUrl(File tmpFile, Archive archive, String urlString, ITaskMonitor monitor) {
|
||||||
|
URL url;
|
||||||
|
|
||||||
|
FileOutputStream os = null;
|
||||||
|
InputStream is = null;
|
||||||
|
try {
|
||||||
|
url = new URL(urlString);
|
||||||
|
is = url.openStream();
|
||||||
|
os = new FileOutputStream(tmpFile);
|
||||||
|
|
||||||
|
MessageDigest digester = archive.getChecksumType().getMessageDigest();
|
||||||
|
|
||||||
|
byte[] buf = new byte[65536];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
long total = 0;
|
||||||
|
long size = archive.getSize();
|
||||||
|
long inc = size / NUM_FETCH_URL_MONITOR_INC;
|
||||||
|
long next_inc = inc;
|
||||||
|
|
||||||
|
while ((n = is.read(buf)) >= 0) {
|
||||||
|
if (n > 0) {
|
||||||
|
os.write(buf, 0, n);
|
||||||
|
digester.update(buf, 0, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
total += n;
|
||||||
|
if (total >= next_inc) {
|
||||||
|
monitor.incProgress(1);
|
||||||
|
next_inc += inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitor.cancelRequested()) {
|
||||||
|
monitor.setResult("Download aborted by user at %1$d bytes.", total);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total != size) {
|
||||||
|
monitor.setResult("Download finished with wrong size. Expected %1$d bytes, got %2$d bytes.",
|
||||||
|
size, total);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an hex string from the digest
|
||||||
|
byte[] digest = digester.digest();
|
||||||
|
n = digest.length;
|
||||||
|
String hex = "0123456789abcdef"; //$NON-NLS-1$
|
||||||
|
char[] hexDigest = new char[n * 2];
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
byte b = digest[i];
|
||||||
|
hexDigest[i*2 + 0] = hex.charAt(b >>> 4);
|
||||||
|
hexDigest[i*2 + 1] = hex.charAt(b & 0x0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
String expected = archive.getChecksum();
|
||||||
|
String actual = new String(hexDigest);
|
||||||
|
if (!actual.equalsIgnoreCase(expected)) {
|
||||||
|
monitor.setResult("Download finished with wrong checksum. Expected %1$s, got %2$s.",
|
||||||
|
expected, actual);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
monitor.setResult(e.getMessage());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (os != null) {
|
||||||
|
try {
|
||||||
|
os.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is != null) {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean installArchive(Archive archive, File archiveFile, ITaskMonitor monitor) {
|
||||||
|
monitor.setDescription("Installing %1$s", archive.getShortDescription());
|
||||||
|
|
||||||
|
File destFolder = archive.getParentPackage().getInstallFolder(mUpdaterData.getOsSdkRoot());
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of hiding from SWT Designer
|
// End of hiding from SWT Designer
|
||||||
|
|||||||
Reference in New Issue
Block a user