aboutsummaryrefslogtreecommitdiffstats
path: root/sdkmanager
diff options
context:
space:
mode:
Diffstat (limited to 'sdkmanager')
-rw-r--r--sdkmanager/Android.mk18
-rw-r--r--sdkmanager/MODULE_LICENSE_APACHE20
-rw-r--r--sdkmanager/app/.classpath9
-rw-r--r--sdkmanager/app/.project17
-rw-r--r--sdkmanager/app/Android.mk5
-rw-r--r--sdkmanager/app/etc/Android.mk8
-rwxr-xr-xsdkmanager/app/etc/android84
-rwxr-xr-xsdkmanager/app/etc/android.bat48
-rw-r--r--sdkmanager/app/etc/manifest.txt1
-rw-r--r--sdkmanager/app/src/Android.mk16
-rw-r--r--sdkmanager/app/src/com/android/sdkmanager/Main.java487
-rw-r--r--sdkmanager/libs/Android.mk18
-rw-r--r--sdkmanager/libs/sdklib/.classpath7
-rw-r--r--sdkmanager/libs/sdklib/.project17
-rw-r--r--sdkmanager/libs/sdklib/Android.mk17
-rw-r--r--sdkmanager/libs/sdklib/src/Android.mk27
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java198
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java104
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java25
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java186
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java174
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java420
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java136
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/vm/HardwareProperties.java159
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java258
-rw-r--r--sdkmanager/libs/sdkuilib/Android.mk4
-rw-r--r--sdkmanager/libs/sdkuilib/README11
-rw-r--r--sdkmanager/libs/sdkuilib/src/Android.mk21
-rw-r--r--sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/SdkTargetSelector.java319
29 files changed, 2794 insertions, 0 deletions
diff --git a/sdkmanager/Android.mk b/sdkmanager/Android.mk
new file mode 100644
index 0000000..30df7f1
--- /dev/null
+++ b/sdkmanager/Android.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2008 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.
+#
+SDKMANAGER_LOCAL_DIR := $(call my-dir)
+include $(SDKMANAGER_LOCAL_DIR)/app/Android.mk
+include $(SDKMANAGER_LOCAL_DIR)/libs/Android.mk
diff --git a/sdkmanager/MODULE_LICENSE_APACHE2 b/sdkmanager/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sdkmanager/MODULE_LICENSE_APACHE2
diff --git a/sdkmanager/app/.classpath b/sdkmanager/app/.classpath
new file mode 100644
index 0000000..45c59d3
--- /dev/null
+++ b/sdkmanager/app/.classpath
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/SdkLib"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/AndroidPrefs"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/SdkUiLib"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/sdkmanager/app/.project b/sdkmanager/app/.project
new file mode 100644
index 0000000..e12c17d
--- /dev/null
+++ b/sdkmanager/app/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>SdkManager</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/sdkmanager/app/Android.mk b/sdkmanager/app/Android.mk
new file mode 100644
index 0000000..24ba61f
--- /dev/null
+++ b/sdkmanager/app/Android.mk
@@ -0,0 +1,5 @@
+# Copyright 2007 The Android Open Source Project
+#
+SDKMANAGERAPP_LOCAL_DIR := $(call my-dir)
+include $(SDKMANAGERAPP_LOCAL_DIR)/etc/Android.mk
+include $(SDKMANAGERAPP_LOCAL_DIR)/src/Android.mk
diff --git a/sdkmanager/app/etc/Android.mk b/sdkmanager/app/etc/Android.mk
new file mode 100644
index 0000000..8723cd8
--- /dev/null
+++ b/sdkmanager/app/etc/Android.mk
@@ -0,0 +1,8 @@
+# Copyright 2008 The Android Open Source Project
+#
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_PREBUILT_EXECUTABLES := android
+include $(BUILD_HOST_PREBUILT)
+
diff --git a/sdkmanager/app/etc/android b/sdkmanager/app/etc/android
new file mode 100755
index 0000000..af4042b
--- /dev/null
+++ b/sdkmanager/app/etc/android
@@ -0,0 +1,84 @@
+#!/bin/sh
+# Copyright 2005-2007, 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.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+ newProg=`/bin/ls -ld "${prog}"`
+ newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+ if expr "x${newProg}" : 'x/' >/dev/null; then
+ prog="${newProg}"
+ else
+ progdir=`dirname "${prog}"`
+ prog="${progdir}/${newProg}"
+ fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+jarfile=sdkmanager.jar
+frameworkdir="$progdir"
+libdir="$progdir"
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+ frameworkdir=`dirname "$progdir"`/tools/lib
+ libdir=`dirname "$progdir"`/tools/lib
+fi
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+ frameworkdir=`dirname "$progdir"`/framework
+ libdir=`dirname "$progdir"`/lib
+fi
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+ echo `basename "$prog"`": can't find $jarfile"
+ exit 1
+fi
+
+
+# Check args.
+if [ debug = "$1" ]; then
+ # add this in for debugging
+ java_debug=-agentlib:jdwp=transport=dt_socket,server=y,address=8050,suspend=y
+ shift 1
+else
+ java_debug=
+fi
+
+# Mac OS X needs an additional arg, or you get an "illegal thread" complaint.
+if [ `uname` = "Darwin" ]; then
+ os_opts="-XstartOnFirstThread"
+ #because Java 1.6 is 64 bits only and SWT doesn't support this, we force the usage of java 1.5
+ java_cmd="/System/Library/Frameworks/JavaVM.framework/Versions/1.5/Commands/java"
+else
+ os_opts=
+ java_cmd="java"
+fi
+
+if [ "$OSTYPE" = "cygwin" ] ; then
+ jarpath=`cygpath -w "$frameworkdir/$jarfile"`
+ progdir=`cygpath -w "$progdir"`
+else
+ jarpath="$frameworkdir/$jarfile"
+fi
+
+# need to use "java.ext.dirs" because "-jar" causes classpath to be ignored
+# might need more memory, e.g. -Xmx128M
+exec "$java_cmd" -Xmx256M $os_opts $java_debug -Djava.ext.dirs="$frameworkdir" -Djava.library.path="$libdir" -Dcom.android.sdkmanager.toolsdir="$progdir" -jar "$jarpath" "$@"
diff --git a/sdkmanager/app/etc/android.bat b/sdkmanager/app/etc/android.bat
new file mode 100755
index 0000000..2aa458d
--- /dev/null
+++ b/sdkmanager/app/etc/android.bat
@@ -0,0 +1,48 @@
+@echo off
+rem Copyright (C) 2007 The Android Open Source Project
+rem
+rem Licensed under the Apache License, Version 2.0 (the "License");
+rem you may not use this file except in compliance with the License.
+rem You may obtain a copy of the License at
+rem
+rem http://www.apache.org/licenses/LICENSE-2.0
+rem
+rem Unless required by applicable law or agreed to in writing, software
+rem distributed under the License is distributed on an "AS IS" BASIS,
+rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+rem See the License for the specific language governing permissions and
+rem limitations under the License.
+
+rem don't modify the caller's environment
+setlocal
+
+rem Set up prog to be the path of this script, including following symlinks,
+rem and set up progdir to be the fully-qualified pathname of its directory.
+set prog=%~f0
+
+rem Change current directory to where ddms is, to avoid issues with directories
+rem containing whitespaces.
+cd %~dp0
+
+set jarfile=sdkmanager.jar
+set frameworkdir=
+set libdir=
+
+if exist %frameworkdir%%jarfile% goto JarFileOk
+ set frameworkdir=lib\
+ set libdir=lib\
+
+if exist %frameworkdir%%jarfile% goto JarFileOk
+ set frameworkdir=..\framework\
+ set libdir=..\lib\
+
+:JarFileOk
+
+if debug NEQ "%1" goto NoDebug
+ set java_debug=-agentlib:jdwp=transport=dt_socket,server=y,address=8050,suspend=y
+ shift 1
+:NoDebug
+
+set jarpath=%frameworkdir%%jarfile%
+
+call java %java_debug% -Djava.ext.dirs=%frameworkdir% -Djava.library.path=%libdir% -Dcom.android.sdkmanager.toolsdir= -jar %jarpath% %*
diff --git a/sdkmanager/app/etc/manifest.txt b/sdkmanager/app/etc/manifest.txt
new file mode 100644
index 0000000..5676634
--- /dev/null
+++ b/sdkmanager/app/etc/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.sdkmanager.Main
diff --git a/sdkmanager/app/src/Android.mk b/sdkmanager/app/src/Android.mk
new file mode 100644
index 0000000..b508076
--- /dev/null
+++ b/sdkmanager/app/src/Android.mk
@@ -0,0 +1,16 @@
+# Copyright 2007 The Android Open Source Project
+#
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAR_MANIFEST := ../etc/manifest.txt
+LOCAL_JAVA_LIBRARIES := \
+ androidprefs \
+ sdklib \
+ sdkuilib
+LOCAL_MODULE := sdkmanager
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
diff --git a/sdkmanager/app/src/com/android/sdkmanager/Main.java b/sdkmanager/app/src/com/android/sdkmanager/Main.java
new file mode 100644
index 0000000..72bd2aa
--- /dev/null
+++ b/sdkmanager/app/src/com/android/sdkmanager/Main.java
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2008 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.sdkmanager;
+
+import com.android.prefs.AndroidLocation;
+import com.android.prefs.AndroidLocation.AndroidLocationException;
+import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.ISdkLog;
+import com.android.sdklib.SdkConstants;
+import com.android.sdklib.SdkManager;
+import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
+import com.android.sdklib.vm.HardwareProperties;
+import com.android.sdklib.vm.VmManager;
+import com.android.sdklib.vm.HardwareProperties.HardwareProperty;
+import com.android.sdklib.vm.VmManager.VmInfo;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Main class for the 'android' application
+ *
+ */
+class Main {
+
+ private final static String TOOLSDIR = "com.android.sdkmanager.toolsdir";
+
+ private final static String ARG_LIST_TARGET = "target";
+ private final static String ARG_LIST_VM = "vm";
+
+ private final static String[] BOOLEAN_YES_REPLIES = new String[] { "yes", "y" };
+ private final static String[] BOOLEAN_NO_REPLIES = new String[] { "no", "n" };
+
+ private String mSdkFolder;
+ private SdkManager mSdkManager;
+ private VmManager mVmManager;
+
+ /* --list parameters */
+ private String mListObject;
+
+ /* --create parameters */
+ private boolean mCreateVm;
+ private int mCreateTargetId;
+ private IAndroidTarget mCreateTarget;
+ private String mCreateName;
+
+ public static void main(String[] args) {
+ new Main().run(args);
+ }
+
+ /**
+ * Runs the sdk manager app
+ * @param args
+ */
+ private void run(String[] args) {
+ init();
+ parseArgs(args);
+ parseSdk();
+ doAction();
+ }
+
+ /**
+ * Init the application by making sure the SDK path is available and
+ * doing basic parsing of the SDK.
+ */
+ private void init() {
+ /* We get passed a property for the tools dir */
+ String toolsDirProp = System.getProperty(TOOLSDIR);
+ if (toolsDirProp == null) {
+ // for debugging, it's easier to override using the process environment
+ toolsDirProp = System.getenv(TOOLSDIR);
+ }
+ if (toolsDirProp == null) {
+ printHelpAndExit("ERROR: The tools directory property is not set, please make sure you are executing android or android.bat");
+ }
+
+ // got back a level for the SDK folder
+ File tools = new File(toolsDirProp);
+ mSdkFolder = tools.getParent();
+
+ }
+
+ /**
+ * Parses command-line arguments, or prints help/usage and exits if error.
+ * @param args arguments passed to the program
+ */
+ private void parseArgs(String[] args) {
+ final int numArgs = args.length;
+
+ try {
+ int argPos = 0;
+ for (; argPos < numArgs; argPos++) {
+ final String arg = args[argPos];
+ if (arg.equals("-l") || arg.equals("--list")) {
+ mListObject = args[++argPos];
+ } else if (arg.equals("-c") || arg.equals("--create")) {
+ mCreateVm = true;
+ parseCreateArgs(args, ++argPos);
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ /* Any OOB triggers help */
+ printHelpAndExit("ERROR: Not enough arguments.");
+ }
+ }
+
+ private void parseCreateArgs(String[] args, int argPos) {
+ final int numArgs = args.length;
+
+ try {
+ for (; argPos < numArgs; argPos++) {
+ final String arg = args[argPos];
+ if (arg.equals("-t") || arg.equals("--target")) {
+ String targetId = args[++argPos];
+ try {
+ // get the target id
+ mCreateTargetId = Integer.parseInt(targetId);
+ } catch (NumberFormatException e) {
+ printHelpAndExit("ERROR: Target Id is not a number");
+ }
+ } else if (arg.equals("-n") || arg.equals("--name")) {
+ mCreateName = args[++argPos];
+ } else {
+ printHelpAndExit("ERROR: '%s' unknown argument for --create mode",
+ args[argPos]);
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ /* Any OOB triggers help */
+ printHelpAndExit("ERROR: Not enough arguments for --create");
+ }
+ }
+
+ /**
+ * Does the basic SDK parsing required for all actions
+ */
+ private void parseSdk() {
+ mSdkManager = SdkManager.createManager(mSdkFolder, new ISdkLog() {
+ public void error(String errorFormat, Object... args) {
+ System.err.printf("Error: " + errorFormat, args);
+ System.err.println("");
+ }
+
+ public void warning(String warningFormat, Object... args) {
+ if (false) {
+ // TODO: on display warnings in verbose mode.
+ System.out.printf("Warning: " + warningFormat, args);
+ System.out.println("");
+ }
+ }
+ });
+
+ if (mSdkManager == null) {
+ printHelpAndExit("ERROR: Unable to parse SDK content.");
+ }
+ }
+
+ /**
+ * Actually do an action...
+ */
+ private void doAction() {
+ if (mListObject != null) {
+ // list action.
+ if (ARG_LIST_TARGET.equals(mListObject)) {
+ displayTargetList();
+ } else if (ARG_LIST_VM.equals(mListObject)) {
+ displayVmList();
+ } else {
+ printHelpAndExit("'%s' is not a valid --list option", mListObject);
+ }
+ } else if (mCreateVm) {
+ createVm();
+ } else {
+ printHelpAndExit(null);
+ }
+ }
+
+ /**
+ * Displays the list of available Targets (Platforms and Add-ons)
+ */
+ private void displayTargetList() {
+ System.out.println("Available Android targets:");
+
+ int index = 1;
+ for (IAndroidTarget target : mSdkManager.getTargets()) {
+ if (target.isPlatform()) {
+ System.out.printf("[%d] %s\n", index, target.getName());
+ System.out.printf(" API level: %d\n", target.getApiVersionNumber());
+ } else {
+ System.out.printf("[%d] Add-on: %s\n", index, target.getName());
+ System.out.printf(" Vendor: %s\n", target.getVendor());
+ if (target.getDescription() != null) {
+ System.out.printf(" Description: %s\n", target.getDescription());
+ }
+ System.out.printf(" Based on Android %s (API level %d)\n",
+ target.getApiVersionName(), target.getApiVersionNumber());
+
+ // display the optional libraries.
+ IOptionalLibrary[] libraries = target.getOptionalLibraries();
+ if (libraries != null) {
+ for (IOptionalLibrary library : libraries) {
+ System.out.printf(" Library: %s (%s)\n", library.getName(),
+ library.getJarName());
+ }
+ }
+ }
+
+ // get the target skins
+ String[] skins = target.getSkins();
+ System.out.print(" Skins: ");
+ if (skins != null) {
+ boolean first = true;
+ for (String skin : skins) {
+ if (first == false) {
+ System.out.print(", ");
+ } else {
+ first = false;
+ }
+ System.out.print(skin);
+ }
+ System.out.println("");
+ } else {
+ System.out.println("no skins.");
+ }
+
+ index++;
+ }
+ }
+
+ /**
+ * Displays the list of available VMs.
+ */
+ private void displayVmList() {
+ try {
+ mVmManager = new VmManager(mSdkManager, null /* sdklog */);
+
+ System.out.println("Available Android VMs:");
+
+ int index = 1;
+ for (VmInfo info : mVmManager.getVms()) {
+ System.out.printf("[%d] %s\n", index, info.getName());
+ System.out.printf(" Path: %s\n", info.getPath());
+
+ // get the target of the Vm
+ IAndroidTarget target = info.getTarget();
+ if (target.isPlatform()) {
+ System.out.printf(" Target: %s (API level %d)\n", target.getName(),
+ target.getApiVersionNumber());
+ } else {
+ System.out.printf(" Target: %s (%s)\n", target.getName(), target
+ .getVendor());
+ System.out.printf(" Based on Android %s (API level %d)\n", target
+ .getApiVersionName(), target.getApiVersionNumber());
+
+ }
+
+ index++;
+ }
+ } catch (AndroidLocationException e) {
+ printHelpAndExit(e.getMessage());
+ }
+ }
+
+ /**
+ * Creates a new VM. This is a text based creation with command line prompt.
+ */
+ private void createVm() {
+ // find a matching target
+ if (mCreateTargetId >= 1 && mCreateTargetId <= mSdkManager.getTargets().length) {
+ mCreateTarget = mSdkManager.getTargets()[mCreateTargetId-1]; // target it is 1-based
+ } else {
+ printHelpAndExit(
+ "ERROR: Target Id is not a valid Id. Check android --list target for the list of targets.");
+ }
+
+ try {
+ // default to standard path now
+ String vmRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS;
+
+ Map<String, String> hardwareConfig = null;
+ if (mCreateTarget.isPlatform()) {
+ try {
+ hardwareConfig = promptForHardware(mCreateTarget);
+ } catch (IOException e) {
+ printHelpAndExit(e.getMessage());
+ }
+ }
+
+ VmManager.createVm(vmRoot, mCreateName, mCreateTarget, null /*skinName*/,
+ null /*sdcardPath*/, 0 /*sdcardSize*/, hardwareConfig,
+ null /* sdklog */);
+ } catch (AndroidLocationException e) {
+ printHelpAndExit(e.getMessage());
+ }
+ }
+
+ /**
+ * Prompts the user to setup a hardware config for a Platform-based VM.
+ * @throws IOException
+ */
+ private Map<String, String> promptForHardware(IAndroidTarget createTarget) throws IOException {
+ byte[] readLineBuffer = new byte[256];
+ String result;
+ String defaultAnswer = "no";
+
+ System.out.print(String.format("%s is a basic Android platform.\n",
+ createTarget.getName()));
+ System.out.print(String.format("Do you which to create a custom hardware profile [%s]",
+ defaultAnswer));
+
+ result = readLine(readLineBuffer);
+ // handle default:
+ if (result.length() == 0) {
+ result = defaultAnswer;
+ }
+
+ if (getBooleanReply(result) == false) {
+ // no custom config.
+ return null;
+ }
+
+ System.out.println(""); // empty line
+
+ // get the list of possible hardware properties
+ File hardwareDefs = new File (mSdkFolder + File.separator +
+ SdkConstants.OS_SDK_TOOLS_LIB_FOLDER, SdkConstants.FN_HARDWARE_INI);
+ List<HardwareProperty> list = HardwareProperties.parseHardwareDefinitions(hardwareDefs,
+ null /*sdkLog*/);
+
+ HashMap<String, String> map = new HashMap<String, String>();
+
+ for (int i = 0 ; i < list.size() ;) {
+ HardwareProperty property = list.get(i);
+
+ String description = property.getDescription();
+ if (description != null) {
+ System.out.printf("%s: %s\n", property.getAbstract(), description);
+ } else {
+ System.out.println(property.getAbstract());
+ }
+
+ String defaultValue = property.getDefault();
+
+ if (defaultValue != null) {
+ System.out.printf("%s [%s]:", property.getName(), defaultValue);
+ } else {
+ System.out.printf("%s (%s):", property.getName(), property.getType());
+ }
+
+ result = readLine(readLineBuffer);
+ if (result.length() == 0) {
+ if (defaultValue != null) {
+ System.out.println(""); // empty line
+ i++; // go to the next property if we have a valid default value.
+ // if there's no default, we'll redo this property
+ }
+ continue;
+ }
+
+ switch (property.getType()) {
+ case BOOLEAN:
+ try {
+ if (getBooleanReply(result)) {
+ map.put(property.getName(), "yes");
+ i++; // valid reply, move to next property
+ } else {
+ map.put(property.getName(), "no");
+ i++; // valid reply, move to next property
+ }
+ } catch (IOException e) {
+ // display error, and do not increment i to redo this property
+ System.out.println("\n" + e.getMessage());
+ }
+ break;
+ case INTEGER:
+ try {
+ @SuppressWarnings("unused")
+ int value = Integer.parseInt(result);
+ map.put(property.getName(), result);
+ i++; // valid reply, move to next property
+ } catch (NumberFormatException e) {
+ // display error, and do not increment i to redo this property
+ System.out.println("\n" + e.getMessage());
+ }
+ break;
+ case DISKSIZE:
+ // TODO check validity
+ map.put(property.getName(), result);
+ i++; // valid reply, move to next property
+ break;
+ }
+
+ System.out.println(""); // empty line
+ }
+
+ return map;
+ }
+
+ /**
+ * Read the line from the input stream.
+ * @param buffer
+ * @return
+ * @throws IOException
+ */
+ private String readLine(byte[] buffer) throws IOException {
+ int count = System.in.read(buffer);
+
+ // is the input longer than the buffer?
+ if (count == buffer.length && buffer[count-1] != 10) {
+ // create a new temp buffer
+ byte[] tempBuffer = new byte[256];
+
+ // and read the rest
+ String secondHalf = readLine(tempBuffer);
+
+ // return a concat of both
+ return new String(buffer, 0, count) + secondHalf;
+ }
+
+ return new String(buffer, 0, count - 1); // -1 to not include the carriage return
+ }
+
+ /**
+ * Returns the boolean value represented by the string.
+ * @throws IOException If the value is not a boolean string.
+ */
+ private boolean getBooleanReply(String reply) throws IOException {
+ for (String valid : BOOLEAN_YES_REPLIES) {
+ if (valid.equalsIgnoreCase(reply)) {
+ return true;
+ }
+ }
+
+ for (String valid : BOOLEAN_NO_REPLIES) {
+ if (valid.equalsIgnoreCase(reply)) {
+ return false;
+ }
+ }
+
+ throw new IOException(String.format("%s is not a valid reply", reply));
+ }
+
+ /**
+ * Prints the help/usage and exits.
+ * @param errorFormat Optional error message to print prior to usage using String.format
+ * @param args Arguments for String.format
+ */
+ private void printHelpAndExit(String errorFormat, Object... args) {
+ if (errorFormat != null) {
+ System.err.println(String.format(errorFormat, args));
+ }
+
+ /*
+ * usage should fit in 80 columns
+ * 12345678901234567890123456789012345678901234567890123456789012345678901234567890
+ */
+ final String usage = "\n" +
+ "Usage:\n" +
+ " android --list [target|vm]\n" +
+ " android --create --target <target id> --name <name>\n" +
+ "\n" +
+ "Options:\n" +
+ " -l [target|vm], --list [target|vm]\n" +
+ " Outputs the available targets or Virtual Machines and their Ids.\n" +
+ "\n";
+
+ System.out.println(usage);
+ System.exit(1);
+ }
+} \ No newline at end of file
diff --git a/sdkmanager/libs/Android.mk b/sdkmanager/libs/Android.mk
new file mode 100644
index 0000000..a934aa7
--- /dev/null
+++ b/sdkmanager/libs/Android.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2008 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.
+#
+SDKLIBS_LOCAL_DIR := $(call my-dir)
+include $(SDKLIBS_LOCAL_DIR)/sdklib/Android.mk
+include $(SDKLIBS_LOCAL_DIR)/sdkuilib/Android.mk
diff --git a/sdkmanager/libs/sdklib/.classpath b/sdkmanager/libs/sdklib/.classpath
new file mode 100644
index 0000000..fc17a43
--- /dev/null
+++ b/sdkmanager/libs/sdklib/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/AndroidPrefs"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/sdkmanager/libs/sdklib/.project b/sdkmanager/libs/sdklib/.project
new file mode 100644
index 0000000..97a8578
--- /dev/null
+++ b/sdkmanager/libs/sdklib/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>SdkLib</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/sdkmanager/libs/sdklib/Android.mk b/sdkmanager/libs/sdklib/Android.mk
new file mode 100644
index 0000000..509c573
--- /dev/null
+++ b/sdkmanager/libs/sdklib/Android.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2008 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.
+#
+SDKLIB_LOCAL_DIR := $(call my-dir)
+include $(SDKLIB_LOCAL_DIR)/src/Android.mk
diff --git a/sdkmanager/libs/sdklib/src/Android.mk b/sdkmanager/libs/sdklib/src/Android.mk
new file mode 100644
index 0000000..a059a46
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2008 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.
+#
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := \
+ androidprefs
+
+LOCAL_MODULE := sdklib
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
new file mode 100644
index 0000000..5759613
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2008 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;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Represents an add-on target in the SDK.
+ * An add-on extends a standard {@link PlatformTarget}.
+ */
+final class AddOnTarget implements IAndroidTarget {
+ /**
+ * String to compute hash for add-on targets.
+ * Format is vendor:name:apiVersion
+ * */
+ private final static String ADD_ON_FORMAT = "%s:%s:%d"; //$NON-NLS-1$
+
+ private final static class OptionalLibrary implements IOptionalLibrary {
+ private final String mJarName;
+ private final String mJarPath;
+ private final String mName;
+
+ OptionalLibrary(String jarName, String jarPath, String name) {
+ mJarName = jarName;
+ mJarPath = jarPath;
+ mName = name;
+ }
+
+ public String getJarName() {
+ return mJarName;
+ }
+
+ public String getJarPath() {
+ return mJarPath;
+ }
+
+ public String getName() {
+ return mName;
+ }
+ }
+
+ private final String mLocation;
+ private final PlatformTarget mBasePlatform;
+ private final String mName;
+ private final String mVendor;
+ private final String mDescription;
+ private String[] mSkins;
+ private IOptionalLibrary[] mLibraries;
+
+ /**
+ * Creates a new add-on
+ * @param location the OS path location of the add-on
+ * @param name the name of the add-on
+ * @param vendor the vendor name of the add-on
+ * @param description the add-on description
+ * @param libMap A map containing the optional libraries. The map key is the fully-qualified
+ * library name. The value is the .jar filename
+ * @param basePlatform the platform the add-on is extending.
+ */
+ AddOnTarget(String location, String name, String vendor, String description,
+ Map<String, String> libMap, PlatformTarget basePlatform) {
+ if (location.endsWith(File.separator) == false) {
+ location = location + File.separator;
+ }
+
+ mLocation = location;
+ mName = name;
+ mVendor = vendor;
+ mDescription = description;
+ mBasePlatform = basePlatform;
+
+ // handle the optional libraries.
+ mLibraries = new IOptionalLibrary[libMap.size()];
+ int index = 0;
+ for (Entry<String, String> entry : libMap.entrySet()) {
+ mLibraries[index++] = new OptionalLibrary(entry.getValue(),
+ mLocation + SdkConstants.OS_ADDON_LIBS_FOLDER + entry.getValue(),
+ entry.getKey());
+ }
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public String getVendor() {
+ return mVendor;
+ }
+
+ public String getDescription() {
+ return mDescription;
+ }
+
+ public String getApiVersionName() {
+ // this is always defined by the base platform
+ return mBasePlatform.getApiVersionName();
+ }
+
+ public int getApiVersionNumber() {
+ // this is always defined by the base platform
+ return mBasePlatform.getApiVersionNumber();
+ }
+
+ public boolean isPlatform() {
+ return false;
+ }
+
+ public String getPath(int pathId) {
+ switch (pathId) {
+ case IMAGES:
+ return mLocation + SdkConstants.OS_IMAGES_FOLDER;
+ case SKINS:
+ return mLocation + SdkConstants.OS_SKINS_FOLDER;
+ default :
+ return mBasePlatform.getPath(pathId);
+ }
+ }
+
+ public String[] getSkins() {
+ return mSkins;
+ }
+
+ public IOptionalLibrary[] getOptionalLibraries() {
+ return mLibraries;
+ }
+
+ public String hashString() {
+ return String.format(ADD_ON_FORMAT, mVendor, mName, mBasePlatform.getApiVersionNumber());
+ }
+
+ @Override
+ public int hashCode() {
+ return hashString().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof AddOnTarget) {
+ AddOnTarget addon = (AddOnTarget)obj;
+
+ return mVendor.equals(addon.mVendor) && mName.equals(addon.mName) &&
+ mBasePlatform.getApiVersionNumber() == addon.mBasePlatform.getApiVersionNumber();
+ }
+
+ return super.equals(obj);
+ }
+
+ /*
+ * Always return +1 if the object we compare to is a platform.
+ * Otherwise, do vendor then name then api version comparison.
+ * (non-Javadoc)
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo(IAndroidTarget target) {
+ if (target.isPlatform()) {
+ return +1;
+ }
+
+ // vendor
+ int value = mVendor.compareTo(target.getVendor());
+
+ // name
+ if (value == 0) {
+ value = mName.compareTo(target.getName());
+ }
+
+ // api version
+ if (value == 0) {
+ value = getApiVersionNumber() - target.getApiVersionNumber();
+ }
+
+ return value;
+ }
+
+
+ // ---- local methods.
+
+
+ public void setSkins(String[] skins) {
+ mSkins = skins;
+ }
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
new file mode 100644
index 0000000..e5d45b2
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2008 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;
+
+
+/**
+ * A version of Android that application can target when building.
+ */
+public interface IAndroidTarget extends Comparable<IAndroidTarget> {
+
+ public static int ANDROID_JAR = 1;
+ public static int ANDROID_AIDL = 2;
+ public static int IMAGES = 3;
+ public static int SAMPLES = 4;
+ public static int SKINS = 5;
+ public static int TEMPLATES = 6;
+ public static int DATA = 7;
+ public static int ATTRIBUTES = 8;
+ public static int MANIFEST_ATTRIBUTES = 9;
+ public static int LAYOUT_LIB = 10;
+ public static int RESOURCES = 11;
+ public static int FONTS = 12;
+ public static int WIDGETS = 13;
+ public static int ACTIONS_ACTIVITY = 14;
+ public static int ACTIONS_BROADCAST = 15;
+ public static int ACTIONS_SERVICE = 16;
+ public static int CATEGORIES = 17;
+ public static int SOURCES = 18;
+
+ public interface IOptionalLibrary {
+ String getName();
+ String getJarName();
+ String getJarPath();
+ }
+
+ /**
+ * Returns the name of the vendor of the target.
+ */
+ String getVendor();
+
+ /**
+ * Returns the name of the target.
+ */
+ String getName();
+
+ /**
+ * Returns the description of the target.
+ */
+ String getDescription();
+
+ /**
+ * Returns the api version as an integer.
+ */
+ int getApiVersionNumber();
+
+ /**
+ * Returns the platform version as a readable string.
+ */
+ String getApiVersionName();
+
+ /**
+ * Returns true if the target is a standard Android platform.
+ */
+ boolean isPlatform();
+
+ /**
+ * Returns the path of a platform component.
+ * @param pathId the id representing the path to return. Any of the constants defined in the
+ * {@link ITargetDataProvider} interface can be used.
+ */
+ String getPath(int pathId);
+
+ /**
+ * Returns the available skins for this target.
+ */
+ String[] getSkins();
+
+ /**
+ * Returns the available optional libraries for this target.
+ * @return an array of optional libraries or <code>null</code> if there is none.
+ */
+ IOptionalLibrary[] getOptionalLibraries();
+
+ /**
+ * Returns a string able to uniquely identify a target.
+ * Typically the target will encode information such as api level, whether it's a platform
+ * or add-on, and if it's an add-on vendor and add-on name.
+ */
+ String hashString();
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java
new file mode 100644
index 0000000..3eda37f
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2008 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;
+
+/**
+ * Interface used to display warnings/errors while parsing the SDK content.
+ */
+public interface ISdkLog {
+ void warning(String warningFormat, Object... args);
+ void error(String errorFormat, Object... args);
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
new file mode 100644
index 0000000..f5a1f6d
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2008 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;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a platform target in the SDK.
+ */
+final class PlatformTarget implements IAndroidTarget {
+ /** String used to get a hash to the platform target */
+ private final static String PLATFORM_HASH = "android-%d";
+
+ private final static String PLATFORM_VENDOR = "Android";
+ private final static String PLATFORM_NAME = "Android %s";
+
+ private final String mLocation;
+ private final String mName;
+ private final int mApiVersionNumber;
+ private final String mApiVersionName;
+ private final Map<String, String> mProperties;
+ private final Map<Integer, String> mPaths = new HashMap<Integer, String>();
+ private String[] mSkins;
+
+ PlatformTarget(String location, Map<String, String> properties,
+ int apiNumber, String apiName) {
+ mName = String.format(PLATFORM_NAME, apiName);
+ if (location.endsWith(File.separator) == false) {
+ location = location + File.separator;
+ }
+ mLocation = location;
+ mProperties = Collections.unmodifiableMap(properties);
+ mApiVersionNumber = apiNumber;
+ mApiVersionName = apiName;
+
+ // pre-build the path to the platform components
+ mPaths.put(ANDROID_JAR, mLocation + SdkConstants.FN_FRAMEWORK_LIBRARY);
+ mPaths.put(SOURCES, mLocation + SdkConstants.FD_ANDROID_SOURCES);
+ mPaths.put(ANDROID_AIDL, mLocation + SdkConstants.FN_FRAMEWORK_AIDL);
+ mPaths.put(IMAGES, mLocation + SdkConstants.OS_IMAGES_FOLDER);
+ mPaths.put(SAMPLES, mLocation + SdkConstants.OS_PLATFORM_SAMPLES_FOLDER);
+ mPaths.put(SKINS, mLocation + SdkConstants.OS_SKINS_FOLDER);
+ mPaths.put(TEMPLATES, mLocation + SdkConstants.OS_PLATFORM_TEMPLATES_FOLDER);
+ mPaths.put(DATA, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER);
+ mPaths.put(ATTRIBUTES, mLocation + SdkConstants.OS_PLATFORM_ATTRS_XML);
+ mPaths.put(MANIFEST_ATTRIBUTES, mLocation + SdkConstants.OS_PLATFORM_ATTRS_MANIFEST_XML);
+ mPaths.put(RESOURCES, mLocation + SdkConstants.OS_PLATFORM_RESOURCES_FOLDER);
+ mPaths.put(FONTS, mLocation + SdkConstants.OS_PLATFORM_FONTS_FOLDER);
+ mPaths.put(LAYOUT_LIB, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER +
+ SdkConstants.FN_LAYOUTLIB_JAR);
+ mPaths.put(WIDGETS, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER +
+ SdkConstants.FN_WIDGETS);
+ mPaths.put(ACTIONS_ACTIVITY, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER +
+ SdkConstants.FN_INTENT_ACTIONS_ACTIVITY);
+ mPaths.put(ACTIONS_BROADCAST, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER +
+ SdkConstants.FN_INTENT_ACTIONS_BROADCAST);
+ mPaths.put(ACTIONS_SERVICE, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER +
+ SdkConstants.FN_INTENT_ACTIONS_SERVICE);
+ mPaths.put(CATEGORIES, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER +
+ SdkConstants.FN_INTENT_CATEGORIES);
+ }
+
+ public String getLocation() {
+ return mLocation;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * For Platform, the vendor name is always "Android".
+ *
+ * @see com.android.sdklib.IAndroidTarget#getVendor()
+ */
+ public String getVendor() {
+ return PLATFORM_VENDOR;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * Description for the Android platform is dynamically generated.
+ *
+ * @see com.android.sdklib.IAndroidTarget#getDescription()
+ */
+ public String getDescription() {
+ return String.format("Standard Android platform %s", mApiVersionName);
+ }
+
+ public int getApiVersionNumber(){
+ return mApiVersionNumber;
+ }
+
+ public String getApiVersionName() {
+ return mApiVersionName;
+ }
+
+ public boolean isPlatform() {
+ return true;
+ }
+
+ public String getPath(int pathId) {
+ return mPaths.get(pathId);
+ }
+
+ public String[] getSkins() {
+ return mSkins;
+ }
+
+ /*
+ * Always returns null, as a standard platforms have no optional libraries.
+ *
+ * (non-Javadoc)
+ * @see com.android.sdklib.IAndroidTarget#getOptionalLibraries()
+ */
+ public IOptionalLibrary[] getOptionalLibraries() {
+ return null;
+ }
+
+
+ public String hashString() {
+ return String.format(PLATFORM_HASH, mApiVersionNumber);
+ }
+
+ @Override
+ public int hashCode() {
+ return hashString().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof PlatformTarget) {
+ return mApiVersionNumber == ((PlatformTarget)obj).mApiVersionNumber;
+ }
+
+ return super.equals(obj);
+ }
+
+ /*
+ * Always return -1 if the object we compare to is an addon.
+ * Otherwise, compare api level.
+ * (non-Javadoc)
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo(IAndroidTarget target) {
+ if (target.isPlatform() == false) {
+ return -1;
+ }
+
+ return mApiVersionNumber - target.getApiVersionNumber();
+ }
+
+ // ---- platform only methods.
+
+ public String getProperty(String name) {
+ return mProperties.get(name);
+ }
+
+ public Map<String, String> getProperties() {
+ return mProperties; // mProperties is unmodifiable.
+ }
+
+ void setSkins(String[] skins) {
+ mSkins = skins;
+ }
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
new file mode 100644
index 0000000..78d1fda
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2007 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;
+
+import java.io.File;
+
+/**
+ * Constant definition class.<br>
+ * <br>
+ * Most constants have a prefix defining the content.
+ * <ul>
+ * <li><code>OS_</code> OS path constant. These paths are different depending on the platform.</li>
+ * <li><code>FN_</code> File name constant.</li>
+ * <li><code>FD_</code> Folder name constant.</li>
+ * </ul>
+ *
+ */
+public final class SdkConstants {
+
+ /** Name of the framework library, i.e. "android.jar" */
+ public static final String FN_FRAMEWORK_LIBRARY = "android.jar";
+ /** Name of the layout attributes, i.e. "attrs.xml" */
+ public static final String FN_ATTRS_XML = "attrs.xml";
+ /** Name of the layout attributes, i.e. "attrs_manifest.xml" */
+ public static final String FN_ATTRS_MANIFEST_XML = "attrs_manifest.xml";
+ /** framework aidl import file */
+ public static final String FN_FRAMEWORK_AIDL = "framework.aidl";
+ /** layoutlib.jar file */
+ public static final String FN_LAYOUTLIB_JAR = "layoutlib.jar";
+ /** widget list file */
+ public static final String FN_WIDGETS = "widgets.txt";
+ /** Intent activity actions list file */
+ public static final String FN_INTENT_ACTIONS_ACTIVITY = "activity_actions.txt";
+ /** Intent broadcast actions list file */
+ public static final String FN_INTENT_ACTIONS_BROADCAST = "broadcast_actions.txt";
+ /** Intent service actions list file */
+ public static final String FN_INTENT_ACTIONS_SERVICE = "service_actions.txt";
+ /** Intent category list file */
+ public static final String FN_INTENT_CATEGORIES = "categories.txt";
+
+ /** platform build property file */
+ public final static String FN_BUILD_PROP = "build.prop";
+ /** plugin properties file */
+ public final static String FN_PLUGIN_PROP = "plugin.prop";
+ /** add-on manifest file */
+ public final static String FN_MANIFEST_INI = "manifest.ini";
+ /** hardware properties definition file */
+ public final static String FN_HARDWARE_INI = "hardware-properties.ini";
+
+ /** Skin layout file */
+ public final static String FN_SKIN_LAYOUT = "layout";//$NON-NLS-1$
+
+ /* Folder Names for the Android SDK */
+
+ /** Name of the SDK platforms folder. */
+ public final static String FD_PLATFORMS = "platforms";
+ /** Name of the SDK addons folder. */
+ public final static String FD_ADDONS = "add-ons";
+ /** Name of the SDK tools folder. */
+ public final static String FD_TOOLS = "tools";
+ /** Name of the SDK tools/lib folder. */
+ public final static String FD_LIB = "lib";
+ /** Name of the SDK docs folder. */
+ public final static String FD_DOCS = "docs";
+ /** Name of the SDK images folder. */
+ public final static String FD_IMAGES = "images";
+ /** Name of the SDK skins folder. */
+ public final static String FD_SKINS = "skins";
+ /** Name of the SDK samples folder. */
+ public final static String FD_SAMPLES = "samples";
+ /** Name of the SDK templates folder, i.e. "templates" */
+ public final static String FD_TEMPLATES = "templates";
+ /** Name of the SDK data folder, i.e. "data" */
+ public final static String FD_DATA = "data";
+ /** Name of the SDK resources folder, i.e. "res" */
+ public final static String FD_RES = "res";
+ /** Name of the SDK font folder, i.e. "fonts" */
+ public final static String FD_FONTS = "fonts";
+ /** Default values resource folder name, i.e. "values" */
+ public final static String FD_VALUES = "values";
+ /** Name of the android sources directory */
+ public static final String FD_ANDROID_SOURCES = "sources";
+ /** Name of the addon libs folder. */
+ public final static String FD_ADDON_LIBS = "libs";
+
+ /* Folder path relative to the SDK root */
+ /** Path of the documentation directory relative to the sdk folder.
+ * This is an OS path, ending with a separator. */
+ public final static String OS_SDK_DOCS_FOLDER = FD_DOCS + File.separator;
+
+ /** Path of the tools directory relative to the sdk folder.
+ * This is an OS path, ending with a separator. */
+ public final static String OS_SDK_TOOLS_FOLDER = FD_TOOLS + File.separator;
+
+ /** Path of the lib directory relative to the sdk folder.
+ * This is an OS path, ending with a separator. */
+ public final static String OS_SDK_TOOLS_LIB_FOLDER =
+ OS_SDK_TOOLS_FOLDER + FD_LIB + File.separator;
+
+ /* Folder paths relative to a platform or add-on folder */
+
+ /** Path of the images directory relative to a platform or addon folder.
+ * This is an OS path, ending with a separator. */
+ public final static String OS_IMAGES_FOLDER = FD_IMAGES + File.separator;
+
+ /** Path of the skin directory relative to a platform or addon folder.
+ * This is an OS path, ending with a separator. */
+ public final static String OS_SKINS_FOLDER = FD_SKINS + File.separator;
+
+ /* Folder paths relative to a Platform folder */
+
+ /** Path of the data directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public final static String OS_PLATFORM_DATA_FOLDER = FD_DATA + File.separator;
+
+ /** Path of the samples directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public final static String OS_PLATFORM_SAMPLES_FOLDER = FD_SAMPLES + File.separator;
+
+ /** Path of the resources directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public final static String OS_PLATFORM_RESOURCES_FOLDER =
+ OS_PLATFORM_DATA_FOLDER + FD_RES + File.separator;
+
+ /** Path of the fonts directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public final static String OS_PLATFORM_FONTS_FOLDER =
+ OS_PLATFORM_DATA_FOLDER + FD_FONTS + File.separator;
+
+ /** Path of the android source directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public final static String OS_PLATFORM_SOURCES_FOLDER = FD_ANDROID_SOURCES + File.separator;
+
+ /** Path of the android templates directory relative to a platform folder.
+ * This is an OS path, ending with a separator. */
+ public final static String OS_PLATFORM_TEMPLATES_FOLDER = FD_TEMPLATES + File.separator;
+
+ /** Path of the attrs.xml file relative to a platform folder. */
+ public final static String OS_PLATFORM_ATTRS_XML =
+ OS_PLATFORM_RESOURCES_FOLDER + FD_VALUES + File.separator + FN_ATTRS_XML;
+
+ /** Path of the attrs_manifest.xml file relative to a platform folder. */
+ public final static String OS_PLATFORM_ATTRS_MANIFEST_XML =
+ OS_PLATFORM_RESOURCES_FOLDER + FD_VALUES + File.separator + FN_ATTRS_MANIFEST_XML;
+
+ /** Path of the layoutlib.jar file relative to a platform folder. */
+ public final static String OS_PLATFORM_LAYOUTLIB_JAR =
+ OS_PLATFORM_DATA_FOLDER + FN_LAYOUTLIB_JAR;
+
+ /* Folder paths relative to a addon folder */
+
+ /** Path of the images directory relative to a folder folder.
+ * This is an OS path, ending with a separator. */
+ public final static String OS_ADDON_LIBS_FOLDER = FD_ADDON_LIBS + File.separator;
+
+
+ /* Skin default */
+ public final static String SKIN_DEFAULT = "default";
+
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
new file mode 100644
index 0000000..67b8499
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2008 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;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * The SDK manager parses the SDK folder and gives access to the content.
+ * @see PlatformTarget
+ * @see AddOnTarget
+ */
+public final class SdkManager {
+
+ private final static String PROP_VERSION_SDK = "ro.build.version.sdk";
+ private final static String PROP_VERSION_RELEASE = "ro.build.version.release";
+
+ private final static String ADDON_NAME = "name";
+ private final static String ADDON_VENDOR = "vendor";
+ private final static String ADDON_API = "api";
+ private final static String ADDON_DESCRIPTION = "description";
+ private final static String ADDON_LIBRARIES = "libraries";
+
+ private final static Pattern PATTERN_PROP = Pattern.compile(
+ "^([a-zA-Z0-9._-]+)\\s*=\\s*(.*)\\s*$");
+
+ /** the location of the SDK */
+ private final String mSdkLocation;
+ private IAndroidTarget[] mTargets;
+
+ /**
+ * Creates an {@link SdkManager} for a given sdk location.
+ * @param sdkLocation the location of the SDK.
+ * @param log the ISdkLog object receiving warning/error from the parsing.
+ * @return the created {@link SdkManager} or null if the location is not valid.
+ */
+ public static SdkManager createManager(String sdkLocation, ISdkLog log) {
+ try {
+ SdkManager manager = new SdkManager(sdkLocation);
+ ArrayList<IAndroidTarget> list = new ArrayList<IAndroidTarget>();
+ manager.loadPlatforms(list, log);
+ manager.loadAddOns(list, log);
+
+ // sort the targets/add-ons
+ Collections.sort(list);
+
+ manager.setTargets(list.toArray(new IAndroidTarget[list.size()]));
+
+ return manager;
+ } catch (IllegalArgumentException e) {
+ if (log != null) {
+ log.error(e.getMessage());
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the location of the SDK.
+ */
+ public String getLocation() {
+ return mSdkLocation;
+ }
+
+ /**
+ * Returns the targets that are available in the SDK.
+ */
+ public IAndroidTarget[] getTargets() {
+ return mTargets;
+ }
+
+ /**
+ * Returns a target from a hash that was generated by {@link IAndroidTarget#hashString()}.
+ * @param hash the hash
+ */
+ public IAndroidTarget getTargetFromHashString(String hash) {
+ if (hash != null) {
+ for (IAndroidTarget target : mTargets) {
+ if (hash.equals(target.hashString())) {
+ return target;
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ private SdkManager(String sdkLocation) {
+ mSdkLocation = sdkLocation;
+ }
+
+ private void setTargets(IAndroidTarget[] targets) {
+ mTargets = targets;
+ }
+
+ /**
+ * Loads the Platforms from the SDK.
+ * @param list the list to fill with the platforms.
+ * @param log the ISdkLog object receiving warning/error from the parsing.
+ */
+ private void loadPlatforms(ArrayList<IAndroidTarget> list, ISdkLog log) {
+ File platformFolder = new File(mSdkLocation, SdkConstants.FD_PLATFORMS);
+ if (platformFolder.isDirectory()) {
+ File[] platforms = platformFolder.listFiles();
+
+ for (File platform : platforms) {
+ if (platform.isDirectory()) {
+ PlatformTarget target = loadPlatform(platform, log);
+ if (target != null) {
+ list.add(target);
+ }
+ } else if (log != null) {
+ log.warning("Ignoring platform '%1$s', not a folder.", platform.getName());
+ }
+ }
+
+ return;
+ }
+
+ String message = null;
+ if (platformFolder.exists() == false) {
+ message = "%s is missing.";
+ } else {
+ message = "%s is not a folder.";
+ }
+
+ throw new IllegalArgumentException(String.format(message,
+ platformFolder.getAbsolutePath()));
+ }
+
+ /**
+ * Loads a specific Platform at a given location.
+ * @param platform the location of the platform.
+ * @param log the ISdkLog object receiving warning/error from the parsing.
+ */
+ private PlatformTarget loadPlatform(File platform, ISdkLog log) {
+ File buildProp = new File(platform, SdkConstants.FN_BUILD_PROP);
+
+ if (buildProp.isFile()) {
+ Map<String, String> map = parsePropertyFile(buildProp, log);
+
+ if (map != null) {
+ // look for some specific values in the map.
+ try {
+ String apiNumber = map.get(PROP_VERSION_SDK);
+ String apiName = map.get(PROP_VERSION_RELEASE);
+ if (apiNumber != null && apiName != null) {
+ // create the target.
+ PlatformTarget target = new PlatformTarget(
+ platform.getAbsolutePath(),
+ map,
+ Integer.parseInt(apiNumber),
+ apiName);
+
+ // need to parse the skins.
+ String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS));
+ target.setSkins(skins);
+
+ return target;
+ }
+ } catch (NumberFormatException e) {
+ // looks like apiNumber does not parse to a number.
+ // Ignore this platform.
+ if (log != null) {
+ log.error("Ignoring platform '%1$s': %2$s is not a valid number in %3$s.",
+ platform.getName(), PROP_VERSION_SDK, SdkConstants.FN_BUILD_PROP);
+ }
+ }
+ }
+ } else if (log != null) {
+ log.error("Ignoring platform '%1$s': %2$s is missing.", platform.getName(),
+ SdkConstants.FN_BUILD_PROP);
+ }
+
+ return null;
+ }
+
+ /**
+ * Loads the Add-on from the SDK.
+ * @param list the list to fill with the add-ons.
+ * @param log the ISdkLog object receiving warning/error from the parsing.
+ */
+ private void loadAddOns(ArrayList<IAndroidTarget> list, ISdkLog log) {
+ File addonFolder = new File(mSdkLocation, SdkConstants.FD_ADDONS);
+ if (addonFolder.isDirectory()) {
+ File[] addons = addonFolder.listFiles();
+
+ for (File addon : addons) {
+ if (addon.isDirectory()) {
+ AddOnTarget target = loadAddon(addon, list, log);
+ if (target != null) {
+ list.add(target);
+ }
+ } else if (log != null) {
+ log.warning("Ignoring add-on '%1$s', not a folder.", addon.getName());
+ }
+ }
+
+ return;
+ }
+
+ String message = null;
+ if (addonFolder.exists() == false) {
+ message = "%s is missing.";
+ } else {
+ message = "%s is not a folder.";
+ }
+
+ throw new IllegalArgumentException(String.format(message,
+ addonFolder.getAbsolutePath()));
+ }
+
+ /**
+ * Loads a specific Add-on at a given location.
+ * @param addon the location of the addon.
+ * @param list
+ * @param log
+ */
+ private AddOnTarget loadAddon(File addon, ArrayList<IAndroidTarget> list, ISdkLog log) {
+ File addOnManifest = new File(addon, SdkConstants.FN_MANIFEST_INI);
+
+ if (addOnManifest.isFile()) {
+ Map<String, String> map = parsePropertyFile(addOnManifest, log);
+
+ if (map != null) {
+ // look for some specific values in the map.
+ // we require name, vendor, and api
+ String name = map.get(ADDON_NAME);
+ if (name == null) {
+ displayAddonManifestError(log, addon.getName(), ADDON_NAME);
+ return null;
+ }
+
+ String vendor = map.get(ADDON_VENDOR);
+ if (vendor == null) {
+ displayAddonManifestError(log, addon.getName(), ADDON_VENDOR);
+ return null;
+ }
+
+ String api = map.get(ADDON_API);
+ PlatformTarget baseTarget = null;
+ if (api == null) {
+ displayAddonManifestError(log, addon.getName(), ADDON_API);
+ return null;
+ } else {
+ try {
+ int apiValue = Integer.parseInt(api);
+ for (IAndroidTarget target : list) {
+ if (target.isPlatform() &&
+ target.getApiVersionNumber() == apiValue) {
+ baseTarget = (PlatformTarget)target;
+ break;
+ }
+ }
+
+ if (baseTarget == null) {
+ if (log != null) {
+ log.error(
+ "Ignoring add-on '%1$s': Unable to find base platform with API level %2$d",
+ addon.getName(), apiValue);
+ }
+
+ return null;
+ }
+ } catch (NumberFormatException e) {
+ // looks like apiNumber does not parse to a number.
+ // Ignore this add-on.
+ if (log != null) {
+ log.error(
+ "Ignoring add-on '%1$s': %2$s is not a valid number in %3$s.",
+ addon.getName(), ADDON_API, SdkConstants.FN_BUILD_PROP);
+ }
+ return null;
+ }
+ }
+
+ // get the optional description
+ String description = map.get(ADDON_DESCRIPTION);
+
+ // get the optional libraries
+ String librariesValue = map.get(ADDON_LIBRARIES);
+
+ // split in the string into the values we care about
+ String[] libraries = librariesValue.split(";");
+ Map<String, String> libMap = null;
+ if (libraries.length > 0) {
+ libMap = new HashMap<String, String>();
+ for (String lib : libraries) {
+ String[] values = lib.split(":");
+ if (values.length == 2) {
+ libMap.put(values[0], values[1]);
+ } else {
+ // TODO: log error
+ }
+ }
+ }
+
+ AddOnTarget target = new AddOnTarget(addon.getAbsolutePath(), name, vendor,
+ description, libMap, baseTarget);
+
+ // need to parse the skins.
+ String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS));
+ target.setSkins(skins);
+
+ return target;
+ }
+ } else if (log != null) {
+ log.error("Ignoring add-on '%1$s': %2$s is missing.", addon.getName(),
+ SdkConstants.FN_MANIFEST_INI);
+ }
+
+ return null;
+ }
+
+ private void displayAddonManifestError(ISdkLog log, String addonName, String valueName) {
+ if (log != null) {
+ log.error("Ignoring add-on '%1$s': '%2$s' is missing from %3$s.",
+ addonName, valueName, SdkConstants.FN_MANIFEST_INI);
+ }
+ }
+
+ /**
+ * Parses a property file and returns
+ * @param buildProp the property file to parse
+ * @param log the ISdkLog object receiving warning/error from the parsing.
+ * @return the map of (key,value) pairs, or null if the parsing failed.
+ */
+ public static Map<String, String> parsePropertyFile(File buildProp, ISdkLog log) {
+ try {
+ FileInputStream fis = new FileInputStream(buildProp);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
+
+ String line = null;
+ Map<String, String> map = new HashMap<String, String>();
+ while ((line = reader.readLine()) != null) {
+ if (line.length() > 0 && line.charAt(0) != '#') {
+
+ Matcher m = PATTERN_PROP.matcher(line);
+ if (m.matches()) {
+ map.put(m.group(1), m.group(2));
+ } else {
+ log.warning("Error parsing '%1$s': \"%2$s\" is not a valid syntax",
+ buildProp.getAbsolutePath(), line);
+ return null;
+ }
+ }
+ }
+
+ return map;
+ } catch (FileNotFoundException e) {
+ // this should not happen since we usually test the file existence before
+ // calling the method.
+ // Return null below.
+ } catch (IOException e) {
+ if (log != null) {
+ log.warning("Error parsing '%1$s': %2$s.", buildProp.getAbsolutePath(),
+ e.getMessage());
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Parses the skin folder and builds the skin list.
+ * @param osPath The path of the skin root folder.
+ */
+ private String[] parseSkinFolder(String osPath) {
+ File skinRootFolder = new File(osPath);
+
+ if (skinRootFolder.isDirectory()) {
+ ArrayList<String> skinList = new ArrayList<String>();
+
+ File[] files = skinRootFolder.listFiles();
+
+ for (File skinFolder : files) {
+ if (skinFolder.isDirectory()) {
+ // check for layout file
+ File layout = new File(skinFolder, SdkConstants.FN_SKIN_LAYOUT);
+
+ if (layout.isFile()) {
+ // for now we don't parse the content of the layout and
+ // simply add the directory to the list.
+ skinList.add(skinFolder.getName());
+ }
+ }
+ }
+
+ return skinList.toArray(new String[skinList.size()]);
+ }
+
+ return new String[0];
+ }
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java
new file mode 100644
index 0000000..c0c1fe3
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008 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.project;
+
+import com.android.sdklib.SdkManager;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Class to load and save project properties for both ADT and Ant-based build.
+ *
+ */
+public final class ProjectProperties {
+ /** The property name for the project target */
+ public final static String PROPERTY_TARGET = "target";
+ public final static String PROPERTY_SDK = "sdk-folder";
+
+ private final static String PROPERTIES_FILE = "default.properties";
+
+ private final static String PROP_HEADER =
+ "# This file is automatically generated by Android Tools.\n" +
+ "# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n" +
+ "# For customized properties when using Ant, set new values\n" +
+ "# in a \"build.properties\" file.\n\n";
+
+ private final static Map<String, String> COMMENT_MAP = new HashMap<String, String>();
+ static {
+ COMMENT_MAP.put(PROPERTY_TARGET, "# Project target.\n");
+ COMMENT_MAP.put(PROPERTY_SDK, "# location of the SDK. Only used by Ant.\n");
+ }
+
+ private final String mProjectFolderOsPath;
+ private final Map<String, String> mProperties;
+
+ /**
+ * Loads a project properties file and return a {@link ProjectProperties} object
+ * containing the properties
+ * @param projectFolderOsPath the project folder.
+ */
+ public static ProjectProperties load(String projectFolderOsPath) {
+ File projectFolder = new File(projectFolderOsPath);
+ if (projectFolder.isDirectory()) {
+ File defaultFile = new File(projectFolder, PROPERTIES_FILE);
+ if (defaultFile.isFile()) {
+ Map<String, String> map = SdkManager.parsePropertyFile(defaultFile, null /* log */);
+ if (map != null) {
+ return new ProjectProperties(projectFolderOsPath, map);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new project properties file, with no properties.
+ * <p/>The file is not created until {@link #save()} is called.
+ * @param projectFolderOsPath the project folder.
+ */
+ public static ProjectProperties create(String projectFolderOsPath) {
+ // create and return a ProjectProperties with an empty map.
+ return new ProjectProperties(projectFolderOsPath, new HashMap<String, String>());
+ }
+
+ /**
+ * Sets a new properties. If a property with the same name already exists, it is replaced.
+ * @param name the name of the property.
+ * @param value the value of the property.
+ */
+ public void setProperty(String name, String value) {
+ mProperties.put(name, value);
+ }
+
+ /**
+ * Returns the value of a property.
+ * @param name the name of the property.
+ * @return the property value or null if the property is not set.
+ */
+ public String getProperty(String name) {
+ return mProperties.get(name);
+ }
+
+ /**
+ * Saves the property file.
+ * @throws IOException
+ */
+ public void save() throws IOException {
+ File toSave = new File(mProjectFolderOsPath, PROPERTIES_FILE);
+
+ FileWriter writer = new FileWriter(toSave);
+
+ // write the header
+ writer.write(PROP_HEADER);
+
+ // write the properties.
+ for (Entry<String, String> entry : mProperties.entrySet()) {
+ String comment = COMMENT_MAP.get(entry.getKey());
+ if (comment != null) {
+ writer.write(comment);
+ }
+ writer.write(String.format("%s=%s\n", entry.getKey(), entry.getValue()));
+ }
+
+ // close the file to flush
+ writer.close();
+ }
+
+ /**
+ * Private constructor.
+ * Use {@link #load(String)} or {@link #create(String)} to instantiate.
+ * @param projectFolderOsPath
+ * @param map
+ */
+ private ProjectProperties(String projectFolderOsPath, Map<String, String> map) {
+ mProjectFolderOsPath = projectFolderOsPath;
+ mProperties = map;
+ }
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/HardwareProperties.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/HardwareProperties.java
new file mode 100644
index 0000000..cb2c8c2
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/HardwareProperties.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2008 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.vm;
+
+import com.android.sdklib.ISdkLog;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class HardwareProperties {
+ private final static Pattern PATTERN_PROP = Pattern.compile(
+ "^([a-zA-Z0-9._-]+)\\s*=\\s*(.*)\\s*$");
+
+ private final static String HW_PROP_NAME = "name";
+ private final static String HW_PROP_TYPE = "type";
+ private final static String HW_PROP_DEFAULT = "default";
+ private final static String HW_PROP_ABSTRACT = "abstract";
+ private final static String HW_PROP_DESC = "description";
+
+ public enum ValueType {
+ INTEGER("integer"),
+ BOOLEAN("boolean"),
+ DISKSIZE("diskSize");
+
+ private String mValue;
+
+ ValueType(String value) {
+ mValue = value;
+ }
+
+ public static ValueType getEnum(String value) {
+ for (ValueType type : values()) {
+ if (type.mValue.equals(value)) {
+ return type;
+ }
+ }
+
+ return null;
+ }
+ }
+
+ public static final class HardwareProperty {
+ private String mName;
+ private ValueType mType;
+ /** the string representation of the default value. can be null. */
+ private String mDefault;
+ private String mAbstract;
+ private String mDescription;
+
+ public String getName() {
+ return mName;
+ }
+
+ public ValueType getType() {
+ return mType;
+ }
+
+ public String getDefault() {
+ return mDefault;
+ }
+
+ public String getAbstract() {
+ return mAbstract;
+ }
+
+ public String getDescription() {
+ return mDescription;
+ }
+ }
+
+ /**
+ * Parses the harware definition file.
+ * @param buildProp the property file to parse
+ * @param log the ISdkLog object receiving warning/error from the parsing.
+ * @return the map of (key,value) pairs, or null if the parsing failed.
+ */
+ public static List<HardwareProperty> parseHardwareDefinitions(File file, ISdkLog log) {
+ try {
+ FileInputStream fis = new FileInputStream(file);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
+
+ List<HardwareProperty> map = new ArrayList<HardwareProperty>();
+
+ String line = null;
+ HardwareProperty prop = null;
+ while ((line = reader.readLine()) != null) {
+ if (line.length() > 0 && line.charAt(0) != '#') {
+ Matcher m = PATTERN_PROP.matcher(line);
+ if (m.matches()) {
+ String valueName = m.group(1);
+ String value = m.group(2);
+
+ if (HW_PROP_NAME.equals(valueName)) {
+ prop = new HardwareProperty();
+ prop.mName = value;
+ map.add(prop);
+ }
+
+ if (prop == null) {
+ log.warning("Error parsing '%1$s': missing '%2$s'",
+ file.getAbsolutePath(), HW_PROP_NAME);
+ return null;
+ }
+
+ if (HW_PROP_TYPE.equals(valueName)) {
+ prop.mType = ValueType.getEnum(value);
+ } else if (HW_PROP_DEFAULT.equals(valueName)) {
+ prop.mDefault = value;
+ } else if (HW_PROP_ABSTRACT.equals(valueName)) {
+ prop.mAbstract = value;
+ } else if (HW_PROP_DESC.equals(valueName)) {
+ prop.mDescription = value;
+ }
+ } else {
+ log.warning("Error parsing '%1$s': \"%2$s\" is not a valid syntax",
+ file.getAbsolutePath(), line);
+ return null;
+ }
+ }
+ }
+
+ return map;
+ } catch (FileNotFoundException e) {
+ // this should not happen since we usually test the file existence before
+ // calling the method.
+ // Return null below.
+ } catch (IOException e) {
+ if (log != null) {
+ log.warning("Error parsing '%1$s': %2$s.", file.getAbsolutePath(),
+ e.getMessage());
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java
new file mode 100644
index 0000000..a9f1b17
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2008 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.vm;
+
+import com.android.prefs.AndroidLocation;
+import com.android.prefs.AndroidLocation.AndroidLocationException;
+import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.ISdkLog;
+import com.android.sdklib.SdkConstants;
+import com.android.sdklib.SdkManager;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Virtual Machine manager to access the list of VMs or create new ones.
+ */
+public final class VmManager {
+
+ private final static String VM_INFO_PATH = "path";
+ private final static String VM_INFO_TARGET = "target";
+
+ private final static String IMAGE_USERDATA = "userdata.img";
+ private final static String CONFIG_INI = "config.ini";
+
+ private final static Pattern INI_NAME_PATTERN = Pattern.compile("(.+)\\.ini$",
+ Pattern.CASE_INSENSITIVE);
+
+ public static final class VmInfo {
+ String name;
+ String path;
+ IAndroidTarget target;
+
+ public String getName() {
+ return name;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public IAndroidTarget getTarget() {
+ return target;
+ }
+ }
+
+ private final ArrayList<VmInfo> mVmList = new ArrayList<VmInfo>();
+ private ISdkLog mSdkLog;
+
+ public VmManager(SdkManager sdk, ISdkLog sdkLog) throws AndroidLocationException {
+ mSdkLog = sdkLog;
+ buildVmList(sdk);
+ }
+
+ public VmInfo[] getVms() {
+ return mVmList.toArray(new VmInfo[mVmList.size()]);
+ }
+
+ /**
+ * Creates a new VM.
+ * @param parentFolder the folder to contain the VM. A new folder will be created in this
+ * folder with the name of the VM
+ * @param name the name of the VM
+ * @param target the target of the VM
+ * @param skinName the name of the skin. Can be null.
+ * @param sdcardPath the path to the sdCard. Can be null.
+ * @param sdcardSize the size of a local sdcard to create. Can be 0 for no local sdcard.
+ * @param hardwareConfig the hardware setup for the VM
+ */
+ public static void createVm(String parentFolder, String name, IAndroidTarget target,
+ String skinName, String sdcardPath, int sdcardSize, Map<String,String> hardwareConfig,
+ ISdkLog log) {
+
+ // now write the ini file in the vmRoot folder.
+ // get the Android prefs location.
+ try {
+ File rootDirectory = new File(parentFolder);
+ if (rootDirectory.isDirectory() == false) {
+ if (log != null) {
+ log.error("%s does not exists.", parentFolder);
+ }
+ return;
+ }
+
+ File vmFolder = new File(parentFolder, name + ".avm");
+ if (vmFolder.exists()) {
+ if (log != null) {
+ log.error("%s already exists.", vmFolder.getAbsolutePath());
+ }
+ return;
+ }
+
+ // create the vm folder.
+ vmFolder.mkdir();
+
+ HashMap<String, String> values = new HashMap<String, String>();
+
+ // prepare the ini file.
+ String vmRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS;
+ File iniFile = new File(vmRoot, name + ".ini");
+ values.put(VM_INFO_PATH, vmFolder.getAbsolutePath());
+ values.put(VM_INFO_TARGET, target.hashString());
+ createConfigIni(iniFile, values);
+
+ // writes the userdata.img in it.
+ String imagePath = target.getPath(IAndroidTarget.IMAGES);
+ File userdataSrc = new File(imagePath, IMAGE_USERDATA);
+ FileInputStream fis = new FileInputStream(userdataSrc);
+
+ File userdataDest = new File(vmFolder, IMAGE_USERDATA);
+ FileOutputStream fos = new FileOutputStream(userdataDest);
+
+ byte[] buffer = new byte[4096];
+ int count;
+ while ((count = fis.read(buffer)) != -1) {
+ fos.write(buffer, 0, count);
+ }
+
+ fos.close();
+ fis.close();
+
+ // Config file
+ values.clear();
+ if (skinName != null) {
+ values.put("skin", skinName);
+ } else {
+ values.put("skin", SdkConstants.SKIN_DEFAULT);
+ }
+
+ if (sdcardPath != null) {
+ values.put("sdcard", sdcardPath);
+ } else if (sdcardSize != 0) {
+ // TODO: create sdcard image.
+ }
+
+ if (hardwareConfig != null) {
+ values.putAll(hardwareConfig);
+ }
+
+ File configIniFile = new File(vmFolder, CONFIG_INI);
+ createConfigIni(configIniFile, values);
+
+ if (target.isPlatform()) {
+ System.out.println(String.format(
+ "Created VM '%s' based on %s", name, target.getName()));
+ } else {
+ System.out.println(String.format(
+ "Created VM '%s' based on %s (%s)", name, target.getName(),
+ target.getVendor()));
+ }
+ } catch (AndroidLocationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private void buildVmList(SdkManager sdk) throws AndroidLocationException {
+ // get the Android prefs location.
+ String vmRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS;
+
+ // ensure folder validity.
+ File folder = new File(vmRoot);
+ if (folder.isFile()) {
+ throw new AndroidLocationException(String.format("%s is not a valid folder.", vmRoot));
+ } else if (folder.exists() == false) {
+ // folder is not there, we create it and return
+ folder.mkdirs();
+ return;
+ }
+
+ File[] vms = folder.listFiles(new FilenameFilter() {
+ public boolean accept(File parent, String name) {
+ if (INI_NAME_PATTERN.matcher(name).matches()) {
+ // check it's a file and not a folder
+ return new File(parent, name).isFile();
+ }
+
+ return false;
+ }
+ });
+
+ for (File vm : vms) {
+ VmInfo info = parseVmInfo(vm, sdk);
+ if (info != null) {
+ mVmList.add(info);
+ }
+ }
+ }
+
+ private VmInfo parseVmInfo(File path, SdkManager sdk) {
+ Map<String, String> map = SdkManager.parsePropertyFile(path, mSdkLog);
+
+ String vmPath = map.get(VM_INFO_PATH);
+ if (vmPath == null) {
+ return null;
+ }
+
+ String targetHash = map.get(VM_INFO_TARGET);
+ if (targetHash == null) {
+ return null;
+ }
+
+ IAndroidTarget target = sdk.getTargetFromHashString(targetHash);
+ if (target == null) {
+ return null;
+ }
+
+ VmInfo info = new VmInfo();
+ Matcher matcher = INI_NAME_PATTERN.matcher(path.getName());
+ if (matcher.matches()) {
+ info.name = matcher.group(1);
+ } else {
+ info.name = path.getName(); // really this should not happen.
+ }
+ info.path = vmPath;
+ info.target = target;
+
+ return info;
+ }
+
+ private static void createConfigIni(File iniFile, Map<String, String> values)
+ throws IOException {
+ FileWriter writer = new FileWriter(iniFile);
+
+ for (Entry<String, String> entry : values.entrySet()) {
+ writer.write(String.format("%s=%s\n", entry.getKey(), entry.getValue()));
+ }
+ writer.close();
+
+ }
+}
diff --git a/sdkmanager/libs/sdkuilib/Android.mk b/sdkmanager/libs/sdkuilib/Android.mk
new file mode 100644
index 0000000..8e0bc23
--- /dev/null
+++ b/sdkmanager/libs/sdkuilib/Android.mk
@@ -0,0 +1,4 @@
+# Copyright 2008 The Android Open Source Project
+#
+SDKUILIB_LOCAL_DIR := $(call my-dir)
+include $(SDKUILIB_LOCAL_DIR)/src/Android.mk
diff --git a/sdkmanager/libs/sdkuilib/README b/sdkmanager/libs/sdkuilib/README
new file mode 100644
index 0000000..d66b84a
--- /dev/null
+++ b/sdkmanager/libs/sdkuilib/README
@@ -0,0 +1,11 @@
+Using the Eclipse projects for ddmuilib.
+
+ddmuilib requires SWT to compile.
+
+SWT is available in the depot under prebuild/<platform>/swt
+
+Because the build path cannot contain relative path that are not inside the project directory,
+the .classpath file references a user library called ANDROID_SWT.
+
+In order to compile the project, make a user library called ANDROID_SWT containing the jar
+available at prebuild/<platform>/swt. \ No newline at end of file
diff --git a/sdkmanager/libs/sdkuilib/src/Android.mk b/sdkmanager/libs/sdkuilib/src/Android.mk
new file mode 100644
index 0000000..2d3c774
--- /dev/null
+++ b/sdkmanager/libs/sdkuilib/src/Android.mk
@@ -0,0 +1,21 @@
+# Copyright 2008 The Android Open Source Project
+#
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+# no resources yet.
+# LOCAL_JAVA_RESOURCE_DIRS := resources
+
+LOCAL_JAVA_LIBRARIES := \
+ sdklib \
+ swt \
+ org.eclipse.jface_3.2.0.I20060605-1400 \
+ org.eclipse.equinox.common_3.2.0.v20060603 \
+ org.eclipse.core.commands_3.2.0.I20060605-1400
+
+LOCAL_MODULE := sdkuilib
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/SdkTargetSelector.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/SdkTargetSelector.java
new file mode 100644
index 0000000..ddc492e
--- /dev/null
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/SdkTargetSelector.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sdkuilib;
+
+import com.android.sdklib.IAndroidTarget;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+
+import java.util.ArrayList;
+
+
+/**
+ * The SDK target selector is a table that is added to the given parent composite.
+ */
+public class SdkTargetSelector {
+
+ private final IAndroidTarget[] mTargets;
+ private final boolean mAllowMultipleSelection;
+ private SelectionListener mSelectionListener;
+ private Table mTable;
+ private Label mDescription;
+
+ public SdkTargetSelector(Composite parent, IAndroidTarget[] targets,
+ boolean allowMultipleSelection) {
+ mTargets = targets;
+
+ // Layout has 1 column
+ Composite group = new Composite(parent, SWT.NONE);
+ group.setLayout(new GridLayout());
+ group.setLayoutData(new GridData(GridData.FILL_BOTH));
+ group.setFont(parent.getFont());
+
+ mAllowMultipleSelection = allowMultipleSelection;
+ mTable = new Table(group, SWT.CHECK | SWT.FULL_SELECTION | SWT.SINGLE | SWT.BORDER);
+ mTable.setHeaderVisible(true);
+ mTable.setLinesVisible(false);
+
+ GridData data = new GridData();
+ data.grabExcessVerticalSpace = true;
+ data.grabExcessHorizontalSpace = true;
+ data.horizontalAlignment = GridData.FILL;
+ data.verticalAlignment = GridData.FILL;
+ mTable.setLayoutData(data);
+
+ mDescription = new Label(group, SWT.WRAP);
+ mDescription.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ // create the table columns
+ final TableColumn column0 = new TableColumn(mTable, SWT.NONE);
+ column0.setText("SDK Target");
+ final TableColumn column1 = new TableColumn(mTable, SWT.NONE);
+ column1.setText("Vendor");
+ final TableColumn column2 = new TableColumn(mTable, SWT.NONE);
+ column2.setText("API Level");
+
+ adjustColumnsWidth(mTable, column0, column1, column2);
+ setupSelectionListener(mTable);
+ fillTable(mTable);
+ setupTooltip(mTable);
+ }
+
+ /**
+ * Sets a selection listener. Set it to null to remove it.
+ * The listener will be called <em>after</em> this table processed its selection
+ * events so that the caller can see the updated state.
+ * <p/>
+ * The event's item contains a {@link TableItem}.
+ * The {@link TableItem#getData()} contains an {@link IAndroidTarget}.
+ * <p/>
+ * It is recommended that the caller uses the {@link #getFirstSelected()} and
+ * {@link #getAllSelected()} methods instead.
+ *
+ * @param selectionListener The new listener or null to remove it.
+ */
+ public void setSelectionListener(SelectionListener selectionListener) {
+ mSelectionListener = selectionListener;
+ }
+
+ /**
+ * Sets the current target selection.
+ * @param target the target to be selection
+ * @return true if the target could be selected, false otherwise.
+ */
+ public boolean setSelection(IAndroidTarget target) {
+ boolean found = false;
+ for (TableItem i : mTable.getItems()) {
+ if ((IAndroidTarget) i.getData() == target) {
+ found = true;
+ i.setChecked(true);
+ } else {
+ i.setChecked(false);
+ }
+ }
+
+ return found;
+ }
+
+ /**
+ * Returns all selected items.
+ * This is useful when the table is in multiple-selection mode.
+ *
+ * @see #getFirstSelected()
+ * @return An array of selected items. The list can be empty but not null.
+ */
+ public IAndroidTarget[] getAllSelected() {
+ ArrayList<IAndroidTarget> list = new ArrayList<IAndroidTarget>();
+ for (TableItem i : mTable.getItems()) {
+ if (i.getChecked()) {
+ list.add((IAndroidTarget) i.getData());
+ }
+ }
+ return list.toArray(new IAndroidTarget[list.size()]);
+ }
+
+ /**
+ * Returns the first selected item.
+ * This is useful when the table is in single-selection mode.
+ *
+ * @see #getAllSelected()
+ * @return The first selected item or null.
+ */
+ public IAndroidTarget getFirstSelected() {
+ for (TableItem i : mTable.getItems()) {
+ if (i.getChecked()) {
+ return (IAndroidTarget) i.getData();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 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(final Table table,
+ final TableColumn column0,
+ final TableColumn column1,
+ final TableColumn column2) {
+ // Add a listener to resize the column to the full width of the table
+ table.addControlListener(new ControlAdapter() {
+ @Override
+ public void controlResized(ControlEvent e) {
+ Rectangle r = table.getClientArea();
+ column0.setWidth(r.width * 3 / 10); // 30%
+ column1.setWidth(r.width * 5 / 10); // 50%
+ column2.setWidth(r.width * 2 / 10); // 20%
+ }
+ });
+ }
+
+
+ /**
+ * Creates a selection listener that will check or uncheck the whole line when
+ * double-clicked (aka "the default selection").
+ */
+ private void setupSelectionListener(final Table table) {
+ // Add a selection listener that will check/uncheck items when they are double-clicked
+ table.addSelectionListener(new SelectionListener() {
+ /** Default selection means double-click on "most" platforms */
+ public void widgetDefaultSelected(SelectionEvent e) {
+ if (e.item instanceof TableItem) {
+ TableItem i = (TableItem) e.item;
+ i.setChecked(!i.getChecked());
+ enforceSingleSelection(i);
+ updateDescription(i);
+ }
+
+ if (mSelectionListener != null) {
+ mSelectionListener.widgetDefaultSelected(e);
+ }
+ }
+
+ public void widgetSelected(SelectionEvent e) {
+ if (e.item instanceof TableItem) {
+ TableItem i = (TableItem) e.item;
+ enforceSingleSelection(i);
+ updateDescription(i);
+ }
+
+ if (mSelectionListener != null) {
+ mSelectionListener.widgetSelected(e);
+ }
+ }
+
+ /**
+ * If we're not in multiple selection mode, uncheck all other
+ * items when this one is selected.
+ */
+ private void enforceSingleSelection(TableItem item) {
+ if (!mAllowMultipleSelection && item.getChecked()) {
+ Table parentTable = item.getParent();
+ for (TableItem i2 : parentTable.getItems()) {
+ if (i2 != item && i2.getChecked()) {
+ i2.setChecked(false);
+ }
+ }
+ }
+ }
+ });
+ }
+
+
+ /**
+ * Fills the table with all SDK targets.
+ * The table columns are:
+ * <ul>
+ * <li>column 0: sdk name
+ * <li>column 1: sdk vendor
+ * <li>column 2: sdk api name
+ * </ul>
+ */
+ private void fillTable(final Table table) {
+ if (mTargets != null && mTargets.length > 0) {
+ table.setEnabled(true);
+ for (IAndroidTarget target : mTargets) {
+ TableItem item = new TableItem(table, SWT.NONE);
+ item.setData(target);
+ item.setText(0, target.getName());
+ item.setText(1, target.getVendor());
+ item.setText(2, target.getApiVersionName());
+ }
+ } else {
+ table.setEnabled(false);
+ TableItem item = new TableItem(table, SWT.NONE);
+ item.setData(null);
+ item.setText(0, "--");
+ item.setText(1, "No target available");
+ item.setText(2, "--");
+ }
+ }
+
+ /**
+ * Sets up a tooltip that displays the current item description.
+ * <p/>
+ * Displaying a tooltip over the table looks kind of odd here. Instead we actually
+ * display the description in a label under the table.
+ */
+ private void setupTooltip(final Table table) {
+ /*
+ * Reference:
+ * http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet125.java?view=markup
+ */
+
+ final Listener listener = new Listener() {
+ public void handleEvent(Event event) {
+
+ switch(event.type) {
+ case SWT.KeyDown:
+ case SWT.MouseExit:
+ case SWT.MouseDown:
+ return;
+
+ case SWT.MouseHover:
+ updateDescription(table.getItem(new Point(event.x, event.y)));
+ break;
+
+ case SWT.Selection:
+ if (event.item instanceof TableItem) {
+ updateDescription((TableItem) event.item);
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ }
+ };
+
+ table.addListener(SWT.Dispose, listener);
+ table.addListener(SWT.KeyDown, listener);
+ table.addListener(SWT.MouseMove, listener);
+ table.addListener(SWT.MouseHover, listener);
+ }
+
+ /**
+ * Updates the description label with the description of the item's android target, if any.
+ */
+ private void updateDescription(TableItem item) {
+ if (item != null) {
+ Object data = item.getData();
+ if (data instanceof IAndroidTarget) {
+ String newTooltip = ((IAndroidTarget) data).getDescription();
+ mDescription.setText(newTooltip == null ? "" : newTooltip); //$NON-NLS-1$
+ }
+ }
+ }
+}