Merge change 2768 into donut
* changes:
Add an API demo that shows the effets of setting Bitmaps as being purgeable.
diff --git a/emulator/qemud/qemud.c b/emulator/qemud/qemud.c
index c578145..92b2a2b 100644
--- a/emulator/qemud/qemud.c
+++ b/emulator/qemud/qemud.c
@@ -849,6 +849,10 @@
static void
fdhandler_shutdown( FDHandler* f )
{
+ /* prevent later fdhandler_close() to
+ * call the receiver's close.
+ */
+ f->receiver->close = NULL;
if (f->out_first != NULL && !f->closing)
{
@@ -856,9 +860,6 @@
f->closing = 1;
fdhandler_remove(f);
fdhandler_prepend(f, &f->list->closing);
-
- /* notify the receiver that we're closing */
- receiver_close(f->receiver);
return;
}
diff --git a/emulator/sensors/sensors_qemu.c b/emulator/sensors/sensors_qemu.c
index 85a5af4..0cc636a 100644
--- a/emulator/sensors/sensors_qemu.c
+++ b/emulator/sensors/sensors_qemu.c
@@ -34,6 +34,7 @@
#include <errno.h>
#include <string.h>
#include <cutils/log.h>
+#include <cutils/native_handle.h>
#include <cutils/sockets.h>
#include <hardware/sensors.h>
@@ -123,16 +124,19 @@
/* this must return a file descriptor that will be used to read
* the sensors data (it is passed to data__data_open() below
*/
-static int
+static native_handle_t*
control__open_data_source(struct sensors_control_device_t *dev)
{
SensorControl* ctl = (void*)dev;
+ native_handle_t* handle;
if (ctl->fd < 0) {
ctl->fd = qemud_channel_open(SENSORS_SERVICE_NAME);
}
D("%s: fd=%d", __FUNCTION__, ctl->fd);
- return ctl->fd;
+ handle = native_handle_create(1, 0);
+ handle->data[0] = ctl->fd;
+ return handle;
}
static int
@@ -244,7 +248,7 @@
}
static int
-data__data_open(struct sensors_data_device_t *dev, int fd)
+data__data_open(struct sensors_data_device_t *dev, native_handle_t* handle)
{
SensorData* data = (void*)dev;
int i;
@@ -258,7 +262,9 @@
data->timeStart = 0;
data->timeOffset = 0;
- data->events_fd = dup(fd);
+ data->events_fd = dup(handle->data[0]);
+ native_handle_close(handle);
+ native_handle_delete(handle);
return 0;
}
diff --git a/emulator/tools/Android.mk b/emulator/tools/Android.mk
new file mode 100644
index 0000000..c9d9613
--- /dev/null
+++ b/emulator/tools/Android.mk
@@ -0,0 +1,36 @@
+# 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.
+
+# this file is used to build emulator-specific program tools
+# that should only run in the emulator.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+ifneq ($(TARGET_PRODUCT),sim)
+
+# The 'qemu-props' program is run from /system/etc/init.goldfish.rc
+# to setup various system properties sent by the emulator program.
+#
+include $(CLEAR_VARS)
+LOCAL_MODULE := qemu-props
+LOCAL_SRC_FILES := qemu-props.c
+LOCAL_SHARED_LIBRARIES := libcutils
+# we don't want this in 'user' builds which don't have
+# emulator-specific binaries.
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_EXECUTABLE)
+
+endif # TARGET_PRODUCT != sim
+
diff --git a/emulator/tools/qemu-props.c b/emulator/tools/qemu-props.c
new file mode 100644
index 0000000..09105fc
--- /dev/null
+++ b/emulator/tools/qemu-props.c
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+/* this program is used to read a set of system properties and their values
+ * from the emulator program and set them in the currently-running emulated
+ * system. It does so by connecting to the 'boot-properties' qemud service.
+ *
+ * This program should be run as root and called from
+ * /system/etc/init.goldfish.rc exclusively.
+ */
+
+#define LOG_TAG "qemu-props"
+
+#define DEBUG 1
+
+#if DEBUG
+# include <cutils/log.h>
+# define DD(...) LOGI(__VA_ARGS__)
+#else
+# define DD(...) ((void)0)
+#endif
+
+#include <cutils/properties.h>
+#include <unistd.h>
+#include <hardware/qemud.h>
+
+/* Name of the qemud service we want to connect to.
+ */
+#define QEMUD_SERVICE "boot-properties"
+
+#define MAX_TRIES 5
+
+int main(void)
+{
+ int qemud_fd, count = 0;
+
+ /* try to connect to the qemud service */
+ {
+ int tries = MAX_TRIES;
+
+ while (1) {
+ qemud_fd = qemud_channel_open( "boot-properties" );
+ if (qemud_fd >= 0)
+ break;
+
+ if (--tries <= 0) {
+ DD("Could not connect after too many tries. Aborting");
+ return 1;
+ }
+
+ DD("waiting 1s to wait for qemud.");
+ sleep(1);
+ }
+ }
+
+ DD("connected to '%s' qemud service.", QEMUD_SERVICE);
+
+ /* send the 'list' command to the service */
+ if (qemud_channel_send(qemud_fd, "list", -1) < 0) {
+ DD("could not send command to '%s' service", QEMUD_SERVICE);
+ return 1;
+ }
+
+ /* read each system property as a single line from the service,
+ * until exhaustion.
+ */
+ for (;;)
+ {
+#define BUFF_SIZE (PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 2)
+
+ char* q;
+ char temp[BUFF_SIZE];
+ int len = qemud_channel_recv(qemud_fd, temp, sizeof temp - 1);
+
+ if (len < 0 || len > BUFF_SIZE-1)
+ break;
+
+ temp[len] = '\0'; /* zero-terminate string */
+
+ DD("received: %.*s", len, temp);
+
+ /* separate propery name from value */
+ q = strchr(temp, '=');
+ if (q == NULL) {
+ DD("invalid format, ignored.");
+ continue;
+ }
+ *q++ = '\0';
+
+ if (property_set(temp, q) < 0) {
+ DD("could not set property '%s' to '%s'", temp, q);
+ } else {
+ count += 1;
+ }
+ }
+
+ /* finally, close the channel and exit */
+ close(qemud_fd);
+ DD("exiting (%d properties set).", count);
+ return 0;
+}
diff --git a/ide/eclipse/.classpath b/ide/eclipse/.classpath
index f4d2cee..281349b 100644
--- a/ide/eclipse/.classpath
+++ b/ide/eclipse/.classpath
@@ -48,6 +48,7 @@
<classpathentry kind="src" path="frameworks/base/services/java"/>
<classpathentry kind="src" path="frameworks/base/telephony/java"/>
<classpathentry kind="src" path="frameworks/base/test-runner"/>
+ <classpathentry kind="src" path="frameworks/base/tts/java"/>
<classpathentry kind="src" path="frameworks/base/wifi/java"/>
<classpathentry kind="src" path="frameworks/policies/base/phone"/>
<classpathentry kind="src" path="development/samples/ApiDemos/src"/>
@@ -102,6 +103,7 @@
<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/location/java"/>
<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java"/>
<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java"/>
+ <classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/tts/java"/>
<classpathentry kind="src" path="out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/wifi/java"/>
<classpathentry kind="src" path="out/target/common/R"/>
<classpathentry kind="src" path="external/tagsoup/src"/>
diff --git a/ndk/README.TXT b/ndk/README.TXT
index 56299c6..4c5ff7f 100644
--- a/ndk/README.TXT
+++ b/ndk/README.TXT
@@ -9,6 +9,10 @@
in docs/OVERVIEW.TXT. Please read this document as it contains crucial
information for correct usage.
+See docs/STABLE-APIS.TXT for the list of frozen binary APIs exposed by
+this NDK, as well as the corresponding system image versions that support
+them.
+
Before using the NDK, you will need to follow the steps described by
docs/INSTALL.TXT which lists the NDK pre-requisites and the steps needed
to set it up properly on your machine.
@@ -17,8 +21,10 @@
note that the NDK is *not* a good way to write non-JNI native code for the
Android platform.
-The document docs/ROADMAP.TXT gives a tentative roadmap for upcoming
-NDK features and improvements.
+See docs/HOWTO.TXT for a few useful tips and tricks when using the NDK.
+
+See docs/SYSTEM-ISSUES.TXT for a list of important issues related to
+the Android system images that all NDK developers should be aware of.
Finally, discussions related to the Android NDK happen on the public
"android-ndk" forum located at the following address:
diff --git a/ndk/apps/hello-jni/project/libs/armeabi/.gitignore b/ndk/apps/hello-jni/project/libs/armeabi/.gitignore
new file mode 100644
index 0000000..bd01364
--- /dev/null
+++ b/ndk/apps/hello-jni/project/libs/armeabi/.gitignore
@@ -0,0 +1 @@
+lib*.so
diff --git a/ndk/apps/two-libs/project/libs/armeabi/.gitignore b/ndk/apps/two-libs/project/libs/armeabi/.gitignore
new file mode 100644
index 0000000..bd01364
--- /dev/null
+++ b/ndk/apps/two-libs/project/libs/armeabi/.gitignore
@@ -0,0 +1 @@
+lib*.so
diff --git a/ndk/build/core/build-binary.mk b/ndk/build/core/build-binary.mk
index 6566fec..1446a7d 100644
--- a/ndk/build/core/build-binary.mk
+++ b/ndk/build/core/build-binary.mk
@@ -29,6 +29,10 @@
# list of generated object files
LOCAL_OBJECTS :=
+# always define ANDROID when building binaries
+#
+LOCAL_CFLAGS := -DANDROID $(LOCAL_CFLAGS)
+
#
# Add the default system shared libraries to the build
#
diff --git a/ndk/build/core/definitions.mk b/ndk/build/core/definitions.mk
index 4135faa..1a425de 100644
--- a/ndk/build/core/definitions.mk
+++ b/ndk/build/core/definitions.mk
@@ -370,7 +370,6 @@
$$(_OBJ): PRIVATE_CFLAGS := $$($$(my)CFLAGS) \
$$($$(my)_$(LOCAL_ARM_MODE)_$(LOCAL_BUILD_MODE)_CFLAGS) \
-I$$(LOCAL_PATH) \
- -I$$(OBJS_DIR) \
$$(LOCAL_CFLAGS) \
$$(NDK_APP_CPPFLAGS) \
$$(NDK_APP_CFLAGS) \
@@ -430,7 +429,6 @@
$$(_OBJ): PRIVATE_CXXFLAGS := $$($$(my)CXXFLAGS) \
$$($$(my)_$(LOCAL_ARM_MODE)_$(LOCAL_BUILD_MODE)_CFLAGS) \
-I$$(LOCAL_PATH) \
- -I$$(OBJS_DIR) \
$$(LOCAL_CFLAGS) \
$$(NDK_APP_CPPFLAGS) \
$$(NDK_APP_CXXFLAGS) \
diff --git a/ndk/build/host-setup.sh b/ndk/build/host-setup.sh
index 6926f1b..e94944e 100755
--- a/ndk/build/host-setup.sh
+++ b/ndk/build/host-setup.sh
@@ -54,6 +54,7 @@
echo "Detecting host toolchain."
echo ""
+force_32bit_binaries
setup_toolchain
create_config_mk
diff --git a/ndk/build/platforms/android-1.5/arch-arm/usr/include/android/log.h b/ndk/build/platforms/android-1.5/arch-arm/usr/include/android/log.h
new file mode 120000
index 0000000..da91a66
--- /dev/null
+++ b/ndk/build/platforms/android-1.5/arch-arm/usr/include/android/log.h
@@ -0,0 +1 @@
+../../../../common/include/android/log.h
\ No newline at end of file
diff --git a/ndk/build/platforms/android-1.5/arch-arm/usr/lib/liblog.so b/ndk/build/platforms/android-1.5/arch-arm/usr/lib/liblog.so
new file mode 100644
index 0000000..92bf1a7
--- /dev/null
+++ b/ndk/build/platforms/android-1.5/arch-arm/usr/lib/liblog.so
Binary files differ
diff --git a/ndk/build/platforms/android-1.5/common/include/android/log.h b/ndk/build/platforms/android-1.5/common/include/android/log.h
new file mode 100644
index 0000000..0ea4c29
--- /dev/null
+++ b/ndk/build/platforms/android-1.5/common/include/android/log.h
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_LOG_H
+#define _ANDROID_LOG_H
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ * This file is part of Android's set of stable system headers
+ * exposed by the Android NDK (Native Development Kit) since
+ * platform release 1.5
+ *
+ * Third-party source AND binary code relies on the definitions
+ * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+/*
+ * Support routines to send messages to the Android in-kernel log buffer,
+ * which can later be accessed through the 'logcat' utility.
+ *
+ * Each log message must have
+ * - a priority
+ * - a log tag
+ * - some text
+ *
+ * The tag normally corresponds to the component that emits the log message,
+ * and should be reasonably small.
+ *
+ * Log message text may be truncated to less than an implementation-specific
+ * limit (e.g. 1023 characters max).
+ *
+ * Note that a newline character ("\n") will be appended automatically to your
+ * log message, if not already there. It is not possible to send several messages
+ * and have them appear on a single line in logcat.
+ *
+ * PLEASE USE LOGS WITH MODERATION:
+ *
+ * - Sending log messages eats CPU and slow down your application and the
+ * system.
+ *
+ * - The circular log buffer is pretty small (<64KB), sending many messages
+ * might push off other important log messages from the rest of the system.
+ *
+ * - In release builds, only send log messages to account for exceptional
+ * conditions.
+ *
+ * NOTE: These functions MUST be implemented by /system/lib/liblog.so
+ */
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Android log priority values, in ascending priority order.
+ */
+typedef enum android_LogPriority {
+ ANDROID_LOG_UNKNOWN = 0,
+ ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
+ ANDROID_LOG_VERBOSE,
+ ANDROID_LOG_DEBUG,
+ ANDROID_LOG_INFO,
+ ANDROID_LOG_WARN,
+ ANDROID_LOG_ERROR,
+ ANDROID_LOG_FATAL,
+ ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
+} android_LogPriority;
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_write(int prio, const char *tag, const char *text);
+
+/*
+ * Send a formatted string to the log, used like printf(fmt,...)
+ */
+int __android_log_print(int prio, const char *tag, const char *fmt, ...)
+#if defined(__GNUC__)
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ ;
+
+/*
+ * A variant of __android_log_print() that takes a va_list to list
+ * additional parameters.
+ */
+int __android_log_vprint(int prio, const char *tag,
+ const char *fmt, va_list ap);
+
+/*
+ * Log an assertion failure and SIGTRAP the process to have a chance
+ * to inspect it, if a debugger is attached. This uses the FATAL priority.
+ */
+void __android_log_assert(const char *cond, const char *tag,
+ const char *fmt, ...)
+#if defined(__GNUC__)
+ __attribute__ ((noreturn))
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+ ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ANDROID_LOG_H */
diff --git a/ndk/build/tools/build-toolchain.sh b/ndk/build/tools/build-toolchain.sh
index 75de8f9..42f7276 100755
--- a/ndk/build/tools/build-toolchain.sh
+++ b/ndk/build/tools/build-toolchain.sh
@@ -34,6 +34,7 @@
OPTION_PLATFORM=
OPTION_FORCE_32=no
OPTION_REBUILD=no
+
VERBOSE=no
for opt do
optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
@@ -73,9 +74,7 @@
done
if [ $OPTION_HELP = "yes" ] ; then
- echo "Collect files from an Android build tree and assembles a sysroot"
- echo "suitable for building a standalone toolchain or be used by the"
- echo "Android NDK."
+ echo "Rebuild the prebuilt binaries for the Android NDK toolchain."
echo ""
echo "options:"
echo ""
@@ -90,27 +89,14 @@
exit 0
fi
-# some Linux platforms report 64-bit while they have a 32-bit userland
-# so check that the compiler generates 32-bit binaries
-# if it does, call force_32bit_binaries to change the value of $HOST_TAG
-#
-# note that this also changes HOST_CFLAGS and HOST_LDFLAGS, however, there
-# is no way for the configure script in the toolchain to get these properly.
-#
-if [ $HOST_TAG = linux-x86_64 ] ; then
- setup_toolchain
- cat >$TMPC <<EOF
-int main(void)
-{
- return 0;
-}
-EOF
- compile_exec_run
- readelf -h $TMPE | grep -q -e "ELF32"
- if [ $? = 0 ] ; then
- force_32bit_binaries
- fi
-fi
+# Force generation of 32-bit binaries on 64-bit systems
+case $HOST_TAG in
+ *-x86_64)
+ HOST_CFLAGS="$HOST_CFLAGS -m32"
+ HOST_LDFLAGS="$HOST_LDFLAGS -m32"
+ force_32bit_binaries # to modify HOST_TAG and others
+ ;;
+esac
TMPLOG=/tmp/android-toolchain-build-$$.log
rm -rf $TMPLOG
@@ -305,6 +291,7 @@
echo "ERROR: Invalid MD5 Sum for $PACKAGE_TARBALL"
echo " Expected $PKGSUM"
echo " Computed $SUM"
+ echo "You might want to use the --force-download option."
exit 2
fi
@@ -378,7 +365,8 @@
echo "Configure: toolchain build"
mkdir -p $TOOLCHAIN_BUILD &&
cd $TOOLCHAIN_BUILD &&
- CFLAGS="$HOST_CFLAGS" LDFLAGS="$HOST_LDFLAGS" run \
+ export CFLAGS="$HOST_CFLAGS" &&
+ export LDFLAGS="$HOST_LDFLAGS" && run \
$TOOLCHAIN_SRC/configure --target=arm-eabi \
--disable-nls \
--prefix=$TOOLCHAIN_PREFIX \
@@ -394,9 +382,11 @@
# build the toolchain
if ! timestamp_check toolchain build ; then
- echo "Building : toolchain (this can take a long time)."
+ echo "Building : toolchain [this can take a long time]."
cd $TOOLCHAIN_BUILD &&
- CFLAGS="$HOST_CFLAGS" LDFLAGS="$HOST_LDFLAGS" run make -j$JOBS
+ export CFLAGS="$HOST_CFLAGS" &&
+ export LDFLAGS="$HOST_LDFLAGS" &&
+ run make -j$JOBS
if [ $? != 0 ] ; then
echo "Error while building toolchain. See $TMPLOG"
exit 1
@@ -414,8 +404,12 @@
echo "Error while installing toolchain. See $TMPLOG"
exit 1
fi
+ # don't forget to copy the GPL and LGPL license files
+ cp -f $TOOLCHAIN_SRC/COPYING $TOOLCHAIN_SRC/COPYING.LIB $TOOLCHAIN_PREFIX
+ # remove some unneeded files
rm -f $TOOLCHAIN_PREFIX/bin/*-gccbug
rm -rf $TOOLCHAIN_PREFIX/man $TOOLCHAIN_PREFIX/info
+ # strip binaries to reduce final package size
strip $TOOLCHAIN_PREFIX/bin/*
strip $TOOLCHAIN_PREFIX/arm-eabi/bin/*
strip $TOOLCHAIN_PREFIX/libexec/gcc/*/*/cc1
@@ -431,6 +425,7 @@
mkdir -p $GDBSERVER_BUILD
cd $GDBSERVER_BUILD &&
CFLAGS="-g -O2 -static -mandroid -I$ANDROID_SYSROOT/usr/include" \
+ LDFLAGS= \
CC="$TOOLCHAIN_PREFIX/bin/arm-eabi-gcc" \
run $TOOLCHAIN_SRC/gdb-6.6/gdb/gdbserver/configure \
--host=arm-eabi-linux \
diff --git a/ndk/build/tools/make-release.sh b/ndk/build/tools/make-release.sh
index b4ab459..a599124 100755
--- a/ndk/build/tools/make-release.sh
+++ b/ndk/build/tools/make-release.sh
@@ -21,7 +21,7 @@
PREBUILT_PREFIX=android-ndk-prebuilt-20090323
# the list of supported host development systems
-PREBUILT_SYSTEMS="linux-x86 linux-x86_64 darwin-x86 windows"
+PREBUILT_SYSTEMS="linux-x86 darwin-x86 windows"
OPTION_HELP=no
diff --git a/ndk/docs/ANDROID-MK.TXT b/ndk/docs/ANDROID-MK.TXT
index fb6bc8e..9ba5388 100644
--- a/ndk/docs/ANDROID-MK.TXT
+++ b/ndk/docs/ANDROID-MK.TXT
@@ -353,6 +353,17 @@
i.e. you should still add them to your application's required modules
in your Application.mk
+LOCAL_LDLIBS
+ The list of additional linker flags to be used when building your
+ module. This is useful to pass the name of specific system libraries
+ with the "-l" prefix. For example, the following will tell the linker
+ to generate a module that links to /system/lib/libz.so at load time:
+
+ LOCAL_LDLIBS := -lz
+
+ See docs/STABLE-APIS.TXT for the list of exposed system libraries you
+ can linked against with this NDK release.
+
LOCAL_ALLOW_UNDEFINED_SYMBOLS
By default, any undefined reference encountered when trying to build
a shared library will result in an "undefined symbol" error. This is a
diff --git a/ndk/docs/CHANGES.TXT b/ndk/docs/CHANGES.TXT
new file mode 100644
index 0000000..c65c821
--- /dev/null
+++ b/ndk/docs/CHANGES.TXT
@@ -0,0 +1,4 @@
+Android NDK ChangeLog:
+
+-------------------------------------------------------------------------------
+android-1.5_r1 released.
diff --git a/ndk/docs/HOWTO.TXT b/ndk/docs/HOWTO.TXT
new file mode 100644
index 0000000..d2fa95f
--- /dev/null
+++ b/ndk/docs/HOWTO.TXT
@@ -0,0 +1,98 @@
+Android NDK How-To:
+===================
+
+A collection of tips and tricks for NDK users
+
+
+How to force the display of build commands:
+-------------------------------------------
+
+Do "make APP=<yourapp> V=1" and actual build commands will be
+displayed. This can be used to verify that things are compiled
+as you expect them to, and check for bugs in the NDK build system.
+
+(The V=1 trick comes from the Linux kernel build system)
+
+
+
+How to force a rebuild of all your sources:
+-------------------------------------------
+
+Use GNU Make's "-B" option, as in:
+
+ make APP=<yourapp> -B
+
+
+How to store your native sources in under your project's path:
+--------------------------------------------------------------
+
+It is often more convenient to store your native sources at a
+different location than $NDK_ROOT/sources. For example, you would
+typically place them under the same directory than your other project
+files, to keep everything under source control, etc...
+
+The NDK build system needs to access the sources from $NDK_ROOT/sources
+and your Application.mk from $NDK_ROOT/apps/<name>. This is essentially
+to keep its implementation sane and simple, and to ensure that certain
+features, like automatic dependency management, work reliably.
+
+You can however use simple symlinks to redirect paths to your project's
+storage location. For example:
+
+ $NDK_ROOT/sources/<foo> ----> $PROJECT_PATH/jni/<foo>
+ $NDK_ROOT/apps/<foo> ----> $PROJECT_PATH/jni/<foo>
+
+Where $PROJECT_PATH/jni/<foo> contains both an Android.mk and an
+Application.mk. Note that things like $(call my-dir) will always evaluate
+to the NDK paths (i.e. $NDK_ROOT/sources/<foo>) at build time.
+
+Windows users: The NDK is only supported on Cygwin, which implements
+symbolic links through the "ln -s" command, as in:
+
+ ln -s <target> <link>
+
+
+How to properly add include directories to your module declaration:
+-------------------------------------------------------------------
+
+If you define several modules, it is common to need to include one
+module's header while compiling another one. For example, consider
+the following example:
+
+ $NDK_ROOT/sources/foo/
+ Android.mk
+ foo.h
+ foo.c
+
+ $NDK_ROOT/sources/bar/
+ Android.mk
+ bar.c
+
+Where the 'bar.c' uses '#include <foo.h>'. You will need to add the
+path to the 'foo' module in bar/Android.mk to build it properly.
+
+One is tempted to use the following:
+
+ LOCAL_CPPFLAGS := -I../foo
+
+However this will not work because all compilation happens from the
+root NDK directory (i.e. $NDK_ROOT), and include files must be relative
+to it. The above line really translates to:
+
+ LOCAL_CPPFLAGS := -I$(NDK_ROOT)/../foo
+
+Which adds a non-existing directory to the C include path. The correct
+line is instead:
+
+ LOCAL_CPPFLAGS := -Isources/foo
+
+Or even better:
+
+ LOCAL_CPPFLAGS := $(LOCAL_PATH)/../foo
+
+Which uses a path relative to $(LOCAL_PATH), in the case where you would
+need to move 'foo' and 'bar' to a deeper level in the 'sources' hierarchy.
+
+
+
+
diff --git a/ndk/docs/STABLE-APIS.TXT b/ndk/docs/STABLE-APIS.TXT
new file mode 100644
index 0000000..743d657
--- /dev/null
+++ b/ndk/docs/STABLE-APIS.TXT
@@ -0,0 +1,113 @@
+Android NDK Stable APIs:
+========================
+
+This is the list of stable APIs/ABIs exposed by the Android NDK.
+
+I. Purpose:
+-----------
+
+Each API corresponds to a set of headers files, and a shared library file
+that contains the corresponding implementation, and which must be linked
+against by your native code.
+
+For example, to use system library "Foo", you would include a header
+like <foo.h> in your code, then tell the build system that your native
+module needs to link to /system/lib/libfoo.so at load-time by adding
+the following line to your Android.mk file:
+
+ LOCAL_LDLIBS := -lfoo
+
+Note that the build system automatically links the C library, the Math
+library and the C++ support library to your native code, there is no
+need to list them in a LOCAL_LDLIBS line.
+
+
+
+II. Android 1.5 Stable Native APIs:
+-----------------------------------
+
+All the APIs listed below are available for developing native code that
+runs on Android 1.5 system images and above.
+
+The C Library:
+--------------
+
+The C library headers, as they are defined on Android 1.5 are available
+through their standard names (<stdlib.h>, <stdio.h>, etc...). If one header
+is not there at build time, it's because its implementation is not available
+on a 1.5 system image.
+
+The build system automatically links your native modules to the C library,
+you don't need to add it to LOCAL_LDLIBS.
+
+Note that the Android C library includes support for pthread (<pthread.h>),
+so "LOCAL_LIBS := -lpthread" is not needed. The same is true for real-time
+extensions (-lrt on typical Linux distributions).
+
+
+** VERY IMPORTANT NOTE: ******************************************************
+*
+* The kernel-specific headers in <linux/...> and <asm/...> are not considered
+* stable at this point. Avoid including them directly because some of them
+* are likely to change in future releases of the platform. This is especially
+* true for anything related to specific hardware definitions.
+*
+******************************************************************************
+
+
+The Math Library:
+-----------------
+
+<math.h> is available, and the math library is automatically linked to your
+native modules at build time, so there is no need to list "-lm" through
+LOCAL_LDLIBS.
+
+
+
+C++ Library:
+------------
+
+An *extremely* minimal C++ support API is available. For Android 1.5, this is
+currently limited to the following headers:
+
+ <cstddef>
+ <new>
+ <utility>
+ <stl_pair.h>
+
+They may not contain all definitions required by the standard. Notably, support
+for C++ exceptions and RTTI is not available with Android 1.5 system images.
+
+The C++ support library (-lstdc++) is automatically linked to your native
+modules too, so there is no need to list it through LOCAL_LDLIBS
+
+
+
+Android-specific Log Support:
+-----------------------------
+
+<android/log.h> contains various definitions that can be used to send log messages
+to the kernel from your native code. Please have a look at its content in
+(build/platforms/android-1.5/common/include/android/log.h), which contain many
+informative comments on how to use it.
+
+You should be able to write helpful wrapper macros for your own usage to
+access this facility.
+
+If you use it, your native module should link to /system/lib/liblog.so with:
+
+ LOCAL_LDLIBS := -llog
+
+
+
+ZLib Compression Library:
+-------------------------
+
+<zlib.h> and <zconf.h> are available and can be used to use the ZLib compression
+library available on Android 1.5 system images. Documentation for it is available
+on the ZLib page: http://www.zlib.net/manual.html
+
+If you use it, your native module should link to /system/lib/libz.so with:
+
+ LOCAL_LDLIBS := -lz
+
diff --git a/ndk/docs/SYSTEM-ISSUES.TXT b/ndk/docs/SYSTEM-ISSUES.TXT
new file mode 100644
index 0000000..17ee4e8
--- /dev/null
+++ b/ndk/docs/SYSTEM-ISSUES.TXT
@@ -0,0 +1,113 @@
+Android System Image Issues
+===========================
+
+This document contains a list of known issues in existing Android
+system images that NDK developers should be aware of.
+
+I. Android 1.5 System Issues:
+-----------------------------
+
+The following issues correspond to the official Android 1.5
+system images:
+
+
+No standard C++ library support:
+--------------------------------
+
+The Android 1.5 system does not use any C++ standard library, and does
+not provide one to applicative native code. Instead, a very limited set
+of headers are provided (see docs/STABLE-APIS.TXT) which correspond to
+the C++ support code used to build the Android platform.
+
+It is possible to hack existing C++ STL implementations to work on top
+of this, but this is not supported yet. We recommend trying with uSTL
+and STLport at this point if you really need this.
+
+
+No support for C++ exceptions and RTTI:
+---------------------------------------
+
+The Android 1.5 system image lacks several features necessary to reliably
+implement C++ exceptions and RTTI. C++ code that depends on these features
+will simply not link or run appropriately on Android 1.5
+
+
+C Library limitations:
+----------------------
+
+The C library doesn't try to implement every feature under the sun.
+Most notably, pthread cancellation is not supported. A detailed overview
+of the C library and its design is available in docs/system/libc/OVERVIEW.TXT
+
+
+No SysV IPCs in C library:
+--------------------------
+
+Unix System V Inter-Process Communication APIs (e.g. semget()) are
+intentionally not available from the C library, to avoid denial-of-service
+issues. See docs/system/libc/SYSV-IPC.TXT for details.
+
+
+C Library bug: getservbyname() returns port number in incorrect order:
+----------------------------------------------------------------------
+
+The Android 1.5 C library function getservbyname() returns the port number
+corresponding to a given network service in incorrect order. The function
+stores its result in a 'struct servent' structure, and the port number in
+its 's_port' field.
+
+The standard mandates that this value is stored in network order (and thus
+should be converted to host order through ntohs()). However, the 1.5
+implementation is buggy and returns the number.
+
+This bug will be fixed in future releases of the platform, and applications
+should not depend on the wrong behaviour in the future. Avoid using this
+function if possible; if this is not possible, try to use a small wrapper
+like the following one:
+
+static struct servent*
+my_getservbyname(const char* name, const char* proto)
+{
+ static int has_bug = -1;
+ struct servent* ret;
+
+ if (has_bug < 0) {
+ ret = getservbyname("http",NULL);
+ has_bug = (ret == NULL || ret->s_port == 80);
+ }
+
+ ret = getservbyname(name, proto);
+ if (has_bug)
+ ret->s_port = htons(ret->s_port);
+}
+
+(the returned struct servent is thread-local and can be modified by the
+ caller. It will be over-written on the next call to the function though).
+
+
+Dynamic Linker limitations:
+---------------------------
+
+The Android dynamic linker in 1.5 has many important limitations:
+
+- No support for LD_LIBRARY_PATH, LD_PRELOAD, RTLD_LOCAL and many
+ other options.
+
+- Static C++ constructors in executables are called twice due to a bug
+ in the C library initialization sequence. However, static C++
+ constructors in shared libraries are only called once.
+
+- Static destructors are never called at the moment, either at program
+ exit, or when dlclose() is called.
+
+- dlerror() reporting is very limited and only provides a few generic
+ error messages that make it difficult to know why a dynamic load/link
+ operation failed. Most of the time, the culprit is a missing symbol.
+
+- A bug prevents one application shared library from depending on another
+ one. For example, if you build both libfoo.so and libbar.so for your
+ application, and list libfoo.so as a dependency for libbar.so in
+ bar/Android.mk (with LOCAL_SHARED_LIBRARIES := foo), then loading
+ libbar.so will always fail, even if you have already loaded libfoo.so
+ in your process.
+
diff --git a/ndk/docs/system/jni/jni-tips.html b/ndk/docs/system/jni/jni-tips.html
deleted file mode 100644
index e2c3b85..0000000
--- a/ndk/docs/system/jni/jni-tips.html
+++ /dev/null
@@ -1,512 +0,0 @@
-<html>
- <head>
- <title>Android JNI Tips</title>
- <link rel=stylesheet href="android.css">
- </head>
-
- <body>
- <h1><a name="JNI_Tips"></a>Android JNI Tips</h1>
-<p>
-</p><p>
-</p><ul>
-<li> <a href="#What_s_JNI_">What's JNI?</a>
-</li>
-<li> <a href="#JavaVM_and_JNIEnv">JavaVM and JNIEnv</a>
-
-</li>
-<li> <a href="#jclassID_jmethodID_and_jfieldID">jclassID, jmethodID, and jfieldID</a>
-</li>
-<li> <a href="#local_vs_global_references">Local vs. Global References</a>
-</li>
-<li> <a href="#UTF_8_and_UTF_16_strings">UTF-8 and UTF-16 Strings</a>
-</li>
-<li> <a href="#Arrays">Primitive Arrays</a>
-</li>
-<li> <a href="#RegionCalls">Region Calls</a>
-</li>
-<li> <a href="#Exceptions">Exceptions</a>
-</li>
-
-<li> <a href="#Extended_checking">Extended Checking</a>
-</li>
-<li> <a href="#Native_Libraries">Native Libraries</a>
-</li>
-<li> <a href="#64bit">64-bit Considerations</a>
-</li>
-
-<li> <a href="#Unsupported">Unsupported Features</a>
-</ul>
-<p>
-<noautolink>
-</noautolink></p><p>
-</p><h2><a name="What_s_JNI_"> </a> What's JNI? </h2>
-<p>
-
-JNI is the Java Native Interface. It defines a way for code written in the
-Java programming language to interact with native
-code, e.g. functions written in C/C++. It's VM-neutral, has support for loading code from
-dynamic shared libraries, and while cumbersome at times is reasonably efficient.
-</p><p>
-You really should read through the
-<a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html">JNI spec for J2SE 1.6</a>
-to get a sense for how JNI works and what features are available. Some
-aspects of the interface aren't immediately obvious on
-first reading, so you may find the next few sections handy.
-The more detailed <i>JNI Programmer's Guide and Specification</i> can be found
-<a href="http://java.sun.com/docs/books/jni/html/jniTOC.html">here</a>.
-</p><p>
-</p><p>
-</p><h2><a name="JavaVM_and_JNIEnv"> </a> JavaVM and JNIEnv </h2>
-<p>
-JNI defines two key data structures, "JavaVM" and "JNIEnv". Both of these are essentially
-pointers to pointers to function tables. (In the C++ version, it's a class whose sole member
-is a pointer to a function table.) The JavaVM provides the "invocation interface" functions,
-which allow you to create and destroy the VM. In theory you can have multiple VMs per process,
-but Android's VMs only allow one.
-</p><p>
-The JNIEnv provides most of the JNI functions. Your native functions all receive a JNIEnv as
-the first argument.
-</p><p>
-
-On some VMs, the JNIEnv is used for thread-local storage. For this reason, <strong>you cannot share a JNIEnv between threads</strong>.
-If a piece of code has no other way to get its JNIEnv, you should share
-the JavaVM, and use JavaVM->GetEnv to discover the thread's JNIEnv.
-</p><p>
-The C and C++ declarations of JNIEnv and JavaVM are different. "jni.h" provides different typedefs
-depending on whether it's included into ".c" or ".cpp". For this reason it's a bad idea to
-include JNIEnv arguments in header files included by both languages. (Put another way: if your
-header file requires "#ifdef __cplusplus", you may have to do some extra work if anything in
-that header refers to JNIEnv.)
-</p><p>
-</p><p>
-</p><h2><a name="jclassID_jmethodID_and_jfieldID"> jclassID, jmethodID, and jfieldID </a></h2>
-<p>
-If you want to access an object's field from native code, you would do the following:
-</p><p>
-</p><ul>
-<li> Get the class object reference for the class with <code>FindClass</code>
-</li>
-<li> Get the field ID for the field with <code>GetFieldID</code>
-</li>
-<li> Get the contents of the field with something appropriate, e.g.
-<code>GetIntField</code>
-</li>
-</ul>
-<p>
-Similarly, to call a method, you'd first get a class object reference and then a method ID. The IDs are often just
-pointers to internal VM data structures. Looking them up may require several string
-comparisons, but once you have them the actual call to get the field or invoke the method
-is very quick.
-</p><p>
-If performance is important, it's useful to look the values up once and cache the results
-in your native code. Because we are limiting ourselves to one VM per process, it's reasonable
-to store this data in a static local structure.
-</p><p>
-The class references, field IDs, and method IDs are guaranteed valid until the class is unloaded. Classes
-are only unloaded if all classes associated with a ClassLoader can be garbage collected,
-which is rare but will not be impossible in our system. The jclassID
-is a class reference and <strong>must be protected</strong> with a call
-to <code>NewGlobalRef</code> (see the next section).
-</p><p>
-If you would like to cache the IDs when a class is loaded, and automatically re-cache them
-if the class is ever unloaded and reloaded, the correct way to initialize
-the IDs is to add a piece of code that looks like this to the appropriate class:
-</p><p>
-
-</p><pre> /*
- * We use a class initializer to allow the native code to cache some
- * field offsets.
- */
-
- /*
- * A native function that looks up and caches interesting
- * class/field/method IDs for this class. Returns false on failure.
- */
- native private static boolean nativeClassInit();
-
- /*
- * Invoke the native initializer when the class is loaded.
- */
- static {
- if (!nativeClassInit())
- throw new RuntimeException("native init failed");
- }
-</pre>
-<p>
-Create a nativeClassInit method in your C/C++ code that performs the ID lookups. The code
-will be executed once, when the class is initialized. If the class is ever unloaded and
-then reloaded, it will be executed again. (See the implementation of java.io.FileDescriptor
-for an example in our source tree.)
-</p><p>
-</p><p>
-</p><p>
-</p><h2><a name="local_vs_global_references"> Local vs. Global References </a></h2>
-<p>
-Every object that JNI returns is a "local reference". This means that it's valid for the
-duration of the current native method in the current thread.
-<strong>Even if the object itself continues to live on after the native method returns, the reference is not valid.</strong>
-This applies to all sub-classes of jobject, including jclass and jarray.
-(Dalvik VM will warn you about this when -Xcheck:jni is enabled.)
-</p><p>
-
-If you want to hold on to a reference for a longer period, you must use a "global" reference.
-The <code>NewGlobalRef</code> function takes the local reference as
-an argument and returns a global one:
-
-<p><pre>jobject* localRef = [...];
-jobject* globalRef;
-globalRef = env->NewGlobalRef(localRef);
-</pre>
-
-The global reference is guaranteed to be valid until you call
-<code>DeleteGlobalRef</code>.
-</p><p>
-All JNI methods accept both local and global references as arguments.
-</p><p>
-Programmers are required to "not excessively allocate" local references. In practical terms this means
-that if you're creating large numbers of local references, perhaps while running through an array of
-Objects, you should free them manually with
-<code>DeleteLocalRef</code> instead of letting JNI do it for you. The
-VM is only required to reserve slots for
-16 local references, so if you need more than that you should either delete as you go or use
-<code>EnsureLocalCapacity</code> to reserve more.
-</p><p>
-Note: method and field IDs are just 32-bit identifiers, not object
-references, and should not be passed to <code>NewGlobalRef</code>. The raw data
-pointers returned by functions like <code>GetStringUTFChars</code>
-and <code>GetByteArrayElements</code> are also not objects.
-</p><p>
-One unusual case deserves separate mention. If you attach a native
-thread to the VM with AttachCurrentThread, the code you are running will
-never "return" to the VM until the thread detaches from the VM. Any local
-references you create will have to be deleted manually unless the thread
-is about to exit or detach.
-</p><p>
-</p><p>
-</p><p>
-</p><h2><a name="UTF_8_and_UTF_16_strings"> </a> UTF-8 and UTF-16 Strings </h2>
-<p>
-The Java programming language uses UTF-16. For convenience, JNI provides methods that work with "modified UTF-8" encoding
-as well. (Some VMs use the modified UTF-8 internally to store strings; ours do not.) The
-modified encoding only supports the 8- and 16-bit forms, and stores ASCII NUL values in a 16-bit encoding.
-The nice thing about it is that you can count on having C-style zero-terminated strings,
-suitable for use with standard libc string functions. The down side is that you cannot pass
-arbitrary UTF-8 data into the VM and expect it to work correctly.
-</p><p>
-It's usually best to operate with UTF-16 strings. With our current VMs, the
-<code>GetStringChars</code> method
-does not require a copy, whereas <code>GetStringUTFChars</code> requires a malloc and a UTF conversion. Note that
-<strong>UTF-16 strings are not zero-terminated</strong>, and \u0000 is allowed,
-so you need to hang on to the string length as well as
-the string pointer.
-
-</p><p>
-<strong>Don't forget to Release the strings you Get</strong>. The string functions return <code>jchar*</code> or <code>jbyte*</code>, which
-are pointers to primitive types rather than local references. They are
-guaranteed valid until Release is called, which means they are not
-released when the native method returns.
-</p><p>
-</p><p>
-
-
-</p><h2><a name="Arrays"> </a> Primitive Arrays </h2>
-<p>
-JNI provides functions for accessing the contents of array objects.
-While arrays of objects must be accessed one entry at a time, arrays of
-primitives can be read and written directly as if they were declared in C.
-</p><p>
-To make the interface as efficient as possible without constraining
-the VM implementation,
-the <code>Get<PrimitiveType>ArrayElements</code> family of calls
-allows the VM to either return a pointer to the actual elements, or
-allocate some memory and make a copy. Either way, the raw pointer returned
-is guaranteed to be valid until the corresponding <code>Release</code> call
-is issued (which implies that, if the data wasn't copied, the array object
-will be pinned down and can't be relocated as part of compacting the heap).
-<strong>You must Release every array you Get.</strong> Also, if the Get
-call fails, you must ensure that your code doesn't try to Release a NULL
-pointer later.
-</p><p>
-You can determine whether or not the data was copied by passing in a
-non-NULL pointer for the <code>isCopy</code> argument. This is rarely
-useful.
-</p><p>
-The <code>Release</code> call takes a <code>mode</code> argument that can
-have one of three values. The actions performed by the VM depend upon
-whether it returned a pointer to the actual data or a copy of it:
-<ul>
- <li><code>0</code>
- <ul>
- <li>Actual: the array object is un-pinned.
- <li>Copy: data is copied back. The buffer with the copy is freed.
- </ul>
- <li><code>JNI_COMMIT</code>
- <ul>
- <li>Actual: does nothing.
- <li>Copy: data is copied back. The buffer with the copy
- <strong>is not freed</strong>.
- </ul>
- <li><code>JNI_ABORT</code>
- <ul>
- <li>Actual: the array object is un-pinned. Earlier
- writes are <strong>not</strong> aborted.
- <li>Copy: the buffer with the copy is freed; any changes to it are lost.
- </ul>
-</ul>
-</p><p>
-One reason for checking the <code>isCopy</code> flag is to know if
-you need to call <code>Release</code> with <code>JNI_COMMIT</code>
-after making changes to an array -- if you're alternating between making
-changes and executing code that uses the contents of the array, you may be
-able to
-skip the no-op commit. Another possible reason for checking the flag is for
-efficient handling of <code>JNI_ABORT</code>. For example, you might want
-to get an array, modify it in place, pass pieces to other functions, and
-then discard the changes. If you know that JNI is making a new copy for
-you, there's no need to create another "editable" copy. If JNI is passing
-you the original, then you do need to make your own copy.
-</p><p>
-Some have asserted that you can skip the <code>Release</code> call if
-<code>*isCopy</code> is false. This is not the case. If no copy buffer was
-allocated, then the original memory must be pinned down and can't be moved by
-the garbage collector.
-</p><p>
-Also note that the <code>JNI_COMMIT</code> flag does NOT release the array,
-and you will need to call <code>Release</code> again with a different flag
-eventually.
-</p><p>
-</p><p>
-
-
-</p><h2><a name="RegionCalls"> Region Calls </a></h2>
-
-<p>
-There is an alternative to calls like <code>Get<Type>ArrayElements</code>
-and <code>GetStringChars</code> that may be very helpful when all you want
-to do is copy data in or out. Consider the following:
-<pre>
- jbyte* data = env->GetByteArrayElements(array, NULL);
- if (data != NULL) {
- memcpy(buffer, data, len);
- env->ReleaseByteArrayElements(array, data, JNI_ABORT);
- }
-</pre>
-<p>
-This grabs the array, copies the first <code>len</code> byte
-elements out of it, and then releases the array. Depending upon the VM
-policies the <code>Get</code> call will either pin or copy the array contents.
-We copy the data (for perhaps a second time), then call Release; in this case
-we use <code>JNI_ABORT</code> so there's no chance of a third copy.
-</p><p>
-We can accomplish the same thing with this:
-<pre>
- env->GetByteArrayRegion(array, 0, len, buffer);
-</pre>
-</p><p>
-This accomplishes the same thing, with several advantages:
-<ul>
- <li>Requires one JNI call instead of 3, reducing overhead.
- <li>Doesn't require pinning or extra data copies.
- <li>Reduces the risk of programmer error -- no need to match up
- <code>Get</code> and <code>Release</code> calls.
-</ul>
-</p><p>
-Similarly, you can use the <code>Set<Type>ArrayRegion</code> call
-to copy data into an array, and <code>GetStringRegion</code> or
-<code>GetStringUTFRegion</code> to copy characters out of a
-<code>String</code>.
-
-
-</p><h2><a name="Exceptions"> Exceptions </a></h2>
-<p>
-<strong>You may not call most JNI functions while an exception is pending.</strong>
-Your code is expected to notice the exception (via the function's return value,
-<code>ExceptionCheck()</code>, or <code>ExceptionOccurred()</code>) and return,
-or clear the exception and handle it.
-</p><p>
-The only JNI functions that you are allowed to call while an exception is
-pending are:
-<font size="-1"><ul>
- <li>DeleteGlobalRef
- <li>DeleteLocalRef
- <li>DeleteWeakGlobalRef
- <li>ExceptionCheck
- <li>ExceptionClear
- <li>ExceptionDescribe
- <li>ExceptionOccurred
- <li>MonitorExit
- <li>PopLocalFrame
- <li>PushLocalFrame
- <li>Release<PrimitiveType>ArrayElements
- <li>ReleasePrimitiveArrayCritical
- <li>ReleaseStringChars
- <li>ReleaseStringCritical
- <li>ReleaseStringUTFChars
-</ul></font>
-</p><p>
-Note that exceptions thrown by interpreted code do not "leap over" native code,
-and C++ exceptions thrown by native code are not handled by Dalvik.
-The JNI <code>Throw</code> and <code>ThrowNew</code> instructions just
-set an exception pointer in the current thread. Upon returning to the VM from
-native code, the exception will be noted and handled appropriately.
-</p><p>
-Native code can "catch" an exception by calling <code>ExceptionCheck</code> or
-<code>ExceptionOccurred</code>, and clear it with
-<code>ExceptionClear</code>. As usual,
-discarding exceptions without handling them can lead to problems.
-</p><p>
-There are no built-in functions for manipulating the Throwable object
-itself, so if you want to (say) get the exception string you will need to
-find the Throwable class, look up the method ID for
-<code>getMessage "()Ljava/lang/String;"</code>, invoke it, and if the result
-is non-NULL use <code>GetStringUTFChars</code> to get something you can
-hand to printf or a LOG macro.
-
-</p><p>
-</p><p>
-</p><h2><a name="Extended_checking"> Extended Checking </a></h2>
-<p>
-JNI does very little error checking. Calling <code>SetFieldInt</code>
-on an Object field will succeed, even if the field is marked
-<code>private</code> and <code>final</code>. The
-goal is to minimize the overhead on the assumption that, if you've written it in native code,
-you probably did it for performance reasons.
-</p><p>
-Some VMs support extended checking with the "<code>-Xcheck:jni</code>" flag. If the flag is set, the VM
-puts a different table of functions into the JavaVM and JNIEnv pointers. These functions do
-an extended series of checks before calling the standard implementation.
-
-</p><p>
-Some things that may be verified:
-</p><p>
-</p>
-<ul>
-<li> Check for null pointers where not allowed.
-<li>
-<li> Verify argument type correctness (jclass is a class object,
-jfieldID points to field data, jstring is a java.lang.String).
-</li>
-<li> Field type correctness, e.g. don't store a HashMap in a String field.
-</li>
-<li> Check to see if an exception is pending on calls where pending exceptions are not legal.
-</li>
-<li> Check for calls to inappropriate functions between Critical get/release calls.
-</li>
-<li> Check that JNIEnv structs aren't being shared between threads.
-
-</li>
-<li> Make sure local references aren't used outside their allowed lifespan.
-</li>
-<li> UTF-8 strings contain valid "modified UTF-8" data.
-</li>
-</ul>
-<p>Accessibility of methods and fields (i.e. public vs. private) is not
-checked.
-<p>
-The Dalvik VM supports the <code>-Xcheck:jni</code> flag. For a
-description of how to enable it for Android apps, see
-<a href="embedded-vm-control.html">Controlling the Embedded VM</a>.
-It's currently enabled by default in the Android emulator and on
-"engineering" device builds.
-
-</p><p>
-JNI checks can be modified with the <code>-Xjniopts</code> command-line
-flag. Currently supported values include:
-</p>
-<blockquote><dl>
-<dt>forcecopy
-<dd>When set, any function that can return a copy of the original data
-(array of primitive values, UTF-16 chars) will always do so. The buffers
-are over-allocated and surrounded with a guard pattern to help identify
-code writing outside the buffer, and the contents are erased before the
-storage is freed to trip up code that uses the data after calling Release.
-<dt>warnonly
-<dd>By default, JNI "warnings" cause the VM to abort. With this flag
-it continues on.
-</dl></blockquote>
-
-
-</p><p>
-</p><h2><a name="Native_Libraries"> Native Libraries </a></h2>
-<p>
-You can load native code from shared libraries with the standard
-<code>System.loadLibrary()</code> call. The
-preferred way to get at your native code is:
-</p><p>
-</p><ul>
-<li> Call <code>System.loadLibrary()</code> from a static class initializer. (See the earlier example, where one is used to call nativeClassInit().) The argument is the "undecorated" library name, e.g. to load "libfubar.so" you would pass in "fubar".
-
-</li>
-<li> Provide a native function: <code><strong>jint JNI_OnLoad(JavaVM* vm, void* reserved)</strong></code>
-</li>
-<li>In <code>JNI_OnLoad</code>, register all of your native methods. You
-should declare
-the methods "static" so the names don't take up space in the symbol table
-on the device.
-</li>
-</ul>
-<p>
-The <code>JNI_OnLoad</code> function should look something like this if
-written in C:
-</p><blockquote><pre>jint JNI_OnLoad(JavaVM* vm, void* reserved)
-{
- JNIEnv* env;
- if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK)
- return -1;
-
- /* get class with (*env)->FindClass */
- /* register methods with (*env)->RegisterNatives */
-
- return JNI_VERSION_1_4;
-}
-</pre></blockquote>
-</p><p>
-You can also call <code>System.load()</code> with the full path name of the
-shared library. For Android apps, you can get the full path to the
-application's private data storage area from the context object.
-</p><p>
-Dalvik does support "discovery" of native methods that are named in a
-specific way (see <a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp615">
- the JNI spec</a> for details), but this is a less desirable
-approach. It requires more space in the shared object symbol table,
-loading is slower because it requires string searches through all of the
-loaded shared libraries, and if a method signature is wrong you won't know
-about it until the first time the method is actually used.
-</p><p>
-
-
-</p><h2><a name="64bit"> 64-bit Considerations </a></h2>
-
-<p>
-Android is currently expected to run on 32-bit platforms. In theory it
-could be built for a 64-bit system, but that is not a goal at this time.
-For the most part this isn't something that you will need to worry about
-when interacting with native code,
-but it becomes significant if you plan to store pointers to native
-structures in integer fields in an object. To support architectures
-that use 64-bit pointers, <strong>you need to stash your native pointers in a
-<code>long</code> field rather than an <code>int</code></strong>.
-
-
-</p><h2><a name="Unsupported"> Unsupported Features </a></h2>
-<p>All JNI 1.6 features are supported, with the following exceptions:
-<ul>
- <li><code>DefineClass</code> is not implemented. Dalvik does not use
- Java bytecodes or class files, so passing in binary class data
- doesn't work. Translation facilities may be added in a future
- version of the VM.</li>
- <li><code>NewWeakGlobalRef</code> and <code>DeleteWeakGlobalRef</code>
- are not implemented. The
- VM supports weak references, but not JNI "weak global" references.
- These will be supported in a future release.</li>
- <li><code>GetObjectRefType</code> (new in 1.6) is implemented but not fully
- functional -- it can't always tell the difference between "local" and
- "global" references.</li>
-</ul>
-
-</p>
-
-<address>Copyright © 2008 The Android Open Source Project</address>
-
- </body>
-</html>
diff --git a/ndk/out/.gitignore b/ndk/out/.gitignore
new file mode 100644
index 0000000..ef2875b
--- /dev/null
+++ b/ndk/out/.gitignore
@@ -0,0 +1,2 @@
+# Ignore all generated files here
+*
diff --git a/pdk/docs/guide/build_cookbook.jd b/pdk/docs/guide/build_cookbook.jd
index ad5f8b8..b9d9f7c 100755
--- a/pdk/docs/guide/build_cookbook.jd
+++ b/pdk/docs/guide/build_cookbook.jd
@@ -10,7 +10,6 @@
<a href="http://wiki.corp.google.com/twiki/bin/view/Main/AndroidBuildCookbook#Building_a_APK_that_should_be_si">Building a APK that should be signed with a specific vendor key</a><br>
<a href="http://wiki.corp.google.com/twiki/bin/view/Main/AndroidBuildCookbook#Adding_a_prebuilt_APK">Adding a prebuilt APK</a><br>
<a href="http://wiki.corp.google.com/twiki/bin/view/Main/AndroidBuildCookbook#Adding_a_Static_Java_Library">Adding a Static Java Library</a><br>
- <a href="http://wiki.corp.google.com/twiki/bin/view/Main/AndroidBuildCookbook#LOCAL_MODULE_TAGS">Using LOCAL_MODULE_TAGS</a><br>
</div>
<p>The Android Build Cookbook offers code snippets to help you quickly implement some common build tasks. For additional instruction, please see the other build documents in this section.</p>
@@ -107,12 +106,443 @@
# Build a static jar file.
include $(BUILD_STATIC_JAVA_LIBRARY)
</pre>
-<h2><a name="Random_other_build_tidbits" id="Random_other_build_tidbits"></a>Random other build tidbits</h2>
-<h3><a name="LOCAL_MODULE_TAGS" id="LOCAL_MODULE_TAGS"></a>LOCAL_MODULE_TAGS</h3>
-<p>This variable controls what build flavors the package gets included in. For example:</p>
-<ul type="disc">
- <li>user - means include this in user/userdebug builds</li>
- <li>eng - means include this in eng builds</li>
- <li>tests - means the target is a testing target and makes it available for tests</li>
- <li>optional - don't include this</li>
+<h2><a name="Android_mk_variables" id="Android_mk_variables"></a>Android.mk Variables</h2>
+
+<p>These are the variables that you'll commonly see in Android.mk files, listed
+alphabetically. First, a note on the variable naming: </p>
+
+<ul>
+ <li><b>LOCAL_</b> - These variables are set per-module. They are cleared
+ by the <code>include $(CLEAR_VARS)</code> line, so you can rely on them
+ being empty after including that file. Most of the variables you'll use
+ in most modules are LOCAL_ variables.</li>
+ <li><b>PRIVATE_</b> - These variables are make-target-specific variables. That
+ means they're only usable within the commands for that module. It also
+ means that they're unlikely to change behind your back from modules that
+ are included after yours. This
+ <a href="http://www.gnu.org/software/make/manual/make.html#Target_002dspecific">link to the make documentation</a>
+ describes more about target-specific variables.
+ </li>
+ <li><b>HOST_</b> and <b>TARGET_</b> - These contain the directories
+ and definitions that are specific to either the host or the target builds.
+ Do not set variables that start with HOST_ or TARGET_ in your makefiles.
+ </li>
+ <li><b>BUILD_</b> and <b>CLEAR_VARS</b> - These contain the names of
+ well-defined template makefiles to include. Some examples are CLEAR_VARS
+ and BUILD_HOST_PACKAGE.</li>
+ <li>Any other name is fair-game for you to use in your Android.mk. However,
+ remember that this is a non-recursive build system, so it is possible that
+ your variable will be changed by another Android.mk included later, and be
+ different when the commands for your rule / module are executed.</li>
</ul>
+
+<table border=1 cellpadding=2 cellspacing=0>
+ <tbody><tr>
+ <th scope="col">Parameter</th>
+ <th scope="col">Description</th>
+ </tr>
+<tr>
+<td valign="top">LOCAL_AAPT_FLAGS</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_ACP_UNAVAILABLE</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_ADDITIONAL_JAVA_DIR</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_AIDL_INCLUDES</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_ALLOW_UNDEFINED_SYMBOLS</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_ARM_MODE</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_ASFLAGS</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_ASSET_DIR</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_ASSET_FILES</td>
+<td valign="top">In Android.mk files that <code>include $(BUILD_PACKAGE)</code> set this
+to the set of files you want built into your app. Usually:</p>
+<p><code>LOCAL_ASSET_FILES += $(call find-subdir-assets)</code></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_BUILT_MODULE_STEM</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_C_INCLUDES</td>
+<td valign="top"><p>Additional directories to instruct the C/C++ compilers to look for header
+files in. These paths are rooted at the top of the tree. Use
+<code>LOCAL_PATH</code> if you have subdirectories of your own that you
+want in the include paths. For example:</p>
+<p><code>
+LOCAL_C_INCLUDES += extlibs/zlib-1.2.3<br/>
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
+</code></p>
+<p>You should not add subdirectories of include to
+<code>LOCAL_C_INCLUDES</code>, instead you should reference those files
+in the <code>#include</code> statement with their subdirectories. For
+example:</p>
+<p><code>#include <utils/KeyedVector.h></code><br/>
+not <code><s>#include <KeyedVector.h></s></code></p> </td>
+</tr>
+<tr>
+<td valign="top">LOCAL_CC</td>
+<td valign="top">If you want to use a different C compiler for this module, set LOCAL_CC
+to the path to the compiler. If LOCAL_CC is blank, the appropriate default
+compiler is used.</td>
+</tr>
+<tr>
+<td valign="top">LOCAL_CERTIFICATE</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_CFLAGS</td>
+<td valign="top">If you have additional flags to pass into the C or C++ compiler, add
+them here. For example:</p>
+<p><code>LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1</code></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_CLASSPATH</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_COMPRESS_MODULE_SYMBOLS</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_COPY_HEADERS</td>
+<td valign="top"><p>The set of files to copy to the install include tree. You must also
+supply <code>LOCAL_COPY_HEADERS_TO</code>.</p>
+<p>This is going away because copying headers messes up the error messages, and
+may lead to people editing those headers instead of the correct ones. It also
+makes it easier to do bad layering in the system, which we want to avoid. We
+also aren't doing a C/C++ SDK, so there is no ultimate requirement to copy any
+headers.</p></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_COPY_HEADERS_TO</td>
+<td valign="top"><p>The directory within "include" to copy the headers listed in
+<code>LOCAL_COPY_HEADERS</code> to.</p>
+<p>This is going away because copying headers messes up the error messages, and
+may lead to people editing those headers instead of the correct ones. It also
+makes it easier to do bad layering in the system, which we want to avoid. We
+also aren't doing a C/C++ SDK, so there is no ultimate requirement to copy any
+headers.</p></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_CPP_EXTENSION</td>
+<td valign="top">If your C++ files end in something other than "<code>.cpp</code>",
+you can specify the custom extension here. For example:
+<p><code>LOCAL_CPP_EXTENSION := .cc</code></p>
+Note that all C++ files for a given module must have the same
+extension; it is not currently possible to mix different extensions.</td>
+</tr>
+<tr>
+<td valign="top">LOCAL_CPPFLAGS</td>
+<td valign="top">If you have additional flags to pass into <i>only</i> the C++ compiler, add
+them here. For example:</p>
+<p><code>LOCAL_CPPFLAGS += -ffriend-injection</code></p>
+<code>LOCAL_CPPFLAGS</code> is guaranteed to be after <code>LOCAL_CFLAGS</code>
+on the compile line, so you can use it to override flags listed in
+<code>LOCAL_CFLAGS</code></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_CXX</td>
+<td valign="top">If you want to use a different C++ compiler for this module, set LOCAL_CXX
+to the path to the compiler. If LOCAL_CXX is blank, the appropriate default
+compiler is used.</td>
+</tr>
+<tr>
+<td valign="top">LOCAL_DX_FLAGS</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_EXPORT_PACKAGE_RESOURCES</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_FORCE_STATIC_EXECUTABLE</td>
+<td valign="top"><p>If your executable should be linked statically, set
+<code>LOCAL_FORCE_STATIC_EXECUTABLE:=true</code>. There is a very short
+list of libraries that we have in static form (currently only libc). This is
+really only used for executables in /sbin on the root filesystem.</p> </td>
+</tr>
+<tr>
+<td valign="top">LOCAL_GENERATED_SOURCES</td>
+<td valign="top"><p>Files that you add to <code>LOCAL_GENERATED_SOURCES</code> will be
+automatically generated and then linked in when your module is built.
+See the <a href="#custom-tools">Custom Tools</a> template makefile for an
+example.</p> </td>
+</tr>
+<tr>
+<td valign="top">LOCAL_INSTRUMENTATION_FOR</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_INSTRUMENTATION_FOR_PACKAGE_NAME</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_INTERMEDIATE_SOURCES</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_INTERMEDIATE_TARGETS</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_IS_HOST_MODULE</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_JAR_MANIFEST</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_JARJAR_RULES</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_JAVA_LIBRARIES</td>
+<td valign="top"><p>When linking Java apps and libraries, <code>LOCAL_JAVA_LIBRARIES</code>
+specifies which sets of java classes to include. Currently there are
+two of these: <code>core</code> and <code>framework</code>.
+In most cases, it will look like this:</p>
+<p><code>LOCAL_JAVA_LIBRARIES := core framework</code></p>
+<p>Note that setting <code>LOCAL_JAVA_LIBRARIES</code> is not necessary
+(and is not allowed) when building an APK with
+"<code>include $(BUILD_PACKAGE)</code>". The appropriate libraries
+will be included automatically.</p> </td>
+</tr>
+<tr>
+<td valign="top">LOCAL_JAVA_RESOURCE_DIRS</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_JAVA_RESOURCE_FILES</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_JNI_SHARED_LIBRARIES</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_LDFLAGS</td>
+<td valign="top"><p>You can pass additional flags to the linker by setting
+<code>LOCAL_LDFLAGS</code>. Keep in mind that the order of parameters is
+very important to ld, so test whatever you do on all platforms.</p> </td>
+</tr>
+<tr>
+<td valign="top">LOCAL_LDLIBS</td>
+<td valign="top"><p><code>LOCAL_LDLIBS</code> allows you to specify additional libraries
+that are not part of the build for your executable or library. Specify
+the libraries you want in -lxxx format; they're passed directly to the
+link line. However, keep in mind that there will be no dependency generated
+for these libraries. It's most useful in simulator builds where you want
+to use a library preinstalled on the host. The linker (ld) is a particularly
+fussy beast, so it's sometimes necessary to pass other flags here if you're
+doing something sneaky. Some examples:</p>
+<p><code>LOCAL_LDLIBS += -lcurses -lpthread<br/>
+LOCAL_LDLIBS += -Wl,-z,origin
+</code></p> </td>
+</tr>
+<tr>
+<td valign="top">LOCAL_MODULE</td>
+<td valign="top"><code>LOCAL_MODULE</code> is the name of what's supposed to be generated
+from your Android.mk. For exmample, for libkjs, the <code>LOCAL_MODULE</code>
+is "libkjs" (the build system adds the appropriate suffix -- .so .dylib .dll).
+For app modules, use <code>LOCAL_PACKAGE_NAME</code> instead of
+<code>LOCAL_MODULE</code>. </td>
+</tr>
+<tr>
+<td valign="top">LOCAL_MODULE_PATH</td>
+<td valign="top">Instructs the build system to put the module somewhere other than what's
+normal for its type. If you override this, make sure you also set
+<code>LOCAL_UNSTRIPPED_PATH</code> if it's an executable or a shared library
+so the unstripped binary has somewhere to go. An error will occur if you forget
+to.</p>
+<p>See <a href="#moving-modules">Putting modules elsewhere</a> for more.</td>
+</tr>
+<tr>
+<td valign="top">LOCAL_MODULE_STEM</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_MODULE_TAGS</td>
+<td valign="top"><p>Set <code>LOCAL_MODULE_TAGS</code> to any number of whitespace-separated
+tags. <p>This variable controls what build flavors the package gets included in. For example:</p>
+<ul type="disc">
+ <li><code>user</code>: include this in user/userdebug builds</li>
+ <li><code>eng</code>: include this in eng builds</li>
+ <li><code>tests</code>: the target is a testing target and makes it available for tests</li>
+ <li><code>optional</code>: don't include this</li>
+</ul></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_NO_DEFAULT_COMPILER_FLAGS</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_NO_EMMA_COMPILE</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_NO_EMMA_INSTRUMENT</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_NO_STANDARD_LIBRARIES</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_OVERRIDES_PACKAGES</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_PACKAGE_NAME</td>
+<td valign="top"><code>LOCAL_PACKAGE_NAME</code> is the name of an app. For example,
+Dialer, Contacts, etc. </td>
+</tr>
+<tr>
+<td valign="top">LOCAL_POST_PROCESS_COMMAND</td>
+<td valign="top"><p>For host executables, you can specify a command to run on the module
+after it's been linked. You might have to go through some contortions
+to get variables right because of early or late variable evaluation:</p>
+<p><code>module := $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)<br/>
+LOCAL_POST_PROCESS_COMMAND := /Developer/Tools/Rez -d __DARWIN__ -t APPL\<br/>
+ -d __WXMAC__ -o $(module) Carbon.r
+</code></p>
+ </td>
+</tr>
+<tr>
+<td valign="top">LOCAL_PREBUILT_EXECUTABLES</td>
+<td valign="top">When including $(BUILD_PREBUILT) or $(BUILD_HOST_PREBUILT), set these to
+executables that you want copied. They're located automatically into the
+right bin directory.</td>
+</tr>
+<tr>
+<td valign="top">LOCAL_PREBUILT_JAVA_LIBRARIES</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_PREBUILT_LIBS</td>
+<td valign="top">When including $(BUILD_PREBUILT) or $(BUILD_HOST_PREBUILT), set these to
+libraries that you want copied. They're located automatically into the
+right lib directory.</td>
+</tr>
+<tr>
+<td valign="top">LOCAL_PREBUILT_OBJ_FILES</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_PRELINK_MODULE</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_REQUIRED_MODULES</td>
+<td valign="top"><p>Set <code>LOCAL_REQUIRED_MODULES</code> to any number of whitespace-separated
+module names, like "libblah" or "Email". If this module is installed, all
+of the modules that it requires will be installed as well. This can be
+used to, e.g., ensure that necessary shared libraries or providers are
+installed when a given app is installed.</td>
+</tr>
+<tr>
+<td valign="top">LOCAL_RESOURCE_DIR</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_SDK_VERSION</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_SHARED_LIBRARIES</td>
+<td valign="top">These are the libraries you directly link against. You don't need to
+pass transitively included libraries. Specify the name without the suffix:</p>
+<p><code>LOCAL_SHARED_LIBRARIES := \<br/>
+ libutils \<br/>
+ libui \<br/>
+ libaudio \<br/>
+ libexpat \<br/>
+ libsgl
+</code></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_SRC_FILES</td>
+<td valign="top">The build system looks at <code>LOCAL_SRC_FILES</code> to know what source
+files to compile -- .cpp .c .y .l .java. For lex and yacc files, it knows
+how to correctly do the intermediate .h and .c/.cpp files automatically. If
+the files are in a subdirectory of the one containing the Android.mk, prefix
+them with the directory name:</p>
+<p><code>LOCAL_SRC_FILES := \<br/>
+ file1.cpp \<br/>
+ dir/file2.cpp
+</code></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_STATIC_JAVA_LIBRARIES</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_STATIC_LIBRARIES</td>
+<td valign="top">These are the static libraries that you want to include in your module.
+Mostly, we use shared libraries, but there are a couple of places, like
+executables in sbin and host executables where we use static libraries instead.
+<p><code>LOCAL_STATIC_LIBRARIES := \<br/>
+ libutils \<br/>
+ libtinyxml
+</code></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_UNINSTALLABLE_MODULE</td>
+<td valign="top"></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_UNSTRIPPED_PATH</td>
+<td valign="top">Instructs the build system to put the unstripped version of the module
+somewhere other than what's normal for its type. Usually, you override this
+because you overrode <code>LOCAL_MODULE_PATH</code> for an executable or a
+shared library. If you overrode <code>LOCAL_MODULE_PATH</code>, but not
+<code>LOCAL_UNSTRIPPED_PATH</code>, an error will occur.</p>
+<p>See <a href="#moving-modules">Putting modules elsewhere</a> for more.</td>
+</tr>
+<tr>
+<td valign="top">LOCAL_WHOLE_STATIC_LIBRARIES</td>
+<td valign="top">These are the static libraries that you want to include in your module without allowing
+the linker to remove dead code from them. This is mostly useful if you want to add a static library
+to a shared library and have the static library's content exposed from the shared library.
+<p><code>LOCAL_WHOLE_STATIC_LIBRARIES := \<br/>
+ libsqlite3_android<br/>
+</code></td>
+</tr>
+<tr>
+<td valign="top">LOCAL_YACCFLAGS</td>
+<td valign="top">Any flags to pass to invocations of yacc for your module. A known limitation
+here is that the flags will be the same for all invocations of YACC for your
+module. This can be fixed. If you ever need it to be, just ask.</p>
+<p><code>LOCAL_YACCFLAGS := -p kjsyy</code></td>
+</tr>
+<tr>
+<td valign="top">OVERRIDE_BUILT_MODULE_PATH</td>
+<td valign="top"></td>
+</tr>
+
+</table>
\ No newline at end of file
diff --git a/pdk/docs/guide/build_new_device.jd b/pdk/docs/guide/build_new_device.jd
index e320ff3..d914ebe 100755
--- a/pdk/docs/guide/build_new_device.jd
+++ b/pdk/docs/guide/build_new_device.jd
@@ -126,3 +126,191 @@
</ul>
</ul>
</p>
+
+<a name="androidBuildSystemProductDefFiles"></a><h2>Product Definition Files</h2>
+
+<p>Product-specific variables are defined in product definition files. A product definition file can inherit from other product definition files, thus reducing the need to copy and simplifying maintenance.</p>
+<p>Variables maintained in a product definition files include:</p>
+<p>
+<table border=1 cellpadding=2 cellspacing=0>
+ <tbody><tr>
+ <th scope="col">Parameter</th>
+ <th scope="col">Description</th>
+ <th scope="col">Example</th>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_NAME</td>
+ <td valign="top">End-user-visible name for the overall product. Appears in the "About the phone" info.</td>
+ <td valign="top"></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_MODEL</td>
+ <td valign="top">End-user-visible name for the end product</td>
+ <td valign="top"></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_LOCALES</td>
+ <td valign="top">A space-separated list of two-letter language code, two-letter country code pairs that describe several settings for the user, such as the UI language and time, date and currency formatting. The first locale listed in PRODUCT_LOCALES is is used if the locale has never been set before.</td>
+ <td valign="top"><code>en_GB de_DE es_ES fr_CA</code></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_PACKAGES</td>
+ <td valign="top">Lists the APKs to install.</td>
+ <td valign="top"><code>Calendar Contacts</code></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_DEVICE</td>
+ <td valign="top">Name of the industrial design</td>
+ <td valign="top"><code>dream</code></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_MANUFACTURER</td>
+ <td valign="top">Name of the manufacturer</td>
+ <td valign="top"><code>acme</code></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_BRAND</td>
+ <td valign="top">The brand (e.g., carrier) the software is customized for, if any</td>
+ <td valign="top"></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_PROPERTY_OVERRIDES</td>
+ <td valign="top">List of property assignments in the format "key=value"</td>
+ <td valign="top"></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_COPY_FILES</td>
+ <td valign="top">List of words like <code>source_path:destination_path</code>. The file at the source path should be copied to the destination path when building this product. The rules for the copy steps are defined in config/Makefile</td>
+ <td valign="top"></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_OTA_PUBLIC_KEYS</td>
+ <td valign="top">List of OTA public keys for the product</td>
+ <td valign="top"></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_POLICY</td>
+ <td valign="top">Indicate which policy this product should use</td>
+ <td valign="top"></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_PACKAGE_OVERLAYS</td>
+ <td valign="top">Indicate whether to use default resources or add any product specific overlays</td>
+ <td valign="top"><code>vendor/acme/overlay</code></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_CONTRIBUTORS_FILE</td>
+ <td valign="top">HTML file containing the contributors to the project.</td>
+ <td valign="top"></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_TAGS</td>
+ <td valign="top">list of space-separated words for a given product</td>
+ <td valign="top"></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_SDK_ADDON_NAME</td>
+ <td valign="top"></td>
+ <td valign="top"></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_SDK_ADDON_COPY_FILES</td>
+ <td valign="top"></td>
+ <td valign="top"></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_SDK_ADDON_COPY_MODULES</td>
+ <td valign="top"></td>
+ <td valign="top"></td>
+ </tr>
+ <tr>
+ <td valign="top">PRODUCT_SDK_ADDON_DOC_MODULE</td>
+ <td valign="top"></td>
+ <td valign="top"></td>
+ </tr>
+</table>
+
+</P>
+<p>The snippet below illustrates a typical product definition file.</p>
+<pre class="prettyprint">
+$(call inherit-product, build/target/product/generic.mk)
+
+#Overrides
+PRODUCT_NAME := MyDevice
+PRODUCT_MANUFACTURER := acme
+PRODUCT_BRAND := acme_us
+PRODUCT_LOCALES := en_GB es_ES fr_FR
+PRODUCT_PACKAGE_OVERLAYS := vendor/acme/overlay
+
+</pre>
+
+<a name="androidBuildVariants"></a><h2>Build Variants</h2>
+
+<p>
+When building for a particular product, it's often useful to have minor
+variations on what is ultimately the final release build. These are the
+currently-defined build variants:
+</p>
+
+<table border=1>
+<tr>
+ <td>
+ <code>eng<code>
+ </td>
+ <td>
+ This is the default flavor. A plain "<code>make</code>" is the
+ same as "<code>make eng</code>". <code>droid</code> is an alias
+ for <code>eng</code>.
+ <ul>
+ <li>Installs modules tagged with: <code>eng</code>, <code>debug</code>,
+ <code>user</code>, and/or <code>development</code>.
+ <li>Installs non-APK modules that have no tags specified.
+ <li>Installs APKs according to the product definition files, in
+ addition to tagged APKs.
+ <li><code>ro.secure=0</code>
+ <li><code>ro.debuggable=1</code>
+ <li><code>ro.kernel.android.checkjni=1</code>
+ <li><code>adb</code> is enabled by default.
+ </td>
+</tr>
+<tr>
+ <td>
+ <code>user<code>
+ </td>
+ <td>
+ "<code>make user</code>"
+ <p>
+ This is the flavor intended to be the final release bits.
+ <ul>
+ <li>Installs modules tagged with <code>user</code>.
+ <li>Installs non-APK modules that have no tags specified.
+ <li>Installs APKs according to the product definition files; tags
+ are ignored for APK modules.
+ <li><code>ro.secure=1</code>
+ <li><code>ro.debuggable=0</code>
+ <li><code>adb</code> is disabled by default.
+ </td>
+</tr>
+<tr>
+ <td>
+ <code>userdebug<code>
+ </td>
+ <td>
+ "<code>make userdebug</code>"
+ <p>
+ The same as <code>user</code>, except:
+ <ul>
+ <li>Also installs modules tagged with <code>debug</code>.
+ <li><code>ro.debuggable=1</code>
+ <li><code>adb</code> is enabled by default.
+ </td>
+</tr>
+</table>
+
+<p>
+If you build one flavor and then want to build another, you should run
+"<code>make installclean</code>" between the two makes to guarantee that
+you don't pick up files installed by the previous flavor. "<code>make
+clean</code>" will also suffice, but it takes a lot longer.
+</p>
+
\ No newline at end of file
diff --git a/pdk/docs/guide/build_system.jd b/pdk/docs/guide/build_system.jd
index 158a0a7..36936aa 100755
--- a/pdk/docs/guide/build_system.jd
+++ b/pdk/docs/guide/build_system.jd
@@ -10,7 +10,6 @@
<a href="#androidBuildSystemOverview">Understanding the makefile</a><br/>
<a href="#androidBuildSystemLayers">Layers</a><br/>
-<a href="#androidBuildSystemProductDefFiles">Product Definition Files</a><br/></div>
<a href="#androidSourceSetupBuildingCodeBase">Building the Android Platform</a><br/><div style="padding-left:40px">
<a href="#androidSourceSetupBuildingDeviceCodeBase">Device Code</a><br/>
@@ -31,8 +30,6 @@
<a name="androidBuildSystemUnderstanding"></a><h2>Understanding Android's Build System</h2>
-
-
<a name="androidBuildSystemOverview"></a><h3>Understanding the makefile</h3>
<p>A makefile defines how to build a particular application. Makefiles typically include all of the following elements:</p>
@@ -95,38 +92,6 @@
</tr>
</table>
-
-<a name="androidBuildSystemProductDefFiles"></a><h3>Product Definition Files</h3>
-
-<p>Product-specific variables are defined in product definition files. A product definition file can inherit from other product definition files, thus reducing the need to copy and simplifying maintenance.</p>
-<p>Variables maintained in a product definition files include:</p>
-<p><ul>
-<li><code>PRODUCT_DEVICE</code></LI>
-<LI><code>LOCALES</code></LI>
-<LI><code>BRANDING_PARTNER</code></LI>
-<LI><code>PROPERTY_OVERRIDES</code></LI>
-</UL>
-</P>
-<p>The snippet below illustrates a typical product definition file.</p>
-<PRE class="prettyprint">
-//device/target/product/core.mk
-PRODUCT_PACKAGES := Home SettingsProvider ...
-//device/target/product/generic.mk
-PRODUCT_PACKAGES := Calendar Camera SyncProvider ...
-$(call inherit-product, target/product/core.mk)
-PRODUCT_NAME := generic
-//device/partner/google/products/core.mk
-PRODUCT_PACKAGES := Maps GoogleAppsProvider ...
-$(call inherit-product, target/product/core.mk)
-//device/partner/google/products/generic.mk
-PRODUCT_PACKAGES := Gmail GmailProvider ...
-$(call inherit-product, partner/google/products/core.mk)
-$(call inherit-product, target/product/generic.mk)
-PRODUCT_NAME := google_generic
-
-</pre>
-
-
<a name="androidSourceSetupBuildingCodeBase"></a><h2>Building the Android Platform</h2>
<p>This section describes how to build the default version of Android. Once you are comfortable with a generic build, then you can begin to modify Android for your own target device.</p>
diff --git a/pdk/docs/guide/dalvik.jd b/pdk/docs/guide/dalvik.jd
new file mode 100755
index 0000000..30c92ef
--- /dev/null
+++ b/pdk/docs/guide/dalvik.jd
@@ -0,0 +1,351 @@
+page.title=Dalvik
+pdk.version=1.0
+@jd:body
+
+<a name="toc"/>
+<div style="padding:10px">
+<a href="#androidDalvikIntroduction">Introduction</a><br/>
+<a href="#dalvikCoreLibraries">Core Libraries</a><br/>
+<a href="#dalvikJNICallBridge">JNI Call Bridge</a><br/>
+<a href="#dalvikInterpreter">Interpreter</a><br/></div></font>
+
+<a name="androidDalvikIntroduction"></a><h2>Introduction</h2>
+
+<p>
+The Dalvik virtual machine is intended to run on a variety of platforms.
+The baseline system is expected to be a variant of UNIX (Linux, BSD, Mac
+OS X) running the GNU C compiler. Little-endian CPUs have been exercised
+the most heavily, but big-endian systems are explicitly supported.
+</p><p>
+There are two general categories of work: porting to a Linux system
+with a previously unseen CPU architecture, and porting to a different
+operating system. This document covers the former.
+</p>
+
+
+<a name="dalvikCoreLibraries"></a><h2>Core Libraries</h2>
+
+<p>
+The native code in the core libraries (chiefly <code>dalvik/libcore</code>,
+but also <code>dalvik/vm/native</code>) is written in C/C++ and is expected
+to work without modification in a Linux environment. Much of the code
+comes directly from the Apache Harmony project.
+</p><p>
+The core libraries pull in code from many other projects, including
+OpenSSL, zlib, and ICU. These will also need to be ported before the VM
+can be used.
+</p>
+
+
+<a name="dalvikJNICallBridge"></a><h2>JNI Call Bridge</h2>
+
+<p>
+Most of the Dalvik VM runtime is written in portable C. The one
+non-portable component of the runtime is the JNI call bridge. Simply put,
+this converts an array of integers into function arguments of various
+types, and calls a function. This must be done according to the C calling
+conventions for the platform. The task could be as simple as pushing all
+of the arguments onto the stack, or involve complex rules for register
+assignment and stack alignment.
+</p><p>
+To ease porting to new platforms, the <a href="http://sourceware.org/libffi/">
+open-source FFI library</a> (Foreign Function Interface) is used when a
+custom bridge is unavailable. FFI is not as fast as a native implementation,
+and the optional performance improvements it does offer are not used, so
+writing a replacement is a good first step.
+</p><p>
+The code lives in <code>dalvik/vm/arch/*</code>, with the FFI-based version
+in the "generic" directory. There are two source files for each architecture.
+One defines the call bridge itself:
+</p><p><blockquote>
+<code>void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo,
+int argc, const u4* argv, const char* signature, void* func,
+JValue* pReturn)</code>
+</blockquote></p><p>
+This will invoke a C/C++ function declared:
+</p><p><blockquote>
+ <code>return_type func(JNIEnv* pEnv, Object* this [, <i>args</i>])<br></code>
+</blockquote>or (for a "static" method):<blockquote>
+ <code>return_type func(JNIEnv* pEnv, ClassObject* clazz [, <i>args</i>])</code>
+</blockquote></p><p>
+The role of <code>dvmPlatformInvoke</code> is to convert the values in
+<code>argv</code> into C-style calling conventions, call the method, and
+then place the return type into <code>pReturn</code> (a union that holds
+all of the basic JNI types). The code may use the method signature
+(a DEX "shorty" signature, with one character for the return type and one
+per argument) to determine how to handle the values.
+</p><p>
+The other source file involved here defines a 32-bit "hint". The hint
+is computed when the method's class is loaded, and passed in as the
+"argInfo" argument. The hint can be used to avoid scanning the ASCII
+method signature for things like the return value, total argument size,
+or inter-argument 64-bit alignment restrictions.
+</p>
+
+<a name="dalvikInterpreter"></a><h2>Interpreter</h2>
+
+<p>
+The Dalvik runtime includes two interpreters, labeled "portable" and "fast".
+The portable interpreter is largely contained within a single C function,
+and should compile on any system that supports gcc. (If you don't have gcc,
+you may need to disable the "threaded" execution model, which relies on
+gcc's "goto table" implementation; look for the THREADED_INTERP define.)
+</p><p>
+The fast interpreter uses hand-coded assembly fragments. If none are
+available for the current architecture, the build system will create an
+interpreter out of C "stubs". The resulting "all stubs" interpreter is
+quite a bit slower than the portable interpreter, making "fast" something
+of a misnomer.
+</p><p>
+The fast interpreter is enabled by default. On platforms without native
+support, you may want to switch to the portable interpreter. This can
+be controlled with the <code>dalvik.vm.execution-mode</code> system
+property. For example, if you:
+</p><p><blockquote>
+<code>adb shell "echo dalvik.vm.execution-mode = int:portable >> /data/local.prop"</code>
+</blockquote></p><p>
+and reboot, the Android app framework will start the VM with the portable
+interpreter enabled.
+</p>
+
+
+<h3>Mterp Interpreter Structure</h3>
+
+<p>
+There may be significant performance advantages to rewriting the
+interpreter core in assembly language, using architecture-specific
+optimizations. In Dalvik this can be done one instruction at a time.
+</p><p>
+The simplest way to implement an interpreter is to have a large "switch"
+statement. After each instruction is handled, the interpreter returns to
+the top of the loop, fetches the next instruction, and jumps to the
+appropriate label.
+</p><p>
+An improvement on this is called "threaded" execution. The instruction
+fetch and dispatch are included at the end of every instruction handler.
+This makes the interpreter a little larger overall, but you get to avoid
+the (potentially expensive) branch back to the top of the switch statement.
+</p><p>
+Dalvik mterp goes one step further, using a computed goto instead of a goto
+table. Instead of looking up the address in a table, which requires an
+extra memory fetch on every instruction, mterp multiplies the opcode number
+by a fixed value. By default, each handler is allowed 64 bytes of space.
+</p><p>
+Not all handlers fit in 64 bytes. Those that don't can have subroutines
+or simply continue on to additional code outside the basic space. Some of
+this is handled automatically by Dalvik, but there's no portable way to detect
+overflow of a 64-byte handler until the VM starts executing.
+</p><p>
+The choice of 64 bytes is somewhat arbitrary, but has worked out well for
+ARM and x86.
+</p><p>
+In the course of development it's useful to have C and assembly
+implementations of each handler, and be able to flip back and forth
+between them when hunting problems down. In mterp this is relatively
+straightforward. You can always see the files being fed to the compiler
+and assembler for your platform by looking in the
+<code>dalvik/vm/mterp/out</code> directory.
+</p><p>
+The interpreter sources live in <code>dalvik/vm/mterp</code>. If you
+haven't yet, you should read <code>dalvik/vm/mterp/README.txt</code> now.
+</p>
+
+
+<h3>Getting Started With Mterp</h3>
+
+</p><p>
+Getting started:
+<ol>
+<li>Decide on the name of your architecture. For the sake of discussion,
+let's call it <code>myarch</code>.
+<li>Make a copy of <code>dalvik/vm/mterp/config-allstubs</code> to
+<code>dalvik/vm/mterp/config-myarch</code>.
+<li>Create a <code>dalvik/vm/mterp/myarch</code> directory to hold your
+source files.
+<li>Add <code>myarch</code> to the list in
+<code>dalvik/vm/mterp/rebuild.sh</code>.
+<li>Make sure <code>dalvik/vm/Android.mk</code> will find the files for
+your architecture. If <code>$(TARGET_ARCH)</code> is configured this
+will happen automatically.
+</ol>
+</p><p>
+You now have the basic framework in place. Whenever you make a change, you
+need to perform two steps: regenerate the mterp output, and build the
+core VM library. (It's two steps because we didn't want the build system
+to require Python 2.5. Which, incidentally, you need to have.)
+<ol>
+<li>In the <code>dalvik/vm/mterp</code> directory, regenerate the contents
+of the files in <code>dalvik/vm/mterp/out</code> by executing
+<code>./rebuild.sh</code>. Note there are two files, one in C and one
+in assembly.
+<li>In the <code>dalvik</code> directory, regenerate the
+<code>libdvm.so</code> library with <code>mm</code>. You can also use
+<code>make libdvm</code> from the top of the tree.
+</ol>
+</p><p>
+This will leave you with an updated libdvm.so, which can be pushed out to
+a device with <code>adb sync</code> or <code>adb push</code>. If you're
+using the emulator, you need to add <code>make snod</code> (System image,
+NO Dependency check) to rebuild the system image file. You should not
+need to do a top-level "make" and rebuild the dependent binaries.
+</p><p>
+At this point you have an "all stubs" interpreter. You can see how it
+works by examining <code>dalvik/vm/mterp/cstubs/entry.c</code>. The
+code runs in a loop, pulling out the next opcode, and invoking the
+handler through a function pointer. Each handler takes a "glue" argument
+that contains all of the useful state.
+</p><p>
+Your goal is to replace the entry method, exit method, and each individual
+instruction with custom implementations. The first thing you need to do
+is create an entry function that calls the handler for the first instruction.
+After that, the instructions chain together, so you don't need a loop.
+(Look at the ARM or x86 implementation to see how they work.)
+</p><p>
+Once you have that, you need something to jump to. You can't branch
+directly to the C stub because it's expecting to be called with a "glue"
+argument and then return. We need a C stub "wrapper" that does the
+setup and jumps directly to the next handler. We write this in assembly
+and then add it to the config file definition.
+</p><p>
+To see how this works, create a file called
+<code>dalvik/vm/mterp/myarch/stub.S</code> that contains one line:
+<pre>
+/* stub for ${opcode} */
+</pre>
+Then, in <code>dalvik/vm/mterp/config-myarch</code>, add this below the
+<code>handler-size</code> directive:
+<pre>
+# source for the instruction table stub
+asm-stub myarch/stub.S
+</pre>
+</p><p>
+Regenerate the sources with <code>./rebuild.sh</code>, and take a look
+inside <code>dalvik/vm/mterp/out/InterpAsm-myarch.S</code>. You should
+see 256 copies of the stub function in a single large block after the
+<code>dvmAsmInstructionStart</code> label. The <code>stub.S</code>
+code will be used anywhere you don't provide an assembly implementation.
+</p><p>
+Note that each block begins with a <code>.balign 64</code> directive.
+This is what pads each handler out to 64 bytes. Note also that the
+<code>${opcode}</code> text changed into an opcode name, which should
+be used to call the C implementation (<code>dvmMterp_${opcode}</code>).
+</p><p>
+The actual contents of <code>stub.S</code> are up to you to define.
+See <code>entry.S</code> and <code>stub.S</code> in the <code>armv5te</code>
+or <code>x86</code> directories for working examples.
+</p><p>
+If you're working on a variation of an existing architecture, you may be
+able to use most of the existing code and just provide replacements for
+a few instructions. Look at the <code>armv4t</code> implementation as
+an example.
+</p>
+
+
+<h3>Replacing Stubs</h3>
+
+<p>
+There are roughly 230 Dalvik opcodes, including some that are inserted by
+<a href="dexopt.html">dexopt</a> and aren't described in the
+<a href="dalvik-bytecode.html">Dalvik bytecode</a> documentation. Each
+one must perform the appropriate actions, fetch the next opcode, and
+branch to the next handler. The actions performed by the assembly version
+must exactly match those performed by the C version (in
+<code>dalvik/vm/mterp/c/OP_*</code>).
+</p><p>
+It is possible to customize the set of "optimized" instructions for your
+platform. This is possible because optimized DEX files are not expected
+to work on multiple devices. Adding, removing, or redefining instructions
+is beyond the scope of this document, and for simplicity it's best to stick
+with the basic set defined by the portable interpreter.
+</p><p>
+Once you have written a handler that looks like it should work, add
+it to the config file. For example, suppose we have a working version
+of <code>OP_NOP</code>. For demonstration purposes, fake it for now by
+putting this into <code>dalvik/vm/mterp/myarch/OP_NOP.S</code>:
+<pre>
+/* This is my NOP handler */
+</pre>
+</p><p>
+Then, in the <code>op-start</code> section of <code>config-myarch</code>, add:
+<pre>
+ op OP_NOP myarch
+</pre>
+</p><p>
+This tells the generation script to use the assembly version from the
+<code>myarch</code> directory instead of the C version from the <code>c</code>
+directory.
+</p><p>
+Execute <code>./rebuild.sh</code>. Look at <code>InterpAsm-myarch.S</code>
+and <code>InterpC-myarch.c</code> in the <code>out</code> directory. You
+will see that the <code>OP_NOP</code> stub wrapper has been replaced with our
+new code in the assembly file, and the C stub implementation is no longer
+included.
+</p><p>
+As you implement instructions, the C version and corresponding stub wrapper
+will disappear from the output files. Eventually you will have a 100%
+assembly interpreter.
+</p>
+
+
+<h3>Interpreter Switching</h3>
+
+<p>
+The Dalvik VM actually includes a third interpreter implementation: the debug
+interpreter. This is a variation of the portable interpreter that includes
+support for debugging and profiling.
+</p><p>
+When a debugger attaches, or a profiling feature is enabled, the VM
+will switch interpreters at a convenient point. This is done at the
+same time as the GC safe point check: on a backward branch, a method
+return, or an exception throw. Similarly, when the debugger detaches
+or profiling is discontinued, execution transfers back to the "fast" or
+"portable" interpreter.
+</p><p>
+Your entry function needs to test the "entryPoint" value in the "glue"
+pointer to determine where execution should begin. Your exit function
+will need to return a boolean that indicates whether the interpreter is
+exiting (because we reached the "bottom" of a thread stack) or wants to
+switch to the other implementation.
+</p><p>
+See the <code>entry.S</code> file in <code>x86</code> or <code>armv5te</code>
+for examples.
+</p>
+
+
+<h3>Testing</h3>
+
+<p>
+A number of VM tests can be found in <code>dalvik/tests</code>. The most
+useful during interpreter development is <code>003-omnibus-opcodes</code>,
+which tests many different instructions.
+</p><p>
+The basic invocation is:
+<pre>
+$ cd dalvik/tests
+$ ./run-test 003
+</pre>
+</p><p>
+This will run test 003 on an attached device or emulator. You can run
+the test against your desktop VM by specifying <code>--reference</code>
+if you suspect the test may be faulty. You can also use
+<code>--portable</code> and <code>--fast</code> to explictly specify
+one Dalvik interpreter or the other.
+</p><p>
+Some instructions are replaced by <code>dexopt</code>, notably when
+"quickening" field accesses and method invocations. To ensure
+that you are testing the basic form of the instruction, add the
+<code>--no-optimize</code> option.
+</p><p>
+There is no in-built instruction tracing mechanism. If you want
+to know for sure that your implementation of an opcode handler
+is being used, the easiest approach is to insert a "printf"
+call. For an example, look at <code>common_squeak</code> in
+<code>dalvik/vm/mterp/armv5te/footer.S</code>.
+</p><p>
+At some point you need to ensure that debuggers and profiling work with
+your interpreter. The easiest way to do this is to simply connect a
+debugger or toggle profiling. (A future test suite may include some
+tests for this.)
+</p>
+
+
diff --git a/pdk/docs/guide/pdk_toc.cs b/pdk/docs/guide/pdk_toc.cs
index 282e5a2..1ab43b6 100644
--- a/pdk/docs/guide/pdk_toc.cs
+++ b/pdk/docs/guide/pdk_toc.cs
@@ -11,25 +11,44 @@
<li><a href="<?cs var:toroot ?>guide/system_requirements.html">Device Requirements</a></li>
<li><a href="<?cs var:toroot ?>guide/build_system.html">Build System</a></li>
<li><a href="<?cs var:toroot ?>guide/build_new_device.html">Building New Device</a></li>
- <li><a href="<?cs var:toroot ?>guide/bring_up.html">Bring up</a></li>
- <li><a href="<?cs var:toroot ?>guide/keymaps_keyboard_input.html">Keymaps and Keyboard</a></li>
- <li><a href="<?cs var:toroot ?>guide/display_drivers.html">Display Drivers</a></li>
<li><a href="<?cs var:toroot ?>guide/build_cookbook.html">Build Cookbook</a></li>
+ <li><a href="<?cs var:toroot ?>guide/bring_up.html">Bring up</a></li>
</ul>
</li>
+<li> <h2>Customization</h2>
+ <ul>
+ <li><a href="<?cs var:toroot ?>guide/customization.html">Customization</a></li>
+ </ul>
+</li>
<li> <h2>System</h2>
<ul>
<li class="toggle-list">
+ <div><a href="javascript:nothing()">Connectivity</a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>guide/bluetooth.html">Bluetooth</a></li>
+ <li><a href="<?cs var:toroot ?>guide/gps.html">GPS</a></li>
+ <li><a href="<?cs var:toroot ?>guide/wifi.html">Wi-Fi</a></li>
+ </ul>
+ </li>
+
+ <li><a href="<?cs var:toroot ?>guide/display_drivers.html">Display Drivers</a></li>
+ <li class="toggle-list">
+ <div><a href="javascript:nothing()">Input Devices</a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>guide/keymaps_keyboard_input.html">Keymaps and Keyboard</a></li>
+ </ul>
+ </li>
+ <li><a href="<?cs var:toroot ?>guide/lights.html">LED</a></li>
+ <li class="toggle-list">
<div><a href="javascript:nothing()">Multimedia</a></div>
<ul>
<li><a href="<?cs var:toroot ?>guide/audio.html">Audio</a></li>
- <li><a href="<?cs var:toroot ?>guide/camera.html">Camera</a></li>
+ <li><a href="<?cs var:toroot ?>guide/camera.html">Camera/Video</a></li>
</ul>
</li>
-
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>guide/power_management.html">Power Management</a></div>
<ul>
@@ -37,13 +56,12 @@
<li><a href="<?cs var:toroot ?>guide/early_suspend.html">Early Suspend</a></li>
</ul>
</li>
-
+ <li><a href="<?cs var:toroot ?>guide/sensors.html">Sensors</a></li>
<li class="toggle-list">
- <div><a href="javascript:nothing()">Networking</a></div>
+ <div><a href="javascript:nothing()">Telephony</a></div>
<ul>
- <li><a href="<?cs var:toroot ?>guide/wifi.html">Wi-Fi</a></li>
- <li><a href="<?cs var:toroot ?>guide/gps.html">GPS</a></li>
- <li><a href="<?cs var:toroot ?>guide/bluetooth.html">Bluetooth</a></li>
+ <li><a href="<?cs var:toroot ?>guide/telephony.html">Radio Interface Layer</a></li>
+ <li><a href="<?cs var:toroot ?>guide/stk.html">SIM Toolkit Application (STK)</a></li>
</ul>
</li>
@@ -57,13 +75,11 @@
</ul>
</li>
-<li> <h2>Telephony</h2>
+<li> <h2>Dalvik Virtual Machine</h2>
<ul>
- <li><a href="<?cs var:toroot ?>guide/telephony.html">Radio Interface Layer</a></li>
- <li><a href="<?cs var:toroot ?>guide/stk.html">SIM Toolkit Application (STK)</a></li>
+ <li><a href="<?cs var:toroot ?>guide/dalvik.html">Porting Dalvik</a></li>
</ul>
</li>
-
<li> <h2>Testing and Debugging</h2>
<ul>
<li><a href="<?cs var:toroot ?>guide/instrumentation_testing.html">Instrumentation Testing</a></li>
@@ -72,11 +88,7 @@
</ul>
</li>
-<li> <h2>Customization</h2>
- <ul>
- <li><a href="<?cs var:toroot ?>guide/customization.html">Customization</a></li>
- </ul>
-</li>
+
</ul>
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar4.java b/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar4.java
index ee396b3..86188f2 100644
--- a/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar4.java
+++ b/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar4.java
@@ -26,7 +26,7 @@
/**
- * Demonstrates how to use an indetermiate progress indicator in the window's title bar.
+ * Demonstrates how to use an indeterminate progress indicator in the window's title bar.
*/
public class ProgressBar4 extends Activity {
private boolean mToggleIndeterminate = false;
diff --git a/testrunner/adb_interface.py b/testrunner/adb_interface.py
index dd8d6f4..b1e3757 100755
--- a/testrunner/adb_interface.py
+++ b/testrunner/adb_interface.py
@@ -157,8 +157,9 @@
separated into its package and runner components.
"""
instrumentation_path = "%s/%s" % (package_name, runner_name)
- return self.StartInstrumentation(self, instrumentation_path, timeout_time,
- no_window_animation, instrumentation_args)
+ return self.StartInstrumentation(instrumentation_path, timeout_time=timeout_time,
+ no_window_animation=no_window_animation,
+ instrumentation_args=instrumentation_args)
def StartInstrumentation(
self, instrumentation_path, timeout_time=60*10, no_window_animation=False,
@@ -203,7 +204,7 @@
instrumentation_path, no_window_animation=no_window_animation,
profile=profile, raw_mode=True,
instrumentation_args=instrumentation_args)
-
+ logger.Log(command_string)
(test_results, inst_finished_bundle) = (
am_instrument_parser.ParseAmInstrumentOutput(
self.SendShellCommand(command_string, timeout_time=timeout_time,
@@ -217,7 +218,7 @@
short_msg_result = "no error message"
if "shortMsg" in inst_finished_bundle:
short_msg_result = inst_finished_bundle["shortMsg"]
- logger.Log(short_msg_result)
+ logger.Log("Error! Test run failed: %s" % short_msg_result)
raise errors.InstrumentationError(short_msg_result)
if "INSTRUMENTATION_ABORTED" in inst_finished_bundle:
diff --git a/testrunner/coverage.py b/testrunner/coverage.py
index 39a2ceb..c80eea0 100755
--- a/testrunner/coverage.py
+++ b/testrunner/coverage.py
@@ -44,16 +44,15 @@
# path to EMMA host jar, relative to Android build root
_EMMA_JAR = os.path.join(_EMMA_BUILD_PATH, "lib", "emma.jar")
_TEST_COVERAGE_EXT = "ec"
- # default device-side path to code coverage results file
- _DEVICE_COVERAGE_PATH = "/sdcard/coverage.ec"
# root path of generated coverage report files, relative to Android build root
_COVERAGE_REPORT_PATH = os.path.join("out", "emma")
+ _TARGET_DEF_FILE = "coverage_targets.xml"
_CORE_TARGET_PATH = os.path.join("development", "testrunner",
- "coverage_targets.xml")
+ _TARGET_DEF_FILE)
# vendor glob file path patterns to tests, relative to android
# build root
_VENDOR_TARGET_PATH = os.path.join("vendor", "*", "tests", "testinfo",
- "coverage_targets.xml")
+ _TARGET_DEF_FILE)
# path to root of target build intermediates
_TARGET_INTERMEDIATES_BASE_PATH = os.path.join("out", "target", "common",
@@ -93,7 +92,7 @@
return False
def ExtractReport(self, test_suite,
- device_coverage_path=_DEVICE_COVERAGE_PATH,
+ device_coverage_path,
output_path=None):
"""Extract runtime coverage data and generate code coverage report.
@@ -122,8 +121,14 @@
report_path = os.path.join(output_path,
test_suite.GetName())
target = self._targets_manifest.GetTarget(test_suite.GetTargetName())
- return self._GenerateReport(report_path, coverage_local_path, [target],
- do_src=True)
+ if target is None:
+ msg = ["Error: test %s references undefined target %s."
+ % (test_suite.GetName(), test_suite.GetTargetName())]
+ msg.append(" Ensure target is defined in %s" % self._TARGET_DEF_FILE)
+ logger.Log("".join(msg))
+ else:
+ return self._GenerateReport(report_path, coverage_local_path, [target],
+ do_src=True)
return None
def _GenerateReport(self, report_path, coverage_file_path, targets,
diff --git a/testrunner/errors.py b/testrunner/errors.py
index e240899..c04fd01 100755
--- a/testrunner/errors.py
+++ b/testrunner/errors.py
@@ -34,7 +34,7 @@
"""Generic exception that indicates a fatal error has occurred and program
execution should be aborted."""
- def __init__(self, msg="AbortError"):
+ def __init__(self, msg=""):
self.msg = msg
diff --git a/testrunner/runtest.py b/testrunner/runtest.py
index 05d29ec..e66b8de 100755
--- a/testrunner/runtest.py
+++ b/testrunner/runtest.py
@@ -112,7 +112,13 @@
default=False, action="store_true",
help="Run all tests defined as part of the continuous "
"test set")
-
+ parser.add_option("--timeout", dest="timeout",
+ default=300, help="Set a timeout limit (in sec) for "
+ "running native tests on a device (default: 300 secs)")
+ parser.add_option("--cts", dest="cts_tests",
+ default=False, action="store_true",
+ help="Run all tests defined as part of the "
+ "compatibility test suite")
group = optparse.OptionGroup(
parser, "Targets", "Use these options to direct tests to a specific "
"Android target")
@@ -126,8 +132,11 @@
self._options, self._test_args = parser.parse_args()
- if (not self._options.only_list_tests and not self._options.all_tests
- and not self._options.continuous_tests and len(self._test_args) < 1):
+ if (not self._options.only_list_tests
+ and not self._options.all_tests
+ and not self._options.continuous_tests
+ and not self._options.cts_tests
+ and len(self._test_args) < 1):
parser.print_help()
logger.SilentLog("at least one test name must be specified")
raise errors.AbortError
@@ -226,8 +235,10 @@
"""Get a list of TestSuite objects to run, based on command line args."""
if self._options.all_tests:
return self._known_tests.GetTests()
- if self._options.continuous_tests:
+ elif self._options.continuous_tests:
return self._known_tests.GetContinuousTests()
+ elif self._options.cts_tests:
+ return self._known_tests.GetCtsTests()
tests = []
for name in self._test_args:
test = self._known_tests.GetTest(name)
@@ -275,16 +286,53 @@
raw_mode=self._options.raw_mode,
instrumentation_args=instrumentation_args)
logger.Log(adb_cmd)
+ elif self._options.coverage:
+ # need to parse test output to determine path to coverage file
+ logger.Log("Running in coverage mode, suppressing test output")
+ try:
+ (test_results, status_map) = self._adb.StartInstrumentationForPackage(
+ package_name=test_suite.GetPackageName(),
+ runner_name=test_suite.GetRunnerName(),
+ timeout_time=60*60,
+ instrumentation_args=instrumentation_args)
+ except errors.InstrumentationError, errors.DeviceUnresponsiveError:
+ return
+ self._PrintTestResults(test_results)
+ device_coverage_path = status_map.get("coverageFilePath", None)
+ if device_coverage_path is None:
+ logger.Log("Error: could not find coverage data on device")
+ return
+ coverage_file = self._coverage_gen.ExtractReport(test_suite, device_coverage_path)
+ if coverage_file is not None:
+ logger.Log("Coverage report generated at %s" % coverage_file)
else:
self._adb.StartInstrumentationNoResults(
package_name=test_suite.GetPackageName(),
runner_name=test_suite.GetRunnerName(),
raw_mode=self._options.raw_mode,
instrumentation_args=instrumentation_args)
- if self._options.coverage and test_suite.GetTargetName() is not None:
- coverage_file = self._coverage_gen.ExtractReport(test_suite)
- if coverage_file is not None:
- logger.Log("Coverage report generated at %s" % coverage_file)
+
+ def _PrintTestResults(self, test_results):
+ """Prints a summary of test result data to stdout.
+
+ Args:
+ test_results: a list of am_instrument_parser.TestResult
+ """
+ total_count = 0
+ error_count = 0
+ fail_count = 0
+ for test_result in test_results:
+ if test_result.GetStatusCode() == -1: # error
+ logger.Log("Error in %s: %s" % (test_result.GetTestName(),
+ test_result.GetFailureReason()))
+ error_count+=1
+ elif test_result.GetStatusCode() == -2: # failure
+ logger.Log("Failure in %s: %s" % (test_result.GetTestName(),
+ test_result.GetFailureReason()))
+ fail_count+=1
+ total_count+=1
+ logger.Log("Tests run: %d, Failures: %d, Errors: %d" %
+ (total_count, fail_count, error_count))
def _CollectTestSources(self, test_list, dirname, files):
"""For each directory, find tests source file and add them to the list.
@@ -384,7 +432,8 @@
# Single quotes are needed to prevent the shell splitting it.
output = self._adb.SendShellCommand("'%s 2>&1;echo -n exit code:$?'" %
- full_path)
+ full_path,
+ int(self._options.timeout))
success = output.endswith("exit code:0")
logger.Log("%s... %s" % (f, success and "ok" or "failed"))
# Print the captured output when the test failed.
diff --git a/testrunner/test_defs.py b/testrunner/test_defs.py
index 2cdcfa8..0542a05 100644
--- a/testrunner/test_defs.py
+++ b/testrunner/test_defs.py
@@ -144,6 +144,14 @@
con_tests.append(test)
return con_tests
+ def GetCtsTests(self):
+ """Return list of cts tests."""
+ cts_tests = []
+ for test in self.GetTests():
+ if test.IsCts():
+ cts_tests.append(test)
+ return cts_tests
+
def GetTest(self, name):
return self._testname_map.get(name, None)
@@ -157,6 +165,7 @@
_TARGET_ATTR = "coverage_target"
_BUILD_ATTR = "build_path"
_CONTINUOUS_ATTR = "continuous"
+ _CTS_ATTR = "cts"
_DESCRIPTION_ATTR = "description"
_EXTRA_MAKE_ARGS_ATTR = "extra_make_args"
@@ -199,6 +208,11 @@
self._continuous = suite_element.getAttribute(self._CONTINUOUS_ATTR)
else:
self._continuous = False
+ if suite_element.hasAttribute(self._CTS_ATTR):
+ self._cts = suite_element.getAttribute(self._CTS_ATTR)
+ else:
+ self._cts = False
+
if suite_element.hasAttribute(self._DESCRIPTION_ATTR):
self._description = suite_element.getAttribute(self._DESCRIPTION_ATTR)
else:
@@ -236,6 +250,10 @@
"""Returns true if test is flagged as being part of the continuous tests"""
return self._continuous
+ def IsCts(self):
+ """Returns true if test is part of the compatibility test suite"""
+ return self._cts
+
def IsNative(self):
"""Returns true if test is a native one."""
return self._native
diff --git a/testrunner/test_defs.xml b/testrunner/test_defs.xml
index 34366ab..e1d9cc5 100644
--- a/testrunner/test_defs.xml
+++ b/testrunner/test_defs.xml
@@ -42,6 +42,8 @@
continuous: Optional boolean. Default is false. Set to true if tests are known
to be reliable, and should be included in a continuous test system. false if
they are under development.
+ cts: Optional boolean. Default is false. Set to true if test is included in
+ compatibility test suite.
description: Optional string. Default is empty. Short description (typically
less than 60 characters) about this test.
@@ -56,7 +58,7 @@
=============
The <test-native> element has the following attributes
- name build_path [continuous description]
+ name build_path [continuous description extra_make_args]
Where:
name: Self-descriptive name used to uniquely identify the test
@@ -83,7 +85,9 @@
done
-->
-<test-definitions version="1">
+<test-definitions xmlns="http://schemas.android.com/testrunner/test_defs/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://schemas.android.com/testrunner/test_defs/1.0 test_defs.xsd">
<!-- system-wide tests -->
<test name="framework"
@@ -164,6 +168,162 @@
coverage_target="framework"
continuous="true" />
+<!-- cts tests -->
+
+<test name="cts-permission"
+ build_path="cts/tests"
+ package="com.android.cts.permission"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ continuous="true"
+ cts="true" />
+
+<test name="cts-process"
+ build_path="cts/tests"
+ package="com.android.cts.process"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-api-signature"
+ build_path="cts/tests"
+ package="android.tests.sigtest"
+ runner=".InstrumentationRunner"
+ cts="true" />
+
+<test name="cts-api-signature-func"
+ build_path="cts/tests"
+ package="android.tests.sigtest.tests"
+ cts="true" />
+
+<test name="cts-apidemos"
+ build_path="cts/tests"
+ package="android.apidemos.cts"
+ coverage_target="ApiDemos"
+ cts="true" />
+
+<test name="cts-app"
+ build_path="cts/tests"
+ package="com.android.cts.app"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-content"
+ build_path="cts/tests"
+ package="com.android.cts.content"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-database"
+ build_path="cts/tests"
+ package="com.android.cts.database"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-graphics"
+ build_path="cts/tests"
+ package="com.android.cts.graphics"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-hardware"
+ build_path="cts/tests"
+ package="com.android.cts.hardware"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-location"
+ build_path="cts/tests"
+ package="com.android.cts.location"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-net"
+ build_path="cts/tests"
+ package="com.android.cts.net"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-os"
+ build_path="cts/tests"
+ package="com.android.cts.os"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-perf1"
+ build_path="cts/tests"
+ package="com.android.cts.performance"
+ runner="android.test.InstrumentationCtsTestRunner"
+ cts="true" />
+
+<test name="cts-perf2"
+ build_path="cts/tests"
+ package="com.android.cts.performance2"
+ runner="android.test.InstrumentationCtsTestRunner"
+ cts="true" />
+
+<test name="cts-perf3"
+ build_path="cts/tests"
+ package="com.android.cts.performance3"
+ runner="android.test.InstrumentationCtsTestRunner"
+ cts="true" />
+
+<test name="cts-perf4"
+ build_path="cts/tests"
+ package="com.android.cts.performance4"
+ runner="android.test.InstrumentationCtsTestRunner"
+ cts="true" />
+
+<test name="cts-perf5"
+ build_path="cts/tests"
+ package="com.android.cts.performance5"
+ runner="android.test.InstrumentationCtsTestRunner"
+ cts="true" />
+
+<test name="cts-provider"
+ build_path="cts/tests"
+ package="com.android.cts.provider"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-text"
+ build_path="cts/tests"
+ package="com.android.cts.text"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-util"
+ build_path="cts/tests"
+ package="com.android.cts.util"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-view"
+ build_path="cts/tests"
+ package="com.android.cts.view"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<test name="cts-widget"
+ build_path="cts/tests"
+ package="com.android.cts.widget"
+ runner="android.test.InstrumentationCtsTestRunner"
+ coverage_target="framework"
+ cts="true" />
+
+<!-- end of cts tests -->
+
<!-- selected app tests -->
<test name="browser"
build_path="packages/apps/Browser"
@@ -190,13 +350,13 @@
continuous="true" />
<test name="camerastress"
- build_path="packages/apps/Camera/tests"
+ build_path="packages/apps/Camera"
package="com.android.camera.tests"
class="com.android.camera.StressTests"
coverage_target="Camera" />
<test name="camera"
- build_path="packages/apps/Camera/tests"
+ build_path="packages/apps/Camera"
package="com.android.camera.tests"
class="com.android.camera.UnitTests"
continuous="true"
@@ -226,6 +386,26 @@
coverage_target="framework"
continuous="true" />
+<test name="mediaapitest"
+ build_path="frameworks/base/media/tests/MediaFrameworkTest"
+ package="com.android.mediaframeworktest"
+ class="com.android.mediaframeworktest.functional.MediaPlayerApiTest"
+ runner=".MediaFrameworkTestRunner"
+ coverage_target="framework" />
+
+<test name="mediarecordertest"
+ build_path="frameworks/base/media/tests/MediaFrameworkTest"
+ package="com.android.mediaframeworktest"
+ class="com.android.mediaframeworktest.functional.MediaRecorderTest"
+ runner=".MediaFrameworkTestRunner"
+ coverage_target="framework" />
+
+<test name="mediastresstest"
+ build_path="frameworks/base/media/tests/MediaFrameworkTest"
+ package="com.android.mediaframeworktest"
+ runner=".MediaRecorderStressTestRunner"
+ coverage_target="framework" />
+
<test name="mediaunit"
build_path="frameworks/base/media/tests/MediaFrameworkTest"
package="com.android.mediaframeworktest"
diff --git a/testrunner/test_defs.xsd b/testrunner/test_defs.xsd
new file mode 100644
index 0000000..f964779
--- /dev/null
+++ b/testrunner/test_defs.xsd
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://schemas.android.com/testrunner/test_defs/1.0"
+ xmlns="http://schemas.android.com/testrunner/test_defs/1.0"
+ elementFormDefault="qualified">
+
+ <xs:element name="test-definitions">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="test" type="javaTestType"/>
+ <xs:element name="test-native" type="nativeTestType"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:complexType name="javaTestType">
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="package" type="xs:string" use="required"/>
+ <xs:attribute name="build_path" type="xs:string" use="optional"/>
+ <xs:attribute name="class" type="xs:string" use="optional"/>
+ <xs:attribute name="runner" type="xs:string" use="optional"
+ default="android.test.InstrumentationTestRunner"/>
+ <xs:attribute name="coverage_target" type="xs:string" use="optional"/>
+ <xs:attribute name="continuous" type="xs:boolean" use="optional" default="false"/>
+ <xs:attribute name="cts" type="xs:boolean" use="optional" default="false"/>
+ </xs:complexType>
+
+ <xs:complexType name="nativeTestType">
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="build_path" type="xs:string" use="required"/>
+ <xs:attribute name="extra_make_args" type="xs:string" use="optional"/>
+ <xs:attribute name="description" type="xs:string" use="optional"/>
+ <xs:attribute name="continuous" type="xs:boolean" use="optional" default="false"/>
+ </xs:complexType>
+</xs:schema>
diff --git a/tools/ddms/app/etc/ddms b/tools/ddms/app/etc/ddms
index b4470b5..c63930b 100755
--- a/tools/ddms/app/etc/ddms
+++ b/tools/ddms/app/etc/ddms
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
# Copyright 2005-2007, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -67,12 +67,28 @@
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"
-elif [[ `uname -s` = 'Linux' && `uname -m` = 'x86_64' ]]; then
-# Use 32-bit Java on x86_64 Linux.
- java_cmd="/usr/lib/jvm/ia32-java-6-sun/jre/bin/java"
- if [ ! -x $java_cmd ]; then
- echo `basename "$prog"`": missing 32-bit JVM. Please install ia32-sun-java6-bin."
- exit 1
+elif [[ `uname -s` = 'Linux' ]]; then
+ # We need a 32-bit Java on Linux, because our JNI libraries are 32-bit.
+ java_cmd=`which java`
+
+ if [ -x "$java_cmd" ]; then
+ if [[ ! `file -L "$java_cmd"` =~ "ELF 32-bit LSB executable" ]]; then
+ java_cmd=""
+ fi
+ fi
+
+ if [ ! -x "$java_cmd" ]; then
+ # The default JVM is not suitable.
+ # See if we can find a particular known-good JVM
+ java_cmd="/usr/lib/jvm/ia32-java-6-sun/jre/bin/java"
+ if [ ! -x "$java_cmd" ]; then
+ PREFIX=`basename "$prog"`
+ echo "$PREFIX: The default Java VM is not an ELF 32-bit LSB executable."
+ echo "$PREFIX: Please do one of the following:"
+ echo "$PREFIX: 1) Arrange for the default Java VM to be an ELF 32-bit LSB executable."
+ echo "$PREFIX: 2) Install the ia32-sun-java6-bin package."
+ exit 1
+ fi
fi
else
os_opts=
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
index 09ecc63..751d33d 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
@@ -47,6 +47,8 @@
org.eclipse.core.expressions
Eclipse-LazyStart: true
Export-Package: com.android.ide.eclipse.adt;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal.actions;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.build;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.editors;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.editors.descriptors;x-friends:="com.android.ide.eclipse.tests",
@@ -69,13 +71,36 @@
com.android.ide.eclipse.adt.internal.editors.xml;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.editors.xml.descriptors;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.launch;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal.launch.junit;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal.launch.junit.runtime;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal.preferences;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.project;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal.properties;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal.refactorings.extractstring;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.resources;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.resources.configurations;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.resources.manager;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.resources.manager.files;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.sdk;x-friends:="com.android.ide.eclipse.tests",
com.android.ide.eclipse.adt.internal.ui;x-friends:="com.android.ide.eclipse.tests",
- com.android.ide.eclipse.adt.internal.wizards.newproject;x-friends:="com.android.ide.eclipse.tests"
+ com.android.ide.eclipse.adt.internal.wizards.actions;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal.wizards.avdmanager;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal.wizards.export;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal.wizards.newproject;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ide.eclipse.adt.internal.wizards.newxmlfile;x-friends:="com.android.ide.eclipse.tests",
+ com.android.jarutils;x-friends:="com.android.ide.eclipse.tests",
+ com.android.layoutlib.api;x-friends:="com.android.ide.eclipse.tests",
+ com.android.layoutlib.utils;x-friends:="com.android.ide.eclipse.tests",
+ com.android.ninepatch;x-friends:="com.android.ide.eclipse.tests",
+ com.android.prefs;x-friends:="com.android.ide.eclipse.tests",
+ com.android.sdklib;x-friends:="com.android.ide.eclipse.tests",
+ com.android.sdklib.internal.avd;x-friends:="com.android.ide.eclipse.tests",
+ com.android.sdklib.internal.project;x-friends:="com.android.ide.eclipse.tests",
+ com.android.sdklib.internal.repository;x-friends:="com.android.ide.eclipse.tests",
+ com.android.sdklib.repository;x-friends:="com.android.ide.eclipse.tests",
+ com.android.sdkstats;x-friends:="com.android.ide.eclipse.tests",
+ com.android.sdkuilib;x-friends:="com.android.ide.eclipse.tests",
+ com.android.sdkuilib.internal.repository;x-friends:="com.android.ide.eclipse.tests",
+ com.android.sdkuilib.repository;x-friends:="com.android.ide.eclipse.tests"
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
index a5b107b..dc2c612 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
@@ -455,23 +455,23 @@
<extension
point="org.eclipse.wst.sse.ui.editorConfiguration">
<sourceViewerConfiguration
- class="com.android.ide.eclipse.editors.manifest.ManifestSourceViewerConfig"
+ class="com.android.ide.eclipse.adt.internal.editors.manifest.ManifestSourceViewerConfig"
target="com.android.ide.eclipse.editors.manifest.ManifestEditor">
</sourceViewerConfiguration>
<sourceViewerConfiguration
- class="com.android.ide.eclipse.editors.resources.ResourcesSourceViewerConfig"
+ class="com.android.ide.eclipse.adt.internal.editors.resources.ResourcesSourceViewerConfig"
target="com.android.ide.eclipse.editors.resources.ResourcesEditor">
</sourceViewerConfiguration>
<sourceViewerConfiguration
- class="com.android.ide.eclipse.editors.layout.LayoutSourceViewerConfig"
+ class="com.android.ide.eclipse.adt.internal.editors.layout.LayoutSourceViewerConfig"
target="com.android.ide.eclipse.editors.layout.LayoutEditor">
</sourceViewerConfiguration>
<sourceViewerConfiguration
- class="com.android.ide.eclipse.editors.menu.MenuSourceViewerConfig"
+ class="com.android.ide.eclipse.adt.internal.editors.menu.MenuSourceViewerConfig"
target="com.android.ide.eclipse.editors.menu.MenuEditor">
</sourceViewerConfiguration>
<sourceViewerConfiguration
- class="com.android.ide.eclipse.editors.xml.XmlSourceViewerConfig"
+ class="com.android.ide.eclipse.adt.internal.editors.xml.XmlSourceViewerConfig"
target="com.android.ide.eclipse.editors.xml.XmlEditor">
</sourceViewerConfiguration>
</extension>
@@ -530,9 +530,9 @@
id="adt.actionSet.refactorings"
label="Android Refactorings"
visible="true">
-
+
<!-- This duplicates the Refactoring Menu definition from the jdt.ui plugin.xml,
- which allows us to insert our contribution even if the JDT is not loaded.
+ which allows us to insert our contribution even if the JDT is not loaded.
We overload the definition with our new group.-->
<menu
label="Refactor"
@@ -550,12 +550,12 @@
<separator name="scriptGroup"/>
</menu>
- <menu
- label="Android"
- path="org.eclipse.jdt.ui.refactoring.menu/androidGroup"
- id="com.android.ide.eclipse.adt.refactoring.menu">
- <separator name="android"/>
- </menu>
+ <menu
+ label="Android"
+ path="org.eclipse.jdt.ui.refactoring.menu/androidGroup"
+ id="com.android.ide.eclipse.adt.refactoring.menu">
+ <separator name="android"/>
+ </menu>
<action
class="com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringAction"
definitionId="com.android.ide.eclipse.adt.refactoring.extract.string"
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java
index ddfce4d..4464daa 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AndroidConstants.java
@@ -90,7 +90,7 @@
/** Name of the android sources directory */
public static final String FD_ANDROID_SOURCES = "sources"; //$NON-NLS-1$
-
+
/** Resource java class filename, i.e. "R.java" */
public final static String FN_RESOURCE_CLASS = "R.java"; //$NON-NLS-1$
/** Resource class file filename, i.e. "R.class" */
@@ -104,15 +104,11 @@
/** 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 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 =
- (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
- "adb.exe" : "adb"; //$NON-NLS-1$ //$NON-NLS-2$
+ public final static String FN_ADB = SdkConstants.FN_ADB;
- public final static String FN_EMULATOR =
- (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
- "emulator.exe" : "emulator"; //$NON-NLS-1$ //$NON-NLS-2$
+ public final static String FN_EMULATOR = SdkConstants.FN_EMULATOR;
public final static String FN_TRACEVIEW =
(SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
@@ -128,8 +124,8 @@
public final static String WS_ASSETS = WS_SEP + SdkConstants.FD_ASSETS;
/** Leaf of the javaDoc folder. Does not start with a separator. */
- public final static String WS_JAVADOC_FOLDER_LEAF = SdkConstants.FD_DOCS + "/" +
- SdkConstants.FD_DOCS_REFERENCE; //$NON-NLS-1$
+ public final static String WS_JAVADOC_FOLDER_LEAF = SdkConstants.FD_DOCS + "/" + //$NON-NLS-1$
+ SdkConstants.FD_DOCS_REFERENCE;
/** Path of the samples directory relative to the sdk folder.
* This is an OS path, ending with a separator.
@@ -159,10 +155,10 @@
/** aidl marker error. */
public final static String MARKER_AIDL = COMMON_PLUGIN_ID + ".aidlProblem"; //$NON-NLS-1$
-
+
/** android marker error */
public final static String MARKER_ANDROID = COMMON_PLUGIN_ID + ".androidProblem"; //$NON-NLS-1$
-
+
/** Name for the "type" marker attribute */
public final static String MARKER_ATTR_TYPE = "android.type"; //$NON-NLS-1$
/** Name for the "class" marker attribute */
@@ -176,9 +172,9 @@
/** provider value for marker attribute "type" */
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_SERVICE = "android.app.Service"; //$NON-NLS-1$
- public final static String CLASS_BROADCASTRECEIVER = "android.content.BroadcastReceiver"; //$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_BROADCASTRECEIVER = "android.content.BroadcastReceiver"; //$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_RUNNER =
@@ -202,7 +198,7 @@
"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_PARCELABLE = "android.os.Parcelable"; //$NON-NLS-1$
-
+
public final static String CLASS_BRIDGE = "com.android.layoutlib.bridge.Bridge"; //$NON-NLS-1$
/**
@@ -219,6 +215,6 @@
/** 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 LIBRARY_TEST_RUNNER = "android.test.runner"; // $NON-NLS-1$
}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java
index 92ddd84..725c6a8 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidContentAssist.java
@@ -16,6 +16,7 @@
package com.android.ide.eclipse.adt.internal.editors;
+import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
@@ -30,6 +31,7 @@
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
import com.android.sdklib.SdkConstants;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
@@ -74,7 +76,7 @@
/** Regexp to detect an element tag name */
private static Pattern sFirstElementWord = Pattern.compile("^[a-zA-Z0-9_:]+"); //$NON-NLS-1$
-
+
/** Regexp to detect whitespace */
private static Pattern sWhitespace = Pattern.compile("\\s+"); //$NON-NLS-1$
@@ -86,11 +88,11 @@
private ElementDescriptor mRootDescriptor;
private final int mDescriptorId;
-
+
private AndroidEditor mEditor;
/**
- * Constructor for AndroidContentAssist
+ * Constructor for AndroidContentAssist
* @param descriptorId An id for {@link AndroidTargetData#getDescriptorProvider(int)}.
* The Id can be one of {@link AndroidTargetData#DESCRIPTOR_MANIFEST},
* {@link AndroidTargetData#DESCRIPTOR_LAYOUT},
@@ -110,17 +112,22 @@
* @param viewer the viewer whose document is used to compute the proposals
* @param offset an offset within the document for which completions should be computed
* @return an array of completion proposals or <code>null</code> if no proposals are possible
- *
+ *
* @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer, int)
*/
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
-
+
if (mEditor == null) {
mEditor = getAndroidEditor(viewer);
+ if (mEditor == null) {
+ // This should not happen. Duck and forget.
+ AdtPlugin.log(IStatus.ERROR, "Editor not found during completion");
+ return null;
+ }
}
UiElementNode rootUiNode = mEditor.getUiRootNode();
-
+
Object[] choices = null; /* An array of ElementDescriptor, or AttributeDescriptor
or String or null */
String parent = ""; //$NON-NLS-1$
@@ -136,7 +143,12 @@
// check to see if we can find a UiElementNode matching this XML node
UiElementNode currentUiNode =
rootUiNode == null ? null : rootUiNode.findXmlNode(currentNode);
-
+
+ if (currentNode == null) {
+ // Should not happen (an XML doc always has at least a doc node). Just give up.
+ return null;
+ }
+
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
parent = currentNode.getNodeName();
@@ -154,7 +166,7 @@
// We're editing attributes in an element node (either the attributes' names
// or their values).
choices = getChoicesForAttribute(parent, currentNode, currentUiNode, info);
-
+
if (info.correctedPrefix != null) {
wordPrefix = info.correctedPrefix;
}
@@ -180,7 +192,7 @@
needTag = '<';
}
}
-
+
// get the selection length
int selectionLength = 0;
ISelection selection = viewer.getSelectionProvider().getSelection();
@@ -196,7 +208,7 @@
/**
* Returns the namespace prefix matching the Android Resource URI.
* If no such declaration is found, returns the default "android" prefix.
- *
+ *
* @param node The current node. Must not be null.
* @param nsUri The namespace URI of which the prefix is to be found,
* e.g. {@link SdkConstants#NS_RESOURCES}
@@ -210,9 +222,9 @@
if (XmlnsAttributeDescriptor.XMLNS_URI.equals(nsUri)) {
return "xmlns"; //$NON-NLS-1$
}
-
+
HashSet<String> visited = new HashSet<String>();
-
+
String prefix = null;
for (; prefix == null &&
node != null &&
@@ -230,7 +242,7 @@
}
}
}
-
+
// Use a sensible default prefix if we can't find one.
// We need to make sure the prefix is not one that was declared in the scope
// visited above.
@@ -251,7 +263,7 @@
* <p/>
* Example: <manifest><applic*cursor* => returns the list of all elements that
* can be found under <manifest>, of which <application> is one of the choices.
- *
+ *
* @return an ElementDescriptor[] or null if no valid element was found.
*/
private Object[] getChoicesForElement(String parent, Node current_node) {
@@ -287,8 +299,8 @@
* lenient as suitable for attribute values.
* - AttribInfo.needTag will be non-zero if we find that the attribute completion proposal
* must be double-quoted.
- * @param currentUiNode
- *
+ * @param currentUiNode
+ *
* @return an AttributeDescriptor[] if the user is editing an attribute name.
* a String[] if the user is editing an attribute value with some known values,
* or null if nothing is known about the context.
@@ -309,7 +321,7 @@
} else {
attrInfo.needTag = '"';
}
-
+
if (currentUiNode != null) {
// look for an UI attribute matching the current attribute name
String attrName = attrInfo.name;
@@ -329,7 +341,7 @@
if (currAttrNode != null) {
choices = currAttrNode.getPossibleValues(value);
-
+
if (currAttrNode instanceof UiFlagAttributeNode) {
// A "flag" can consist of several values separated by "or" (|).
// If the correct prefix contains such a pipe character, we change
@@ -345,7 +357,7 @@
if (choices == null) {
// fallback on the older descriptor-only based lookup.
-
+
// in order to properly handle the special case of the name attribute in
// the action tag, we need the grandparent of the action node, to know
// what type of actions we need.
@@ -358,7 +370,7 @@
greatGrandParentName = greatGrandParent.getLocalName();
}
}
-
+
AndroidTargetData data = mEditor.getTargetData();
if (data != null) {
choices = data.getAttributeValues(parent, attrInfo.name, greatGrandParentName);
@@ -382,7 +394,7 @@
* This means the user is editing outside of any XML element or attribute.
* Simply return the list of XML elements that can be present there, based on the
* parent of the current node.
- *
+ *
* @return An ElementDescriptor[] or null.
*/
private Object[] getChoicesForTextNode(Node currentNode) {
@@ -413,7 +425,7 @@
* - AttributeDescriptor: a possible attribute descriptor which XML name should be completed.
* - String: string values to display as-is to the user. Typically those are possible
* values for a given attribute.
- *
+ *
* @return The ICompletionProposal[] to display to the user.
*/
private ICompletionProposal[] computeProposals(int offset, Node currentNode,
@@ -421,7 +433,7 @@
boolean is_attribute, int selectionLength) {
ArrayList<CompletionProposal> proposals = new ArrayList<CompletionProposal>();
HashMap<String, String> nsUriMap = new HashMap<String, String>();
-
+
for (Object choice : choices) {
String keyword = null;
String nsPrefix = null;
@@ -441,7 +453,7 @@
if (choice instanceof TextAttributeDescriptor) {
tooltip = ((TextAttributeDescriptor) choice).getTooltip();
}
-
+
// Get the namespace URI for the attribute. Note that some attributes
// do not have a namespace and thus return null here.
String nsUri = ((AttributeDescriptor)choice).getNamespaceUri();
@@ -455,13 +467,13 @@
if (nsPrefix != null) {
nsPrefix += ":"; //$NON-NLS-1$
}
-
+
} else if (choice instanceof String) {
keyword = (String) choice;
} else {
continue; // discard unknown choice
}
-
+
String nsKeyword = nsPrefix == null ? keyword : (nsPrefix + keyword);
if (keyword.startsWith(wordPrefix) ||
@@ -499,7 +511,7 @@
proposals.add(proposal);
}
}
-
+
return proposals.toArray(new ICompletionProposal[proposals.size()]);
}
@@ -510,7 +522,7 @@
* <p/>
* Elements can have children if the descriptor has children element descriptors
* or if one of the attributes is a TextValueDescriptor.
- *
+ *
* @param descriptor An ElementDescriptor or an AttributeDescriptor
* @return True if the descriptor is an ElementDescriptor that can have children or a text value
*/
@@ -548,7 +560,7 @@
/**
* Returns the characters which when entered by the user should
* automatically trigger the presentation of possible completions.
- *
+ *
* In our case, we auto-activate on opening tags and attributes namespace.
*
* @return the auto activation characters for completion proposal or <code>null</code>
@@ -569,7 +581,7 @@
public String getErrorMessage() {
return null;
}
-
+
/**
* Heuristically extracts the prefix used for determining template relevance
* from the viewer's document. The default implementation returns the String from
@@ -578,7 +590,7 @@
*
* The part were we access the docment was extracted from
* org.eclipse.jface.text.templatesTemplateCompletionProcessor and adapted to our needs.
- *
+ *
* @param viewer the viewer
* @param offset offset into document
* @return the prefix to consider
@@ -611,7 +623,7 @@
return ""; //$NON-NLS-1$
}
}
-
+
/**
* Extracts the character at the given offset.
* Returns 0 if the offset is invalid.
@@ -676,7 +688,7 @@
// text will contain the full string of the current element,
// i.e. whatever is after the "<" to the current cursor
String text = document.get(offset, n - offset);
-
+
// Normalize whitespace to single spaces
text = sWhitespace.matcher(text).replaceAll(" "); //$NON-NLS-1$
@@ -684,13 +696,13 @@
// any whitespace. If there's nothing left, no attribute has been defined yet.
// Be sure to keep any whitespace after the initial word if any, as it matters.
text = sFirstElementWord.matcher(text).replaceFirst(""); //$NON-NLS-1$
-
+
// There MUST be space after the element name. If not, the cursor is still
// defining the element name.
if (!text.startsWith(" ")) { //$NON-NLS-1$
return null;
}
-
+
// Remove full attributes:
// Syntax:
// name = "..." quoted string with all but < and "
@@ -709,7 +721,7 @@
// merged with the previous one.
// - string with an = sign, optionally followed by a quote (' or "): the user is
// writing the value of the attribute.
- int pos_equal = text.indexOf('=');
+ int pos_equal = text.indexOf('=');
if (pos_equal == -1) {
info.isInValue = false;
info.name = text.trim();
@@ -749,7 +761,7 @@
return node;
}
-
+
/**
* Computes (if needed) and returns the root descriptor.
*/
@@ -758,17 +770,17 @@
AndroidTargetData data = mEditor.getTargetData();
if (data != null) {
IDescriptorProvider descriptorProvider = data.getDescriptorProvider(mDescriptorId);
-
+
if (descriptorProvider != null) {
mRootDescriptor = new ElementDescriptor("",
descriptorProvider.getRootElementDescriptors());
}
}
}
-
+
return mRootDescriptor;
}
-
+
/**
* Returns the active {@link AndroidEditor} matching this source viewer.
*/
@@ -789,7 +801,7 @@
return null;
}
-
-
+
+
}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/Messages.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/Messages.java
index 9b2803c..1474102 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/Messages.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/Messages.java
@@ -4,7 +4,7 @@
import org.eclipse.osgi.util.NLS;
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "com.android.ide.eclipse.adt.preferences.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = "com.android.ide.eclipse.adt.internal.preferences.messages"; //$NON-NLS-1$
public static String AndroidPreferencePage_ERROR_Reserved_Char;
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java
index 72ff51d..3deea23 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java
@@ -75,28 +75,28 @@
private final static String ACTION_MAIN = "android.intent.action.MAIN"; //$NON-NLS-1$
private final static String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; //$NON-NLS-1$
-
+
public final static int INVALID_MIN_SDK = -1;
-
+
/**
* Instrumentation info obtained from manifest
*/
public static class Instrumentation {
private final String mName;
private final String mTargetPackage;
-
+
Instrumentation(String name, String targetPackage) {
mName = name;
mTargetPackage = targetPackage;
}
-
+
/**
* Returns the fully qualified instrumentation class name
*/
public String getName() {
return mName;
}
-
+
/**
* Returns the Android app package that is the target of this instrumentation
*/
@@ -104,7 +104,7 @@
return mTargetPackage;
}
}
-
+
/**
* Activity info obtained from the manifest.
*/
@@ -114,32 +114,32 @@
private boolean mHasAction = false;
private boolean mHasMainAction = false;
private boolean mHasLauncherCategory = false;
-
+
public Activity(String name, boolean exported) {
mName = name;
mIsExported = exported;
}
-
+
public String getName() {
return mName;
}
-
+
public boolean isExported() {
return mIsExported;
}
-
+
public boolean hasAction() {
return mHasAction;
}
-
+
public boolean isHomeActivity() {
return mHasMainAction && mHasLauncherCategory;
}
-
+
void setHasAction(boolean hasAction) {
mHasAction = hasAction;
}
-
+
/** If the activity doesn't yet have a filter set for the launcher, this resets both
* flags. This is to handle multiple intent-filters where one could have the valid
* action, and another one of the valid category.
@@ -149,16 +149,16 @@
mHasMainAction = mHasLauncherCategory = false;
}
}
-
+
void setHasMainAction(boolean hasMainAction) {
mHasMainAction = hasMainAction;
}
-
+
void setHasLauncherCategory(boolean hasLauncherCategory) {
mHasLauncherCategory = hasLauncherCategory;
}
}
-
+
/**
* XML error & data handler used when parsing the AndroidManifest.xml file.
* <p/>
@@ -166,9 +166,9 @@
* to collect data from the manifest.
*/
private static class ManifestHandler extends XmlErrorHandler {
-
+
//--- data read from the parsing
-
+
/** Application package */
private String mPackage;
/** List of all activities */
@@ -196,10 +196,10 @@
private int mValidLevel = 0;
private Activity mCurrentActivity = null;
private Locator mLocator;
-
+
/**
* Creates a new {@link ManifestHandler}, which is also an {@link XmlErrorHandler}.
- *
+ *
* @param manifestFile The manifest file being parsed. Can be null.
* @param errorListener An optional error listener.
* @param gatherData True if data should be gathered.
@@ -221,24 +221,24 @@
String getPackage() {
return mPackage;
}
-
- /**
+
+ /**
* Returns the list of activities found in the manifest.
* @return An array of fully qualified class names, or empty if no activity were found.
*/
Activity[] getActivities() {
return mActivities.toArray(new Activity[mActivities.size()]);
}
-
+
/**
* Returns the name of one activity found in the manifest, that is configured to show
- * up in the HOME screen.
- * @return the fully qualified name of a HOME activity or null if none were found.
+ * up in the HOME screen.
+ * @return the fully qualified name of a HOME activity or null if none were found.
*/
Activity getLauncherActivity() {
return mLauncherActivity;
}
-
+
/**
* Returns the list of process names declared by the manifest.
*/
@@ -246,42 +246,42 @@
if (mProcesses != null) {
return mProcesses.toArray(new String[mProcesses.size()]);
}
-
+
return new String[0];
}
-
+
/**
* Returns the <code>debuggable</code> attribute value or null if it is not set.
*/
Boolean getDebuggable() {
return mDebuggable;
}
-
+
/**
* Returns the <code>minSdkVersion</code> attribute, or
- * {@link AndroidManifestParser#INVALID_MIN_SDK} if it's not set.
+ * {@link AndroidManifestParser#INVALID_MIN_SDK} if it's not set.
*/
int getApiLevelRequirement() {
return mApiLevelRequirement;
}
-
- /**
+
+ /**
* Returns the list of instrumentations found in the manifest.
- * @return An array of {@link Instrumentation}, or empty if no instrumentations were
+ * @return An array of {@link Instrumentation}, or empty if no instrumentations were
* found.
*/
Instrumentation[] getInstrumentations() {
return mInstrumentations.toArray(new Instrumentation[mInstrumentations.size()]);
}
-
- /**
+
+ /**
* Returns the list of libraries in use found in the manifest.
* @return An array of library names, or empty if no libraries were found.
*/
String[] getUsesLibraries() {
return mLibraries.toArray(new String[mLibraries.size()]);
}
-
+
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#setDocumentLocator(org.xml.sax.Locator)
*/
@@ -290,7 +290,7 @@
mLocator = locator;
super.setDocumentLocator(locator);
}
-
+
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
* java.lang.String, org.xml.sax.Attributes)
@@ -322,18 +322,18 @@
if (value != null) {
addProcessName(value);
}
-
+
value = getAttributeValue(attributes, ATTRIBUTE_DEBUGGABLE,
true /* hasNamespace*/);
if (value != null) {
mDebuggable = Boolean.parseBoolean(value);
}
-
+
mValidLevel++;
} else if (NODE_USES_SDK.equals(localName)) {
value = getAttributeValue(attributes, ATTRIBUTE_MIN_SDK_VERSION,
true /* hasNamespace */);
-
+
if (value != null) {
try {
mApiLevelRequirement = Integer.parseInt(value);
@@ -343,7 +343,7 @@
}
} else if (NODE_INSTRUMENTATION.equals(localName)) {
processInstrumentationNode(attributes);
- }
+ }
break;
case LEVEL_ACTIVITY:
if (NODE_ACTIVITY.equals(localName)) {
@@ -364,7 +364,7 @@
if (value != null) {
mLibraries.add(value);
}
- }
+ }
break;
case LEVEL_INTENT_FILTER:
// only process this level if we are in an activity
@@ -391,7 +391,7 @@
mCurrentActivity.setHasLauncherCategory(true);
}
}
-
+
// no need to increase mValidLevel as we don't process anything
// below this level.
}
@@ -415,13 +415,13 @@
if (mGatherData == false) {
return;
}
-
+
// decrement the levels.
if (mValidLevel == mCurrentLevel) {
mValidLevel--;
}
mCurrentLevel--;
-
+
// if we're at a valid level
// process the end of the element
if (mValidLevel == mCurrentLevel) {
@@ -442,13 +442,13 @@
default:
break;
}
-
+
}
} finally {
super.endElement(uri, localName, name);
}
}
-
+
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
*/
@@ -478,7 +478,7 @@
super.warning(e);
}
}
-
+
/**
* Processes the activity node.
* @param attributes the attributes for the activity node.
@@ -489,14 +489,14 @@
true /* hasNamespace */);
if (activityName != null) {
activityName = combinePackageAndClassName(mPackage, activityName);
-
+
// get the exported flag.
String exportedStr = getAttributeValue(attributes, ATTRIBUTE_EXPORTED, true);
boolean exported = exportedStr == null ||
exportedStr.toLowerCase().equals("true"); // $NON-NLS-1$
mCurrentActivity = new Activity(activityName, exported);
mActivities.add(mCurrentActivity);
-
+
if (mMarkErrors) {
checkClass(activityName, AndroidConstants.CLASS_ACTIVITY,
true /* testVisibility */);
@@ -506,7 +506,7 @@
// so we don't have to do anything
mCurrentActivity = null;
}
-
+
String processName = getAttributeValue(attributes, ATTRIBUTE_PROCESS,
true /* hasNamespace */);
if (processName != null) {
@@ -526,19 +526,19 @@
true /* hasNamespace */);
if (serviceName != null) {
serviceName = combinePackageAndClassName(mPackage, serviceName);
-
+
if (mMarkErrors) {
checkClass(serviceName, superClassName, false /* testVisibility */);
}
}
-
+
String processName = getAttributeValue(attributes, ATTRIBUTE_PROCESS,
true /* hasNamespace */);
if (processName != null) {
addProcessName(processName);
}
}
-
+
/**
* Processes the instrumentation nodes.
* @param attributes the attributes for the activity node.
@@ -563,7 +563,7 @@
/**
* Checks that a class is valid and can be used in the Android Manifest.
* <p/>
- * Errors are put as {@link IMarker} on the manifest file.
+ * Errors are put as {@link IMarker} on the manifest file.
* @param className the fully qualified name of the class to test.
* @param superClassName the fully qualified name of the class it is supposed to extend.
* @param testVisibility if <code>true</code>, the method will check the visibility of
@@ -579,12 +579,12 @@
if (result != BaseProjectHelper.TEST_CLASS_OK) {
// get the line number
int line = mLocator.getLineNumber();
-
+
// mark the file
IMarker marker = BaseProjectHelper.addMarker(getFile(),
AndroidConstants.MARKER_ANDROID,
result, line, IMarker.SEVERITY_ERROR);
-
+
// add custom attributes to be used by the manifest editor.
if (marker != null) {
try {
@@ -594,7 +594,7 @@
} catch (CoreException e) {
}
}
- }
+ }
}
/**
@@ -616,21 +616,21 @@
return attributes.getValue(i);
}
}
-
+
return null;
}
-
+
private void addProcessName(String processName) {
if (mProcesses == null) {
mProcesses = new TreeSet<String>();
}
-
+
mProcesses.add(processName);
}
}
private static SAXParserFactory sParserFactory;
-
+
private final String mJavaPackage;
private final Activity[] mActivities;
private final Activity mLauncherActivity;
@@ -644,14 +644,14 @@
sParserFactory = SAXParserFactory.newInstance();
sParserFactory.setNamespaceAware(true);
}
-
+
/**
* Parses the Android Manifest, and returns an object containing the result of the parsing.
* <p/>
* This method is useful to parse a specific {@link IFile} in a Java project.
* <p/>
* If you only want to gather data, consider {@link #parseForData(IFile)} instead.
- *
+ *
* @param javaProject The java project.
* @param manifestFile the {@link IFile} representing the manifest file.
* @param errorListener
@@ -670,41 +670,42 @@
boolean markErrors)
throws CoreException {
try {
- SAXParser parser = sParserFactory.newSAXParser();
+ if (manifestFile != null) {
+ SAXParser parser = sParserFactory.newSAXParser();
- ManifestHandler manifestHandler = new ManifestHandler(manifestFile,
- errorListener, gatherData, javaProject, markErrors);
- parser.parse(new InputSource(manifestFile.getContents()), manifestHandler);
-
- // get the result from the handler
-
- return new AndroidManifestParser(manifestHandler.getPackage(),
- manifestHandler.getActivities(),
- manifestHandler.getLauncherActivity(),
- manifestHandler.getProcesses(),
- manifestHandler.getDebuggable(),
- manifestHandler.getApiLevelRequirement(),
- manifestHandler.getInstrumentations(),
- manifestHandler.getUsesLibraries());
+ ManifestHandler manifestHandler = new ManifestHandler(manifestFile,
+ errorListener, gatherData, javaProject, markErrors);
+ parser.parse(new InputSource(manifestFile.getContents()), manifestHandler);
+
+ // get the result from the handler
+ return new AndroidManifestParser(manifestHandler.getPackage(),
+ manifestHandler.getActivities(),
+ manifestHandler.getLauncherActivity(),
+ manifestHandler.getProcesses(),
+ manifestHandler.getDebuggable(),
+ manifestHandler.getApiLevelRequirement(),
+ manifestHandler.getInstrumentations(),
+ manifestHandler.getUsesLibraries());
+ }
} catch (ParserConfigurationException e) {
- AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
+ AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Bad parser configuration for %s: %s",
manifestFile.getFullPath(),
e.getMessage());
} catch (SAXException e) {
- AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
+ AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Parser exception for %s: %s",
manifestFile.getFullPath(),
e.getMessage());
} catch (IOException e) {
// Don't log a console error when failing to read a non-existing file
if (!(e instanceof FileNotFoundException)) {
- AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
+ AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"I/O error for %s: %s",
manifestFile.getFullPath(),
e.getMessage());
}
- }
+ }
return null;
}
@@ -716,7 +717,7 @@
* parsing a file that is not part of an Eclipse Java project.
* <p/>
* It assumes errors cannot be marked on the file and that data gathering is enabled.
- *
+ *
* @param manifestFile the manifest file to parse.
* @return an {@link AndroidManifestParser} or null if the parsing failed.
* @throws CoreException
@@ -733,11 +734,11 @@
null, //javaProject
false //markErrors
);
-
+
parser.parse(new InputSource(new FileReader(manifestFile)), manifestHandler);
-
+
// get the result from the handler
-
+
return new AndroidManifestParser(manifestHandler.getPackage(),
manifestHandler.getActivities(),
manifestHandler.getLauncherActivity(),
@@ -747,25 +748,25 @@
manifestHandler.getInstrumentations(),
manifestHandler.getUsesLibraries());
} catch (ParserConfigurationException e) {
- AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
+ AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Bad parser configuration for %s: %s",
manifestFile.getAbsolutePath(),
e.getMessage());
} catch (SAXException e) {
- AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
+ AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Parser exception for %s: %s",
manifestFile.getAbsolutePath(),
e.getMessage());
} catch (IOException e) {
// Don't log a console error when failing to read a non-existing file
if (!(e instanceof FileNotFoundException)) {
- AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
+ AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"I/O error for %s: %s",
manifestFile.getAbsolutePath(),
e.getMessage());
}
}
-
+
return null;
}
@@ -788,9 +789,9 @@
boolean gatherData,
boolean markErrors)
throws CoreException {
-
+
IFile manifestFile = getManifest(javaProject.getProject());
-
+
try {
SAXParser parser = sParserFactory.newSAXParser();
@@ -799,25 +800,25 @@
errorListener, gatherData, javaProject, markErrors);
parser.parse(new InputSource(manifestFile.getContents()), manifestHandler);
-
+
// get the result from the handler
return new AndroidManifestParser(manifestHandler.getPackage(),
manifestHandler.getActivities(), manifestHandler.getLauncherActivity(),
manifestHandler.getProcesses(), manifestHandler.getDebuggable(),
- manifestHandler.getApiLevelRequirement(),
+ manifestHandler.getApiLevelRequirement(),
manifestHandler.getInstrumentations(), manifestHandler.getUsesLibraries());
}
} catch (ParserConfigurationException e) {
- AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
+ AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Bad parser configuration for %s", manifestFile.getFullPath());
} catch (SAXException e) {
- AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
+ AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"Parser exception for %s", manifestFile.getFullPath());
} catch (IOException e) {
- AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
+ AdtPlugin.logAndPrintError(e, AndroidManifestParser.class.getCanonicalName(),
"I/O error for %s", manifestFile.getFullPath());
- }
-
+ }
+
return null;
}
@@ -849,7 +850,7 @@
/**
* Parses the manifest file, and collects data.
- *
+ *
* @param osManifestFilePath The OS path of the manifest file to parse.
* @return an {@link AndroidManifestParser} or null if the parsing failed.
*/
@@ -871,7 +872,7 @@
return mJavaPackage;
}
- /**
+ /**
* Returns the list of activities found in the manifest.
* @return An array of {@link Activity}, or empty if no activity were found.
*/
@@ -881,35 +882,35 @@
/**
* Returns the name of one activity found in the manifest, that is configured to show
- * up in the HOME screen.
- * @return The {@link Activity} representing a HOME activity or null if none were found.
+ * up in the HOME screen.
+ * @return The {@link Activity} representing a HOME activity or null if none were found.
*/
public Activity getLauncherActivity() {
return mLauncherActivity;
}
-
+
/**
* Returns the list of process names declared by the manifest.
*/
public String[] getProcesses() {
return mProcesses;
}
-
+
/**
* Returns the debuggable attribute value or <code>null</code> if it is not set.
*/
public Boolean getDebuggable() {
return mDebuggable;
}
-
+
/**
* Returns the <code>minSdkVersion</code> attribute, or {@link #INVALID_MIN_SDK}
- * if it's not set.
+ * if it's not set.
*/
public int getApiLevelRequirement() {
return mApiLevelRequirement;
}
-
+
/**
* Returns the list of instrumentations found in the manifest.
* @return An array of {@link Instrumentation}, or empty if no instrumentations were found.
@@ -917,7 +918,7 @@
public Instrumentation[] getInstrumentations() {
return mInstrumentations;
}
-
+
/**
* Returns the list of libraries in use found in the manifest.
* @return An array of library names, or empty if no uses-library declarations were found.
@@ -926,7 +927,7 @@
return mLibraries;
}
-
+
/**
* Private constructor to enforce using
* {@link #parse(IJavaProject, XmlErrorListener, boolean, boolean)},
@@ -977,7 +978,7 @@
* Combines a java package, with a class value from the manifest to make a fully qualified
* class name
* @param javaPackage the java package from the manifest.
- * @param className the class name from the manifest.
+ * @param className the class name from the manifest.
* @return the fully qualified class name.
*/
public static String combinePackageAndClassName(String javaPackage, String className) {
@@ -1010,8 +1011,8 @@
* Given a fully qualified activity name (e.g. com.foo.test.MyClass) and given a project
* package base name (e.g. com.foo), returns the relative activity name that would be used
* the "name" attribute of an "activity" element.
- *
- * @param fullActivityName a fully qualified activity class name, e.g. "com.foo.test.MyClass"
+ *
+ * @param fullActivityName a fully qualified activity class name, e.g. "com.foo.test.MyClass"
* @param packageName The project base package name, e.g. "com.foo"
* @return The relative activity name if it can be computed or the original fullActivityName.
*/
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java
index 93c27b7..df716b2 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java
@@ -26,6 +26,7 @@
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
@@ -42,7 +43,7 @@
public final class CompiledResourcesMonitor implements IFileListener, IProjectListener {
private final static CompiledResourcesMonitor sThis = new CompiledResourcesMonitor();
-
+
/**
* Sets up the monitoring system.
* @param monitor The main Resource Monitor.
@@ -62,12 +63,12 @@
/* (non-Javadoc)
* Sent when a file changed : if the file is the R class, then it is parsed again to update
* the internal data.
- *
+ *
* @param file The file that changed.
* @param markerDeltas The marker deltas for the file.
* @param kind The change kind. This is equivalent to
* {@link IResourceDelta#accept(IResourceDeltaVisitor)}
- *
+ *
* @see IFileListener#fileChanged
*/
public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) {
@@ -111,7 +112,7 @@
// pass
}
}
-
+
private void loadAndParseRClass(IProject project) {
try {
// first check there's a ProjectResources to store the content
@@ -129,13 +130,13 @@
return;
}
- // create a temporary class loader to load it.
+ // create a temporary class loader to load it.
ProjectClassLoader loader = new ProjectClassLoader(null /* parentClassLoader */,
project);
-
+
try {
Class<?> clazz = loader.loadClass(className);
-
+
if (clazz != null) {
// create the maps to store the result of the parsing
Map<String, Map<String, Integer>> resourceValueMap =
@@ -144,7 +145,7 @@
new HashMap<Integer, String[]>();
Map<IntArrayWrapper, String> styleableValueToNameMap =
new HashMap<IntArrayWrapper, String>();
-
+
// parse the class
if (parseClass(clazz, genericValueToNameMap, styleableValueToNameMap,
resourceValueMap)) {
@@ -180,7 +181,7 @@
Map<String, Integer> fullMap = new HashMap<String, Integer>();
resourceValueMap.put(resType, fullMap);
-
+
for (Field f : inner.getDeclaredFields()) {
// only process static final fields.
int modifiers = f.getModifiers();
@@ -191,7 +192,7 @@
styleableValueToNameMap.put(new IntArrayWrapper((int[]) f.get(null)),
f.getName());
} else if (type == int.class) {
- Integer value = (Integer) f.get(null);
+ Integer value = (Integer) f.get(null);
genericValueToNameMap.put(value, new String[] { f.getName(), resType });
fullMap.put(f.getName(), value);
} else {
@@ -210,16 +211,18 @@
/**
* Returns the class name of the R class, based on the project's manifest's package.
- *
+ *
* @return A class name (e.g. "my.app.R") or null if there's no valid package in the manifest.
*/
private String getRClassName(IProject project) {
try {
IFile manifestFile = AndroidManifestParser.getManifest(project);
- AndroidManifestParser data = AndroidManifestParser.parseForData(manifestFile);
- if (data != null) {
- String javaPackage = data.getPackage();
- return javaPackage + ".R"; //$NON-NLS-1$
+ if (manifestFile != null && manifestFile.isSynchronized(IResource.DEPTH_ZERO)) {
+ AndroidManifestParser data = AndroidManifestParser.parseForData(manifestFile);
+ if (data != null) {
+ String javaPackage = data.getPackage();
+ return javaPackage + ".R"; //$NON-NLS-1$
+ }
}
} catch (CoreException e) {
// This will typically happen either because the manifest file is not present
@@ -232,5 +235,5 @@
}
return null;
}
-
+
}
diff --git a/tools/scripts/android_rules.xml b/tools/scripts/android_rules.xml
index 236327c..1f5daac 100644
--- a/tools/scripts/android_rules.xml
+++ b/tools/scripts/android_rules.xml
@@ -205,7 +205,7 @@
<echo>Uninstalling ${application-package} from the default emulator...</echo>
<exec executable="${adb}" failonerror="true">
<arg value="uninstall" />
- <arg path="${application-package}" />
+ <arg value="${application-package}" />
</exec>
</target>
diff --git a/tools/sdkmanager/app/src/Android.mk b/tools/sdkmanager/app/src/Android.mk
index b508076..6346349 100644
--- a/tools/sdkmanager/app/src/Android.mk
+++ b/tools/sdkmanager/app/src/Android.mk
@@ -9,7 +9,11 @@
LOCAL_JAVA_LIBRARIES := \
androidprefs \
sdklib \
- sdkuilib
+ sdkuilib \
+ 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 := sdkmanager
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
index 8c9ad26..26af498 100644
--- a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
+++ b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
@@ -29,13 +29,13 @@
import com.android.sdklib.internal.avd.HardwareProperties.HardwareProperty;
import com.android.sdklib.internal.project.ProjectCreator;
import com.android.sdklib.internal.project.ProjectCreator.OutputLevel;
+import com.android.sdkmanager.internal.repository.AboutPage;
+import com.android.sdkmanager.internal.repository.SettingsPage;
import com.android.sdkuilib.repository.UpdaterWindow;
import java.io.File;
-import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -53,9 +53,6 @@
private final static String[] BOOLEAN_YES_REPLIES = new String[] { "yes", "y" };
private final static String[] BOOLEAN_NO_REPLIES = new String[] { "no", "n" };
- /** Preference file containing the usb ids for adb */
- private final static String ADB_INI = "adb_usb.ini";
-
/** Path to the SDK folder. This is the parent of {@link #TOOLSDIR}. */
private String mOsSdkFolder;
/** Logger object. Use this to print normal output, warnings or errors. */
@@ -243,8 +240,11 @@
private void showMainWindow() {
try {
UpdaterWindow window = new UpdaterWindow(
+ mSdkLog,
mOsSdkFolder,
false /*userCanChangeSdkRoot*/);
+ window.registerPage("Settings", SettingsPage.class);
+ window.registerPage("About", AboutPage.class);
window.open();
} catch (Exception e) {
e.printStackTrace();
@@ -758,26 +758,8 @@
* Updates adb with the USB devices declared in the SDK add-ons.
*/
private void updateAdb() {
- FileWriter writer = null;
try {
- // get the android prefs location to know where to write the file.
- File adbIni = new File(AndroidLocation.getFolder(), ADB_INI);
- writer = new FileWriter(adbIni);
-
- // first, put all the vendor id in an HashSet to remove duplicate.
- HashSet<Integer> set = new HashSet<Integer>();
- IAndroidTarget[] targets = mSdkManager.getTargets();
- for (IAndroidTarget target : targets) {
- if (target.getUsbVendorId() != IAndroidTarget.NO_USB_ID) {
- set.add(target.getUsbVendorId());
- }
- }
-
- // now write the Id in a text file, one per line.
- for (Integer i : set) {
- writer.write(i.toString());
- writer.write("\n");
- }
+ mSdkManager.updateAdb();
mSdkLog.printf(
"adb has been updated. You must restart adb with the following commands\n" +
@@ -787,14 +769,6 @@
errorAndExit(e.getMessage());
} catch (IOException e) {
errorAndExit(e.getMessage());
- } finally {
- if (writer != null) {
- try {
- writer.close();
- } catch (IOException e) {
- // ignore
- }
- }
}
}
diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/AboutPage.java b/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/AboutPage.java
new file mode 100755
index 0000000..49aad29
--- /dev/null
+++ b/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/AboutPage.java
@@ -0,0 +1,72 @@
+/*
+ * 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.sdkmanager.internal.repository;
+
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+/*
+ * TODO list
+ * - Change version to be a constant pulled from somewhere.
+ */
+
+public class AboutPage extends Composite {
+
+ private Label mLabel;
+
+ /**
+ * Create the composite.
+ * @param parent The parent of the composite.
+ */
+ public AboutPage(Composite parent) {
+ super(parent, SWT.BORDER);
+
+ createContents(this);
+
+ postCreate(); //$hide$
+ }
+
+ private void createContents(Composite parent) {
+ parent.setLayout(new GridLayout(1, false));
+
+ mLabel = new Label(parent, SWT.NONE);
+ mLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true, 1, 1));
+ mLabel.setText("Android SDK Updater.\n\nVersion 0.1.\n\nCopyright (C) 2009 The Android Open Source Project.");
+ }
+
+ @Override
+ protected void checkSubclass() {
+ // Disable the check that prevents subclassing of SWT components
+ }
+
+ // -- Start of internal part ----------
+ // Hide everything down-below from SWT designer
+ //$hide>>$
+
+ /**
+ * Called by the constructor right after {@link #createContents(Composite)}.
+ */
+ private void postCreate() {
+ }
+
+ // End of hiding from SWT Designer
+ //$hide<<$
+}
diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/SettingsPage.java b/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/SettingsPage.java
new file mode 100755
index 0000000..df72cf9
--- /dev/null
+++ b/tools/sdkmanager/app/src/com/android/sdkmanager/internal/repository/SettingsPage.java
@@ -0,0 +1,109 @@
+/*
+ * 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.sdkmanager.internal.repository;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/*
+ * TODO list
+ * - The window should probably set a callback to be notified when settings are changed.
+ * - Actually use the settings.
+ */
+
+public class SettingsPage extends Composite {
+
+ private Group mProxySettingsGroup;
+ private Group mPlaceholderGroup;
+ private Button mApplyButton;
+ private Label mSomeMoreSettings;
+ private Label mProxyServerLabel;
+ private Label mProxyPortLabel;
+ private Text mProxyServerText;
+ private Text mProxyPortText;
+
+ /**
+ * Create the composite.
+ * @param parent The parent of the composite.
+ */
+ public SettingsPage(Composite parent) {
+ super(parent, SWT.BORDER);
+
+ createContents(this);
+
+ mProxySettingsGroup = new Group(this, SWT.NONE);
+ mProxySettingsGroup.setText("Proxy Settings");
+ mProxySettingsGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+ mProxySettingsGroup.setLayout(new GridLayout(2, false));
+
+ mProxyServerLabel = new Label(mProxySettingsGroup, SWT.NONE);
+ mProxyServerLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ mProxyServerLabel.setText("HTTP Proxy Server");
+
+ mProxyServerText = new Text(mProxySettingsGroup, SWT.BORDER);
+ mProxyServerText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ mProxyPortLabel = new Label(mProxySettingsGroup, SWT.NONE);
+ mProxyPortLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ mProxyPortLabel.setText("HTTP Proxy Port");
+
+ mProxyPortText = new Text(mProxySettingsGroup, SWT.BORDER);
+ mProxyPortText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ mPlaceholderGroup = new Group(this, SWT.NONE);
+ mPlaceholderGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+ mPlaceholderGroup.setText("Placeholder");
+ mPlaceholderGroup.setLayout(new GridLayout(1, false));
+
+ mSomeMoreSettings = new Label(mPlaceholderGroup, SWT.NONE);
+ mSomeMoreSettings.setText("Some more settings here");
+
+ mApplyButton = new Button(this, SWT.NONE);
+ mApplyButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ mApplyButton.setText("Apply");
+
+ postCreate(); //$hide$
+ }
+
+ private void createContents(Composite parent) {
+ parent.setLayout(new GridLayout(1, false));
+ }
+
+ @Override
+ protected void checkSubclass() {
+ // Disable the check that prevents subclassing of SWT components
+ }
+
+ // -- Start of internal part ----------
+ // Hide everything down-below from SWT designer
+ //$hide>>$
+
+ /**
+ * Called by the constructor right after {@link #createContents(Composite)}.
+ */
+ private void postCreate() {
+ }
+
+ // End of hiding from SWT Designer
+ //$hide<<$
+}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
index 75b1d65..d988340 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
@@ -24,57 +24,57 @@
public interface IAndroidTarget extends Comparable<IAndroidTarget> {
/** OS Path to the "android.jar" file. */
- public static int ANDROID_JAR = 1;
+ public final static int ANDROID_JAR = 1;
/** OS Path to the "framework.aidl" file. */
- public static int ANDROID_AIDL = 2;
+ public final static int ANDROID_AIDL = 2;
/** OS Path to "images" folder which contains the emulator system images. */
- public static int IMAGES = 3;
+ public final static int IMAGES = 3;
/** OS Path to the "samples" folder which contains sample projects. */
- public static int SAMPLES = 4;
+ public final static int SAMPLES = 4;
/** OS Path to the "skins" folder which contains the emulator skins. */
- public static int SKINS = 5;
+ public final static int SKINS = 5;
/** OS Path to the "templates" folder which contains the templates for new projects. */
- public static int TEMPLATES = 6;
+ public final static int TEMPLATES = 6;
/** OS Path to the "data" folder which contains data & libraries for the SDK tools. */
- public static int DATA = 7;
+ public final static int DATA = 7;
/** OS Path to the "attrs.xml" file. */
- public static int ATTRIBUTES = 8;
+ public final static int ATTRIBUTES = 8;
/** OS Path to the "attrs_manifest.xml" file. */
- public static int MANIFEST_ATTRIBUTES = 9;
+ public final static int MANIFEST_ATTRIBUTES = 9;
/** OS Path to the "data/layoutlib.jar" library. */
- public static int LAYOUT_LIB = 10;
+ public final static int LAYOUT_LIB = 10;
/** OS Path to the "data/res" folder. */
- public static int RESOURCES = 11;
+ public final static int RESOURCES = 11;
/** OS Path to the "data/fonts" folder. */
- public static int FONTS = 12;
+ public final static int FONTS = 12;
/** OS Path to the "data/widgets.txt" file. */
- public static int WIDGETS = 13;
+ public final static int WIDGETS = 13;
/** OS Path to the "data/activity_actions.txt" file. */
- public static int ACTIONS_ACTIVITY = 14;
+ public final static int ACTIONS_ACTIVITY = 14;
/** OS Path to the "data/broadcast_actions.txt" file. */
- public static int ACTIONS_BROADCAST = 15;
+ public final static int ACTIONS_BROADCAST = 15;
/** OS Path to the "data/service_actions.txt" file. */
- public static int ACTIONS_SERVICE = 16;
+ public final static int ACTIONS_SERVICE = 16;
/** OS Path to the "data/categories.txt" file. */
- public static int CATEGORIES = 17;
+ public final static int CATEGORIES = 17;
/** OS Path to the "sources" folder. */
- public static int SOURCES = 18;
+ public final static int SOURCES = 18;
/** OS Path to the target specific docs */
- public static int DOCS = 19;
+ public final static int DOCS = 19;
/** OS Path to the target's version of the aapt tool. */
- public static int AAPT = 20;
+ public final static int AAPT = 20;
/** OS Path to the target's version of the aidl tool. */
- public static int AIDL = 21;
+ public final static int AIDL = 21;
/** OS Path to the target's version of the dx too. */
- public static int DX = 22;
+ public final static int DX = 22;
/** OS Path to the target's version of the dx.jar file. */
- public static int DX_JAR = 23;
+ public final static int DX_JAR = 23;
/**
* Return value for {@link #getUsbVendorId()} meaning no USB vendor IDs are defined by the
* Android target.
*/
- public static int NO_USB_ID = 0;
+ public final static int NO_USB_ID = 0;
public interface IOptionalLibrary {
String getName();
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
index 557f354..32b9a2e 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
@@ -82,18 +82,26 @@
/** dex.jar file */
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) ?
"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) ?
"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) ?
"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 . */
/** Resources folder name, i.e. "res". */
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
index 5827aa1..ebafa77 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
@@ -16,15 +16,20 @@
package com.android.sdklib;
+import com.android.prefs.AndroidLocation;
+import com.android.prefs.AndroidLocation.AndroidLocationException;
+
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -68,6 +73,14 @@
SdkConstants.OS_SDK_TOOLS_LIB_FOLDER + SdkConstants.FN_DX_JAR,
};
+ /** Preference file containing the usb ids for adb */
+ private final static String ADB_INI_FILE = "adb_usb.ini";
+ //0--------90--------90--------90--------90--------90--------90--------90--------9
+ private final static String ADB_INI_HEADER =
+ "# ANDROID 3RD PARTY USB VENDOR ID LIST -- DO NOT EDIT.\n" +
+ "# USE 'android update adb' TO GENERATE.\n" +
+ "# 1 USB VENDOR ID PER LINE.\n";
+
/** the location of the SDK */
private final String mSdkLocation;
private IAndroidTarget[] mTargets;
@@ -132,6 +145,38 @@
return null;
}
+ /**
+ * Updates adb with the USB devices declared in the SDK add-ons.
+ * @throws AndroidLocationException
+ * @throws IOException
+ */
+ public void updateAdb() throws AndroidLocationException, IOException {
+ FileWriter writer = null;
+ try {
+ // get the android prefs location to know where to write the file.
+ File adbIni = new File(AndroidLocation.getFolder(), ADB_INI_FILE);
+ writer = new FileWriter(adbIni);
+
+ // first, put all the vendor id in an HashSet to remove duplicate.
+ HashSet<Integer> set = new HashSet<Integer>();
+ IAndroidTarget[] targets = getTargets();
+ for (IAndroidTarget target : targets) {
+ if (target.getUsbVendorId() != IAndroidTarget.NO_USB_ID) {
+ set.add(target.getUsbVendorId());
+ }
+ }
+
+ // write file header.
+ writer.write(ADB_INI_HEADER);
+
+ // now write the Id in a text file, one per line.
+ for (Integer i : set) {
+ writer.write(String.format("0x%04x\n", i));
+ }
+ } finally {
+ writer.close();
+ }
+ }
private SdkManager(String sdkLocation) {
mSdkLocation = sdkLocation;
@@ -375,13 +420,6 @@
// get the default skin, or take it from the base platform if needed.
String defaultSkin = propertyMap.get(ADDON_DEFAULT_SKIN);
-
- // get the USB ID (if available)
- int usbVendorId = convertId(propertyMap.get(ADDON_USB_VENDOR));
- if (usbVendorId != IAndroidTarget.NO_USB_ID) {
- target.setUsbVendorId(usbVendorId);
- }
-
if (defaultSkin == null) {
if (skins.length == 1) {
defaultSkin = skins[1];
@@ -390,6 +428,12 @@
}
}
+ // get the USB ID (if available)
+ int usbVendorId = convertId(propertyMap.get(ADDON_USB_VENDOR));
+ if (usbVendorId != IAndroidTarget.NO_USB_ID) {
+ target.setUsbVendorId(usbVendorId);
+ }
+
target.setSkins(skins, defaultSkin);
return target;
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
new file mode 100755
index 0000000..bd76a4c
--- /dev/null
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
@@ -0,0 +1,201 @@
+/*
+ * 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.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 org.w3c.dom.Node;
+
+import java.io.File;
+import java.util.ArrayList;
+
+/**
+ * Represents an add-on XML node in an SDK repository.
+ */
+public class AddonPackage extends Package {
+
+ private final String mVendor;
+ private final String mName;
+ private final int mApiLevel;
+
+ /** An add-on library. */
+ public static class Lib {
+ private final String mName;
+ private final String mDescription;
+
+ public Lib(String name, String description) {
+ mName = name;
+ mDescription = description;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public String getDescription() {
+ return mDescription;
+ }
+ }
+
+ private final Lib[] mLibs;
+
+ /**
+ * Creates a new add-on package from the attributes and elements of the given XML node.
+ * <p/>
+ * This constructor should throw an exception if the package cannot be created.
+ */
+ AddonPackage(RepoSource source, Node packageNode) {
+ super(source, packageNode);
+ mVendor = getXmlString(packageNode, SdkRepository.NODE_VENDOR);
+ mName = getXmlString(packageNode, SdkRepository.NODE_NAME);
+ mApiLevel = getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
+
+ 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) {
+ ArrayList<Lib> libs = new ArrayList<Lib>();
+
+ if (libsNode != null) {
+ for(Node child = libsNode.getFirstChild();
+ child != null;
+ child = child.getNextSibling()) {
+
+ if (child.getNodeType() == Node.ELEMENT_NODE &&
+ SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI()) &&
+ SdkRepository.NODE_LIB.equals(child.getLocalName())) {
+ libs.add(parseLib(child));
+ }
+ }
+ }
+
+ return libs.toArray(new Lib[libs.size()]);
+ }
+
+ /**
+ * Parses a <lib> element from a <libs> container.
+ */
+ private Lib parseLib(Node libNode) {
+ return new Lib(getXmlString(libNode, SdkRepository.NODE_NAME),
+ getXmlString(libNode, SdkRepository.NODE_DESCRIPTION));
+ }
+
+ /** Returns the vendor, a string, for add-on packages. */
+ public String getVendor() {
+ return mVendor;
+ }
+
+ /** Returns the name, a string, for add-on packages or for libraries. */
+ public String getName() {
+ return mName;
+ }
+
+ /** Returns the api-level, an int > 0, for platform, add-on and doc packages. */
+ public int getApiLevel() {
+ return mApiLevel;
+ }
+
+ /** Returns the libs defined in this add-on. Can be an empty array but not null. */
+ public Lib[] getLibs() {
+ return mLibs;
+ }
+
+ /** Returns a short description for an {@link IDescription}. */
+ @Override
+ public String getShortDescription() {
+ return String.format("%1$s by %2$s for Android API %3$d",
+ getName(),
+ getVendor(),
+ getApiLevel());
+ }
+
+ /** Returns a long description for an {@link IDescription}. */
+ @Override
+ public String getLongDescription() {
+ return String.format("%1$s.\n%2$s",
+ getShortDescription(),
+ 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;
+ }
+}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java
new file mode 100755
index 0000000..9686cbd
--- /dev/null
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java
@@ -0,0 +1,273 @@
+/*
+ * 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.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+
+/**
+ * A {@link Archive} is the base class for "something" that can be downloaded from
+ * the SDK repository -- subclasses include {@link PlatformPackage}, {@link AddonPackage},
+ * {@link DocPackage} and {@link ToolPackage}.
+ * <p/>
+ * A package has some attributes (revision, description) and a list of archives
+ * which represent the downloadable bits.
+ * <p/>
+ * Packages are contained in offered by a {@link RepoSource} (a download site).
+ */
+public class Archive implements IDescription {
+
+ /** The checksum type. */
+ public enum ChecksumType {
+ /** A SHA1 checksum, represented as a 40-hex string. */
+ 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. */
+ public enum Os {
+ ANY("Any"),
+ LINUX("Linux"),
+ MACOSX("MacOS X"),
+ 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 archive can be downloaded on. */
+ public enum Arch {
+ ANY("Any"),
+ PPC("PowerPC"),
+ X86("x86"),
+ 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 Arch mArch;
+ private final String mUrl;
+ private final long mSize;
+ private final String mChecksum;
+ private final ChecksumType mChecksumType = ChecksumType.SHA1;
+ private final Package mPackage;
+
+ /**
+ * Creates a new archive.
+ */
+ Archive(Package pkg, Os os, Arch arch, String url, long size, String checksum) {
+ mPackage = pkg;
+ mOs = os;
+ mArch = arch;
+ mUrl = url;
+ mSize = size;
+ mChecksum = checksum;
+ }
+
+ /**
+ * 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() {
+ return mSize;
+ }
+
+ /**
+ * Returns the SHA1 archive checksum, as a 40-char hex.
+ * Can be empty but not null for local installed folders.
+ */
+ public String getChecksum() {
+ return mChecksum;
+ }
+
+ /**
+ * Returns the checksum type, always {@link ChecksumType#SHA1} right now.
+ */
+ public ChecksumType getChecksumType() {
+ return mChecksumType;
+ }
+
+ /**
+ * Returns the download archive URL, either absolute or relative to the repository xml.
+ * For a local installed folder, an URL is frabricated from the folder path.
+ */
+ public String getUrl() {
+ return mUrl;
+ }
+
+ /**
+ * Returns the archive {@link Os} enum.
+ * Can be null for a local installed folder on an unknown OS.
+ */
+ public Os getOs() {
+ return mOs;
+ }
+
+ /**
+ * Returns the archive {@link Arch} enum.
+ * Can be null for a local installed folder on an unknown architecture.
+ */
+ public Arch getArch() {
+ return mArch;
+ }
+
+ /**
+ * Generates a short description for this archive.
+ */
+ public String getShortDescription() {
+ String os;
+ if (mOs == null) {
+ os = "unknown OS";
+ } else if (mOs == Os.ANY) {
+ os = "any OS";
+ } else {
+ os = mOs.toString();
+ }
+
+ String arch = "";
+ if (mArch != null && mArch != Arch.ANY) {
+ arch = mArch.toString();
+ }
+
+ return String.format("Archive for %1$s %2$s", os, arch);
+ }
+
+ /**
+ * Generates a longer description for this archive.
+ */
+ public String getLongDescription() {
+ return String.format("%1$s\nSize: %2$d MiB\nSHA1: %3$s",
+ getShortDescription(),
+ Math.round(getSize() / (1024*1024)),
+ 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;
+ }
+}
+
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java
new file mode 100755
index 0000000..8f07255
--- /dev/null
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java
@@ -0,0 +1,108 @@
+/*
+ * 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.SdkConstants;
+import com.android.sdklib.internal.repository.Archive.Arch;
+import com.android.sdklib.internal.repository.Archive.Os;
+import com.android.sdklib.repository.SdkRepository;
+
+import org.w3c.dom.Node;
+
+import java.io.File;
+
+/**
+ * Represents a doc XML node in an SDK repository.
+ */
+public class DocPackage extends Package {
+
+ private final int mApiLevel;
+
+ /**
+ * Creates a new doc package from the attributes and elements of the given XML node.
+ * <p/>
+ * This constructor should throw an exception if the package cannot be created.
+ */
+ DocPackage(RepoSource source, Node packageNode) {
+ super(source, packageNode);
+ mApiLevel = getXmlInt(packageNode, SdkRepository.NODE_API_LEVEL, 0);
+ }
+
+ /**
+ * 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() {
+ return mApiLevel;
+ }
+
+ /** Returns a short description for an {@link IDescription}. */
+ @Override
+ public String getShortDescription() {
+ 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}. */
+ @Override
+ public String getLongDescription() {
+ return String.format("%1$s.\n%2$s",
+ getShortDescription(),
+ 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);
+ }
+}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IDescription.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IDescription.java
new file mode 100755
index 0000000..7af92e2
--- /dev/null
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/IDescription.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+/**
+ * Interface for elements that can provide a description of themselves.
+ */
+public interface IDescription {
+
+ /**
+ * Returns a description of the given element. Cannot be null.
+ * <p/>
+ * A description is a multi-line of text, typically much more
+ * elaborate than what {@link #toString()} would provide.
+ */
+ public abstract String getShortDescription();
+
+ /**
+ * Returns a description of the given element. Cannot be null.
+ * <p/>
+ * A description is a multi-line of text, typically much more
+ * elaborate than what {@link #toString()} would provide.
+ */
+ public abstract String getLongDescription();
+
+}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITask.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITask.java
new file mode 100755
index 0000000..9178460
--- /dev/null
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITask.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+
+/**
+ * A task that executes and can update a monitor to display its status.
+ * The task will generally be run in a separate thread.
+ */
+public interface ITask {
+ public abstract void run(ITaskMonitor monitor);
+}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskFactory.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskFactory.java
new file mode 100755
index 0000000..540825c
--- /dev/null
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskFactory.java
@@ -0,0 +1,25 @@
+/*
+ * 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;
+
+/**
+ * A factory that can start and run new {@link ITask}s.
+ */
+public interface ITaskFactory {
+
+ public abstract void start(String title, ITask task);
+}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java
new file mode 100755
index 0000000..05c982d
--- /dev/null
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+
+/**
+ * A monitor interface for a {@link ITask}.
+ * <p/>
+ * Depending on the task factory that created the task, there might not be any UI
+ * or it might not implement all the methods, in which case calling them would be
+ * a no-op but is guaranteed not to crash.
+ * <p/>
+ * If the task runs in a non-UI worker thread, the task factory implementation
+ * will take care of the update the UI in the correct thread. The task itself
+ * must not have to deal with it.
+ */
+public interface ITaskMonitor {
+
+ /**
+ * Sets the description in the current task dialog.
+ * This method can be invoked from a non-UI thread.
+ */
+ public void setDescription(String descriptionFormat, Object...args);
+
+ /**
+ * Sets the result text in the current task dialog.
+ * This method can be invoked from a non-UI thread.
+ */
+ public void setResult(String resultFormat, Object...args);
+
+ /**
+ * Sets the max value of the progress bar.
+ * This method can be invoked from a non-UI thread.
+ */
+ public void setProgressMax(int max);
+
+ /**
+ * Increments the current value of the progress bar.
+ * This method can be invoked from a non-UI thread.
+ */
+ public void incProgress(int delta);
+
+ /**
+ * Returns true if the user requested to cancel the operation.
+ * It is up to the task thread to pool this and exit as soon
+ * as possible.
+ */
+ public boolean cancelRequested();
+}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java
new file mode 100755
index 0000000..f150510
--- /dev/null
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java
@@ -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;
+ }
+}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
new file mode 100755
index 0000000..55ecaef
--- /dev/null
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
@@ -0,0 +1,278 @@
+/*
+ * 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.internal.repository.Archive.Arch;
+import com.android.sdklib.internal.repository.Archive.Os;
+import com.android.sdklib.repository.SdkRepository;
+
+import org.w3c.dom.Node;
+
+import java.io.File;
+import java.util.ArrayList;
+
+/**
+ * A {@link Package} is the base class for "something" that can be downloaded from
+ * the SDK repository -- subclasses include {@link PlatformPackage}, {@link AddonPackage},
+ * {@link DocPackage} and {@link ToolPackage}.
+ * <p/>
+ * A package has some attributes (revision, description) and a list of archives
+ * which represent the downloadable bits.
+ * <p/>
+ * Packages are contained by a {@link RepoSource} (a download site).
+ * <p/>
+ * Derived classes must implement the {@link IDescription} methods.
+ */
+public abstract class Package implements IDescription {
+
+ private final int mRevision;
+ private final String mDescription;
+ private final String mDescUrl;
+ private final Archive[] mArchives;
+ private final RepoSource mSource;
+
+ /**
+ * Creates a new package from the attributes and elements of the given XML node.
+ * <p/>
+ * This constructor should throw an exception if the package cannot be created.
+ */
+ Package(RepoSource source, Node packageNode) {
+ mSource = source;
+ mRevision = getXmlInt (packageNode, SdkRepository.NODE_REVISION, 0);
+ mDescription = getXmlString(packageNode, SdkRepository.NODE_DESCRIPTION);
+ mDescUrl = getXmlString(packageNode, SdkRepository.NODE_DESC_URL);
+
+ 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) {
+ ArrayList<Archive> archives = new ArrayList<Archive>();
+
+ if (archivesNode != null) {
+ for(Node child = archivesNode.getFirstChild();
+ child != null;
+ child = child.getNextSibling()) {
+
+ if (child.getNodeType() == Node.ELEMENT_NODE &&
+ SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI()) &&
+ SdkRepository.NODE_ARCHIVE.equals(child.getLocalName())) {
+ archives.add(parseArchive(child));
+ }
+ }
+ }
+
+ return archives.toArray(new Archive[archives.size()]);
+ }
+
+ /**
+ * Parses one <archive> element from an <archives> container.
+ */
+ private Archive parseArchive(Node archiveNode) {
+ Archive a = new Archive(
+ this,
+ (Os) getEnumAttribute(archiveNode, SdkRepository.ATTR_OS,
+ Os.values(), null),
+ (Arch) getEnumAttribute(archiveNode, SdkRepository.ATTR_ARCH,
+ Arch.values(), Arch.ANY),
+ getXmlString(archiveNode, SdkRepository.NODE_URL),
+ getXmlLong(archiveNode, SdkRepository.NODE_SIZE, 0),
+ getXmlString(archiveNode, SdkRepository.NODE_CHECKSUM)
+ );
+
+ return a;
+ }
+
+ /**
+ * 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() {
+ return mRevision;
+ }
+
+ /**
+ * 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() {
+ return mDescription;
+ }
+
+ /**
+ * Returns the optional description URL for all packages (platform, add-on, tool, doc).
+ * Can be empty but not null.
+ */
+ public String getDescUrl() {
+ return mDescUrl;
+ }
+
+ /**
+ * Returns the archives defined in this package.
+ * Can be an empty array but not null.
+ */
+ public Archive[] getArchives() {
+ return mArchives;
+ }
+
+ /**
+ * Returns a short description for an {@link IDescription}.
+ * Can be empty but not null.
+ */
+ public abstract String getShortDescription();
+
+ /**
+ * Returns a long description for an {@link IDescription}.
+ * Can be empty but not null.
+ */
+ public String getLongDescription() {
+ 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) {
+
+ 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 || xmlLocalName.equals(child.getLocalName())) {
+ return child;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Retrieves the value of that XML element as a string.
+ * Returns an empty string when the element is missing.
+ */
+ protected static String getXmlString(Node node, String xmlLocalName) {
+ Node child = getFirstChild(node, xmlLocalName);
+
+ return child == null ? "" : child.getTextContent(); //$NON-NLS-1$
+ }
+
+ /**
+ * Retrieves the value of that XML element as an integer.
+ * Returns the default value when the element is missing or is not an integer.
+ */
+ protected static int getXmlInt(Node node, String xmlLocalName, int defaultValue) {
+ String s = getXmlString(node, xmlLocalName);
+ try {
+ return Integer.parseInt(s);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * 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
+ * case-insensitive name match.
+ *
+ * Returns defaultValue if the attribute does not exist or its value does not match
+ * the given enum values.
+ */
+ private Object getEnumAttribute(
+ Node archiveNode,
+ String attrName,
+ Object[] values,
+ Object defaultValue) {
+
+ Node attr = archiveNode.getAttributes().getNamedItem(attrName);
+ if (attr != null) {
+ String found = attr.getNodeValue();
+ for (Object value : values) {
+ if (value.toString().equalsIgnoreCase(found)) {
+ return value;
+ }
+ }
+ }
+
+ return defaultValue;
+ }
+}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java
new file mode 100755
index 0000000..0d51c58
--- /dev/null
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java
@@ -0,0 +1,114 @@
+/*
+ * 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.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.Node;
+
+import java.io.File;
+
+/**
+ * Represents a platform XML node in an SDK repository.
+ */
+public class PlatformPackage extends Package {
+
+ private final String mVersion;
+ private final int mApiLevel;
+
+ /**
+ * Creates a new platform package from the attributes and elements of the given XML node.
+ * <p/>
+ * This constructor should throw an exception if the package cannot be created.
+ */
+ PlatformPackage(RepoSource source, Node packageNode) {
+ super(source, packageNode);
+ mVersion = getXmlString(packageNode, SdkRepository.NODE_VERSION);
+ 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. */
+ public String getVersion() {
+ return mVersion;
+ }
+
+ /** Returns the api-level, an int > 0, for platform, add-on and doc packages. */
+ public int getApiLevel() {
+ return mApiLevel;
+ }
+
+ /** Returns a short description for an {@link IDescription}. */
+ @Override
+ public String getShortDescription() {
+ return String.format("SDK Platform Android %1$s, API %2$d",
+ getVersion(),
+ getApiLevel());
+ }
+
+ /** Returns a long description for an {@link IDescription}. */
+ @Override
+ public String getLongDescription() {
+ return String.format("%1$s.\n%2$s",
+ getShortDescription(),
+ 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;
+ }
+}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/RepoSource.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java
similarity index 62%
rename from tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/RepoSource.java
rename to tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java
index d2f65de..1fd880f 100755
--- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/RepoSource.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
- * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * 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.eclipse.org/org/documents/epl-v10.php
+ * 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,
@@ -14,12 +14,10 @@
* limitations under the License.
*/
-package com.android.sdkuilib.repository;
+package com.android.sdklib.internal.repository;
import com.android.sdklib.repository.SdkRepository;
-import com.android.sdkuilib.repository.ProgressTask.ThreadTask;
-import org.eclipse.swt.widgets.Shell;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
@@ -43,14 +41,16 @@
import javax.xml.validation.Validator;
/**
- *
+ * An sdk-repository source, i.e. a download site.
+ * It may be a full repository or an add-on only repository.
+ * A repository describes one or {@link Package}s available for download.
*/
-class RepoSource {
+public class RepoSource implements IDescription {
private final String mUrl;
private final boolean mAddonOnly;
- private ArrayList<String> mPackages;
+ private Package[] mPackages;
private String mDescription;
/**
@@ -59,11 +59,7 @@
public RepoSource(String url, boolean addonOnly) {
mUrl = url;
mAddonOnly = addonOnly;
- }
-
- @Override
- public String toString() {
- return mUrl;
+ setDefaultDescription();
}
/** Returns the URL of the source repository. */
@@ -72,32 +68,47 @@
}
/**
- * 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 ArrayList<String> getPackages() {
+ public Package[] getPackages() {
return mPackages;
}
- public String getDescription() {
+ /**
+ * 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() {
+ return mUrl;
+ }
+
+ public String getLongDescription() {
return mDescription == null ? "" : mDescription; //$NON-NLS-1$
}
/**
* Tries to fetch the repository index for the given URL.
*/
- public void load(Shell shell) {
+ public void load(ITaskFactory taskFactory) {
- ProgressTask.start(shell, "Init SDK Updater", new ThreadTask() {
- public void PerformTask(ITaskMonitor monitor) {
+ taskFactory.start("Init SDK Updater", new ITask() {
+ public void run(ITaskMonitor monitor) {
monitor.setProgressMax(4);
- monitor.setDescription(String.format("Fetching %1$s", mUrl));
+ setDefaultDescription();
+
+ monitor.setDescription("Fetching %1$s", mUrl);
monitor.incProgress(1);
String xml = fetchUrl(mUrl, monitor);
if (xml == null) {
- mDescription = String.format("Failed to fetch URL %1$s", mUrl);
+ mDescription += String.format("\nFailed to fetch URL %1$s", mUrl);
return;
}
@@ -105,13 +116,20 @@
monitor.incProgress(1);
if (!validateXml(xml, monitor)) {
- mDescription = String.format("Failed to validate XML at %1$s", mUrl);
+ mDescription += String.format("\nFailed to validate XML at %1$s", mUrl);
return;
}
monitor.setDescription("Parse XML");
monitor.incProgress(1);
parsePackages(xml, monitor);
+ if (mPackages.length == 0) {
+ mDescription += "\nNo packages found.";
+ } else if (mPackages.length == 1) {
+ mDescription += "\nOne package found.";
+ } else {
+ mDescription += String.format("\n%1$d packages found.", mPackages.length);
+ }
// done
monitor.incProgress(1);
@@ -119,7 +137,18 @@
});
}
- /*
+ private void setDefaultDescription() {
+ if (mAddonOnly) {
+ mDescription = String.format("Add-on Source: %1$s", mUrl);
+ } else {
+ mDescription = String.format("SDK Source: %1$s", mUrl);
+ }
+ }
+
+ /**
+ * 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:
* 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
@@ -169,6 +198,10 @@
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) {
try {
@@ -186,7 +219,9 @@
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 {
InputStream xsdStream = SdkRepository.getXsdStream();
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
@@ -200,6 +235,10 @@
}
+ /**
+ * Parse all packages defined in the SDK Repository XML and creates
+ * a new mPackages array with them.
+ */
private boolean parsePackages(String xml, ITaskMonitor monitor) {
try {
@@ -208,32 +247,42 @@
Node root = getFirstChild(doc, SdkRepository.NODE_SDK_REPOSITORY);
if (root != null) {
- mPackages = new ArrayList<String>();
+ ArrayList<Package> packages = new ArrayList<Package>();
for (Node child = root.getFirstChild();
child != null;
child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE &&
- child.getNamespaceURI().equals(SdkRepository.NS_SDK_REPOSITORY)) {
+ SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI())) {
String name = child.getLocalName();
- if (SdkRepository.NODE_ADD_ON.equals(name)) {
- parseAddon(child, mPackages, monitor);
+ Package p = null;
- } else if (!mAddonOnly) {
- if (SdkRepository.NODE_PLATFORM.equals(name)) {
- parsePlatform(child, mPackages, monitor);
+ try {
+ if (SdkRepository.NODE_ADD_ON.equals(name)) {
+ p = new AddonPackage(this, child);
- } else if (SdkRepository.NODE_DOC.equals(name)) {
- parseDoc(child, mPackages, monitor);
-
- } else if (SdkRepository.NODE_TOOL.equals(name)) {
- parseTool(child, mPackages, monitor);
-
+ } else if (!mAddonOnly) {
+ if (SdkRepository.NODE_PLATFORM.equals(name)) {
+ p = new PlatformPackage(this, child);
+ } else if (SdkRepository.NODE_DOC.equals(name)) {
+ p = new DocPackage(this, child);
+ } else if (SdkRepository.NODE_TOOL.equals(name)) {
+ p = new ToolPackage(this, child);
+ }
}
+
+ if (p != null) {
+ packages.add(p);
+ monitor.setDescription("Found %1$s", p.getShortDescription());
+ }
+ } catch (Exception e) {
+ // Ignore invalid packages
}
}
}
+ mPackages = packages.toArray(new Package[packages.size()]);
+
return true;
}
@@ -250,11 +299,15 @@
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) {
for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE &&
- child.getNamespaceURI().equals(SdkRepository.NS_SDK_REPOSITORY)) {
+ SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI())) {
if (xmlLocalName == null || child.getLocalName().equals(xmlLocalName)) {
return child;
}
@@ -264,6 +317,9 @@
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();
@@ -275,42 +331,4 @@
return doc;
}
-
- private void parseAddon(Node addon, ArrayList<String> packages, ITaskMonitor monitor) {
- // TODO Auto-generated method stub
- String s = String.format("addon %1$s by %2$s, api %3$s, rev %4$s",
- getFirstChild(addon, SdkRepository.NODE_NAME).getTextContent(),
- getFirstChild(addon, SdkRepository.NODE_VENDOR).getTextContent(),
- getFirstChild(addon, SdkRepository.NODE_API_LEVEL).getTextContent(),
- getFirstChild(addon, SdkRepository.NODE_REVISION).getTextContent()
- );
- packages.add(s);
- }
-
- private void parsePlatform(Node platform, ArrayList<String> packages, ITaskMonitor monitor) {
- // TODO Auto-generated method stub
- String s = String.format("platform %1$s, api %2$s, rev %3$s",
- getFirstChild(platform, SdkRepository.NODE_VERSION).getTextContent(),
- getFirstChild(platform, SdkRepository.NODE_API_LEVEL).getTextContent(),
- getFirstChild(platform, SdkRepository.NODE_REVISION).getTextContent()
- );
- packages.add(s);
- }
-
- private void parseDoc(Node doc, ArrayList<String> packages, ITaskMonitor monitor) {
- // TODO Auto-generated method stub
- String s = String.format("doc for api %1$s, rev %2$s",
- getFirstChild(doc, SdkRepository.NODE_API_LEVEL).getTextContent(),
- getFirstChild(doc, SdkRepository.NODE_REVISION).getTextContent()
- );
- packages.add(s);
- }
-
- private void parseTool(Node tool, ArrayList<String> packages, ITaskMonitor monitor) {
- // TODO Auto-generated method stub
- String s = String.format("tool, rev %1$s",
- getFirstChild(tool, SdkRepository.NODE_REVISION).getTextContent()
- );
- packages.add(s);
- }
}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSources.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSources.java
new file mode 100755
index 0000000..0a70953
--- /dev/null
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSources.java
@@ -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;
+ }
+}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java
new file mode 100755
index 0000000..71e35c4
--- /dev/null
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java
@@ -0,0 +1,92 @@
+/*
+ * 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.SdkConstants;
+import com.android.sdklib.internal.repository.Archive.Arch;
+import com.android.sdklib.internal.repository.Archive.Os;
+
+import org.w3c.dom.Node;
+
+import java.io.File;
+
+/**
+ * Represents a tool XML node in an SDK repository.
+ */
+public class ToolPackage extends Package {
+
+ /**
+ * Creates a new tool package from the attributes and elements of the given XML node.
+ * <p/>
+ * This constructor should throw an exception if the package cannot be created.
+ */
+ ToolPackage(RepoSource source, Node 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}. */
+ @Override
+ public String getShortDescription() {
+ return String.format("Android SDK Tools, revision %1$d", getRevision());
+ }
+
+ /** Returns a long description for an {@link IDescription}. */
+ @Override
+ public String getLongDescription() {
+ return String.format("Android SDK Tools, revision %1$d.\n%2$s",
+ getRevision(),
+ 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);
+ }
+}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java
index 72cc425..673e43f 100755
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java
@@ -16,27 +16,74 @@
package com.android.sdklib.repository;
+
import java.io.InputStream;
/**
- * Constants for the sdk-repository XML Schema
+ * Public constants for the sdk-repository XML Schema.
*/
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. */
public static final String NS_SDK_REPOSITORY =
"http://schemas.android.com/sdk/android/repository/1"; //$NON-NLS-1$
- public static final String NODE_VERSION = "version"; //$NON-NLS-1$
- public static final String NODE_REVISION = "revision"; //$NON-NLS-1$
- public static final String NODE_API_LEVEL = "api-level"; //$NON-NLS-1$
- public static final String NODE_VENDOR = "vendor"; //$NON-NLS-1$
- public static final String NODE_NAME = "name"; //$NON-NLS-1$
- public static final String NODE_TOOL = "tool"; //$NON-NLS-1$
- public static final String NODE_DOC = "doc"; //$NON-NLS-1$
- public static final String NODE_PLATFORM = "platform"; //$NON-NLS-1$
- public static final String NODE_ADD_ON = "add-on"; //$NON-NLS-1$
+ /** The root sdk-repository element */
public static final String NODE_SDK_REPOSITORY = "sdk-repository"; //$NON-NLS-1$
+ /** A platform package. */
+ public static final String NODE_PLATFORM = "platform"; //$NON-NLS-1$
+ /** An add-on package. */
+ public static final String NODE_ADD_ON = "add-on"; //$NON-NLS-1$
+ /** A tool package. */
+ public static final String NODE_TOOL = "tool"; //$NON-NLS-1$
+ /** A doc package. */
+ public static final String NODE_DOC = "doc"; //$NON-NLS-1$
+
+ /** The revision, an int > 0, for all packages (platform, add-on, tool, doc). */
+ public static final String NODE_REVISION = "revision"; //$NON-NLS-1$
+ /** The optional description for all packages (platform, add-on, tool, doc) or for a lib. */
+ public static final String NODE_DESCRIPTION = "description"; //$NON-NLS-1$
+ /** The optional description URL for all packages (platform, add-on, tool, doc). */
+ public static final String NODE_DESC_URL = "desc-url"; //$NON-NLS-1$
+
+ /** The version, a string, for platform packages. */
+ public static final String NODE_VERSION = "version"; //$NON-NLS-1$
+ /** The api-level, an int > 0, for platform, add-on and doc packages. */
+ public static final String NODE_API_LEVEL = "api-level"; //$NON-NLS-1$
+ /** The vendor, a string, for add-on packages. */
+ public static final String NODE_VENDOR = "vendor"; //$NON-NLS-1$
+ /** The name, a string, for add-on packages or for libraries. */
+ public static final String NODE_NAME = "name"; //$NON-NLS-1$
+
+ /** The libs container, optional for an add-on. */
+ public static final String NODE_LIBS = "libs"; //$NON-NLS-1$
+ /** A lib element in a libs container. */
+ public static final String NODE_LIB = "lib"; //$NON-NLS-1$
+
+ /** The archives container, for all packages. */
+ public static final String NODE_ARCHIVES = "archives"; //$NON-NLS-1$
+ /** An archive element, for the archives container. */
+ public static final String NODE_ARCHIVE = "archive"; //$NON-NLS-1$
+
+ /** An archive size, an int > 0. */
+ public static final String NODE_SIZE = "size"; //$NON-NLS-1$
+ /** A sha1 archive checksum, as a 40-char hex. */
+ public static final String NODE_CHECKSUM = "checksum"; //$NON-NLS-1$
+ /** A download archive URL, either absolute or relative to the repository xml. */
+ public static final String NODE_URL = "url"; //$NON-NLS-1$
+
+ /** An archive checksum type, mandatory. */
+ public static final String ATTR_TYPE = "type"; //$NON-NLS-1$
+ /** An archive OS attribute, mandatory. */
+ public static final String ATTR_OS = "os"; //$NON-NLS-1$
+ /** An optional archive Architecture attribute. */
+ public static final String ATTR_ARCH = "arch"; //$NON-NLS-1$
+
public static InputStream getXsdStream() {
return SdkRepository.class.getResourceAsStream("sdk-repository.xsd"); //$NON-NLS-1$
}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java
index 44c7724..0166556 100644
--- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java
+++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
- * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * 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.eclipse.org/org/documents/epl-v10.php
+ * 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,
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/SdkTargetSelector.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/SdkTargetSelector.java
index b23c865..b90bd61 100644
--- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/SdkTargetSelector.java
+++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/SdkTargetSelector.java
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2009 The Android Open Source Project
*
- * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * 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.eclipse.org/org/documents/epl-v10.php
+ * 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,
@@ -46,17 +46,17 @@
* selection.
*/
public class SdkTargetSelector {
-
+
private IAndroidTarget[] mTargets;
private final boolean mAllowSelection;
private SelectionListener mSelectionListener;
private Table mTable;
private Label mDescription;
private Composite mInnerGroup;
-
+
/**
* Creates a new SDK Target Selector.
- *
+ *
* @param parent The parent composite where the selector will be added.
* @param targets The list of targets. This is <em>not</em> copied, the caller must not modify.
* Targets can be null or an empty array, in which case the table is disabled.
@@ -67,7 +67,7 @@
/**
* Creates a new SDK Target Selector.
- *
+ *
* @param parent The parent composite where the selector will be added.
* @param targets The list of targets. This is <em>not</em> copied, the caller must not modify.
* Targets can be null or an empty array, in which case the table is disabled.
@@ -79,7 +79,7 @@
mInnerGroup.setLayout(new GridLayout());
mInnerGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
mInnerGroup.setFont(parent.getFont());
-
+
mAllowSelection = allowSelection;
int style = SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION;
if (allowSelection) {
@@ -137,7 +137,7 @@
/**
* Changes the targets of the SDK Target Selector.
- *
+ *
* @param targets The list of targets. This is <em>not</em> copied, the caller must not modify.
*/
public void setTargets(IAndroidTarget[] targets) {
@@ -154,19 +154,19 @@
* The {@link TableItem#getData()} contains an {@link IAndroidTarget}.
* <p/>
* It is recommended that the caller uses the {@link #getSelected()} method instead.
- *
+ *
* @param selectionListener The new listener or null to remove it.
*/
public void setSelectionListener(SelectionListener selectionListener) {
mSelectionListener = selectionListener;
}
-
+
/**
* Sets the current target selection.
* <p/>
* If the selection is actually changed, this will invoke the selection listener
* (if any) with a null event.
- *
+ *
* @param target the target to be selection
* @return true if the target could be selected, false otherwise.
*/
@@ -174,7 +174,7 @@
if (!mAllowSelection) {
return false;
}
-
+
boolean found = false;
boolean modified = false;
@@ -192,17 +192,17 @@
}
}
}
-
+
if (modified && mSelectionListener != null) {
mSelectionListener.widgetSelected(null);
}
-
+
return found;
}
/**
* Returns the selected item.
- *
+ *
* @return The selected item or null.
*/
public IAndroidTarget getSelected() {
@@ -234,7 +234,7 @@
@Override
public void controlResized(ControlEvent e) {
Rectangle r = table.getClientArea();
- column0.setWidth(r.width * 30 / 100); // 30%
+ column0.setWidth(r.width * 30 / 100); // 30%
column1.setWidth(r.width * 45 / 100); // 45%
column2.setWidth(r.width * 15 / 100); // 15%
column3.setWidth(r.width * 10 / 100); // 10%
@@ -267,7 +267,7 @@
mSelectionListener.widgetDefaultSelected(e);
}
}
-
+
public void widgetSelected(SelectionEvent e) {
if (e.item instanceof TableItem) {
TableItem i = (TableItem) e.item;
@@ -315,7 +315,7 @@
}
table.removeAll();
-
+
if (mTargets != null && mTargets.length > 0) {
table.setEnabled(true);
for (IAndroidTarget target : mTargets) {
@@ -350,36 +350,36 @@
}
/*
- * Reference:
+ * 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);
@@ -414,5 +414,5 @@
enableControl(c2, enabled);
}
}
-
+
}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/LocalPackagesPage.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/LocalPackagesPage.java
new file mode 100755
index 0000000..3f32ddc
--- /dev/null
+++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/LocalPackagesPage.java
@@ -0,0 +1,251 @@
+/*
+ * 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.ITask;
+import com.android.sdklib.internal.repository.ITaskMonitor;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+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.SelectionEvent;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+
+/*
+ * TODO list
+ * - select => update desc, enable update + delete, enable home page if url
+ * - home page callback
+ * - update callback
+ * - delete callback
+ * - refresh callback
+ */
+
+public class LocalPackagesPage extends Composite {
+ private UpdaterData mUpdaterData;
+
+ private Label mSdkLocLabel;
+ private Text mSdkLocText;
+ private Button mSdkLocBrowse;
+ private TableViewer mTableViewerPackages;
+ private Table mTablePackages;
+ private TableColumn mColumnPackages;
+ private Group mDescriptionContainer;
+ private Composite mContainerButtons;
+ private Button mUpdateButton;
+ private Label mPlaceholder1;
+ private Button mDeleteButton;
+ private Label mPlaceholder2;
+ private Button mHomePageButton;
+ private Label mDescriptionLabel;
+
+ /**
+ * Create the composite.
+ * @param parent The parent of the composite.
+ * @param updaterData An instance of {@link UpdaterData}. If null, a local
+ * one will be allocated just to help with the SWT Designer.
+ */
+ public LocalPackagesPage(Composite parent, UpdaterData updaterData) {
+ super(parent, SWT.BORDER);
+
+ mUpdaterData = updaterData != null ? updaterData : new UpdaterData();
+
+ createContents(this);
+ postCreate(); //$hide$
+ }
+
+ private void createContents(Composite parent) {
+ parent.setLayout(new GridLayout(3, false));
+
+ createSdkLocation(parent);
+
+ mTableViewerPackages = new TableViewer(parent, SWT.BORDER | SWT.FULL_SELECTION);
+ mTablePackages = mTableViewerPackages.getTable();
+ mTablePackages.setHeaderVisible(true);
+ mTablePackages.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
+ mTablePackages.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ onTreeSelected(); //$hide$
+ }
+ });
+
+ mColumnPackages = new TableColumn(mTablePackages, SWT.NONE);
+ mColumnPackages.setWidth(377);
+ mColumnPackages.setText("Installed Packages");
+
+ mDescriptionContainer = new Group(parent, SWT.NONE);
+ mDescriptionContainer.setLayout(new GridLayout(1, false));
+ mDescriptionContainer.setText("Description");
+ mDescriptionContainer.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1));
+
+ mDescriptionLabel = new Label(mDescriptionContainer, SWT.NONE);
+ mDescriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true, 1, 1));
+ mDescriptionLabel.setText("Line1\nLine2\nLine3");
+
+ mContainerButtons = new Composite(parent, SWT.NONE);
+ mContainerButtons.setLayout(new GridLayout(5, false));
+ mContainerButtons.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
+
+ mUpdateButton = new Button(mContainerButtons, SWT.NONE);
+ mUpdateButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ onUpdateInstalledPackage(); //$hide$ (hide from SWT designer)
+ }
+ });
+ mUpdateButton.setText("Update...");
+
+ mPlaceholder1 = new Label(mContainerButtons, SWT.NONE);
+ mPlaceholder1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
+
+ mDeleteButton = new Button(mContainerButtons, SWT.NONE);
+ mDeleteButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
+ mDeleteButton.setText("Delete...");
+
+ mPlaceholder2 = new Label(mContainerButtons, SWT.NONE);
+ mPlaceholder2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
+
+ mHomePageButton = new Button(mContainerButtons, SWT.NONE);
+ mHomePageButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ mHomePageButton.setText("Home Page...");
+ }
+
+ private void createSdkLocation(Composite parent) {
+ mSdkLocLabel = new Label(parent, SWT.NONE);
+ mSdkLocLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ mSdkLocLabel.setText("SDK Location:");
+
+ // If the sdk path is not user-customizable, do not create
+ // the browse button and use horizSpan=2 on the text field.
+
+ mSdkLocText = new Text(parent, SWT.BORDER);
+ mSdkLocText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ if (mUpdaterData.canUserChangeSdkRoot()) {
+ mSdkLocBrowse = new Button(parent, SWT.NONE);
+ mSdkLocBrowse.setText("Browse...");
+ } else {
+ mSdkLocText.setEditable(false);
+ ((GridData)mSdkLocText.getLayoutData()).horizontalSpan++;
+ }
+
+ if (mUpdaterData.getOsSdkRoot() != null) {
+ mSdkLocText.setText(mUpdaterData.getOsSdkRoot());
+ }
+ }
+
+ @Override
+ protected void checkSubclass() {
+ // Disable the check that prevents subclassing of SWT components
+ }
+
+ // -- Start of internal part ----------
+ // Hide everything down-below from SWT designer
+ //$hide>>$
+
+ /**
+ * Must be called once to set the adapter input for the package table viewer.
+ */
+ public void setInput(LocalSdkAdapter localSdkAdapter) {
+ mTableViewerPackages.setLabelProvider( localSdkAdapter.getLabelProvider());
+ mTableViewerPackages.setContentProvider(localSdkAdapter.getContentProvider());
+ mTableViewerPackages.setInput(localSdkAdapter);
+ onTreeSelected();
+ }
+
+ /**
+ * Called by the constructor right after {@link #createContents(Composite)}.
+ */
+ 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);
+ }
+ });
+ }
+
+ /**
+ * Called when an item in the package table viewer is selected.
+ * If the items is an {@link IDescription} (as it should), this will display its long
+ * description in the description area. Otherwise when the item is not of the expected
+ * type or there is no selection, it empties the description area.
+ */
+ private void onTreeSelected() {
+ ISelection sel = mTableViewerPackages.getSelection();
+ if (sel instanceof IStructuredSelection) {
+ Object elem = ((IStructuredSelection) sel).getFirstElement();
+ if (elem instanceof IDescription) {
+ mDescriptionLabel.setText(((IDescription) elem).getLongDescription());
+ mDescriptionContainer.layout(true);
+ return;
+ }
+ }
+ mDescriptionLabel.setText(""); //$NON-NLS1-$
+ }
+
+ private void onUpdateInstalledPackage() {
+ // TODO just a test, needs to be removed later.
+ ProgressTask.start(getShell(), "Test", new ITask() {
+ public void run(ITaskMonitor monitor) {
+ monitor.setDescription("Test");
+ monitor.setProgressMax(100);
+ int n = 0;
+ int d = 1;
+ while(!monitor.cancelRequested()) {
+ monitor.incProgress(d);
+ n += d;
+ if (n == 0 || n == 100) d = -d;
+ try {
+ Thread.sleep(5);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ }
+ });
+ }
+
+ // End of hiding from SWT Designer
+ //$hide<<$
+}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/LocalSdkAdapter.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/LocalSdkAdapter.java
new file mode 100755
index 0000000..330be18
--- /dev/null
+++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/LocalSdkAdapter.java
@@ -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];
+ }
+ }
+
+}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/ProgressTask.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressTask.java
similarity index 76%
rename from tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/ProgressTask.java
rename to tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressTask.java
index ee768dd..7667355 100755
--- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/ProgressTask.java
+++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressTask.java
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
- * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * 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.eclipse.org/org/documents/epl-v10.php
+ * 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,
@@ -14,7 +14,10 @@
* limitations under the License.
*/
-package com.android.sdkuilib.repository;
+package com.android.sdkuilib.internal.repository;
+
+import com.android.sdklib.internal.repository.ITask;
+import com.android.sdklib.internal.repository.ITaskMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
@@ -30,6 +33,13 @@
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
+/*
+ * TODO:
+ * - trap window.close and treat it as a cancel request
+ * - on cancel as been clicked *and* the task finished,, change it to a "close" button
+ */
+
+
class ProgressTask extends Dialog
implements ITaskMonitor //$hide$ (hide from SWT designer)
{
@@ -72,6 +82,9 @@
display.sleep();
}
}
+
+ mCancelRequested = true;
+
if (!mDialogShell.isDisposed()) {
mDialogShell.close();
}
@@ -119,11 +132,7 @@
// Hide everything down-below from SWT designer
//$hide>>$
- public interface ThreadTask {
- public abstract void PerformTask(ITaskMonitor monitor);
- }
-
- private ThreadTask mTask;
+ private ITask mTask;
/**
* Creates a new {@link ProgressTask} with the given title.
@@ -131,7 +140,7 @@
*
* This blocks till the thread ends.
*/
- public static ProgressTask start(Shell parent, String title, ThreadTask task) {
+ public static ProgressTask start(Shell parent, String title, ITask task) {
ProgressTask t = new ProgressTask(parent);
t.setText(title);
t.setTask(task);
@@ -143,11 +152,11 @@
* Sets the description in the current task dialog.
* 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() {
public void run() {
if (!mLabel.isDisposed()) {
- mLabel.setText(description);
+ mLabel.setText(String.format(descriptionFormat, args));
}
}
});
@@ -157,16 +166,18 @@
* Sets the description in the current task dialog.
* 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;
- mDialogShell.getDisplay().asyncExec(new Runnable() {
- public void run() {
- if (!mResultText.isDisposed()) {
- mResultText.setVisible(true);
- mResultText.setText(result);
+ if (!mDialogShell.isDisposed()) {
+ mDialogShell.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (!mResultText.isDisposed()) {
+ mResultText.setVisible(true);
+ mResultText.setText(String.format(resultFormat, args));
+ }
}
- }
- });
+ });
+ }
}
/**
@@ -176,13 +187,15 @@
* @see ProgressBar#setMaximum(int)
*/
public void setProgressMax(final int max) {
- mDialogShell.getDisplay().asyncExec(new Runnable() {
- public void run() {
- if (!mProgressBar.isDisposed()) {
- mProgressBar.setMaximum(max);
+ if (!mDialogShell.isDisposed()) {
+ mDialogShell.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (!mProgressBar.isDisposed()) {
+ mProgressBar.setMaximum(max);
+ }
}
- }
- });
+ });
+ }
}
/**
@@ -191,13 +204,15 @@
* This method can be invoked from a non-UI thread.
*/
public void incProgress(final int delta) {
- mDialogShell.getDisplay().asyncExec(new Runnable() {
- public void run() {
- if (!mProgressBar.isDisposed()) {
- mProgressBar.setSelection(mProgressBar.getSelection() + delta);
+ if (!mDialogShell.isDisposed()) {
+ mDialogShell.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (!mProgressBar.isDisposed()) {
+ mProgressBar.setSelection(mProgressBar.getSelection() + delta);
+ }
}
- }
- });
+ });
+ }
}
/**
@@ -209,12 +224,12 @@
}
/** Sets the task that will execute in a separate thread. */
- private void setTask(ThreadTask task) {
+ private void setTask(ITask task) {
mTask = task;
}
/**
- * Starts the task from {@link #setTask(ThreadTask)} in a separate thread.
+ * Starts the task from {@link #setTask(ITask)} in a separate thread.
* When the task completes, set {@link #mCloseRequested} to end the dialog loop.
*/
private void startTask() {
@@ -222,7 +237,7 @@
new Thread(getText()) {
@Override
public void run() {
- mTask.PerformTask(ProgressTask.this);
+ mTask.run(ProgressTask.this);
if (mAutomaticallyCloseOnTaskCompletion) {
mCloseRequested = true;
}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressTaskFactory.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressTaskFactory.java
new file mode 100755
index 0000000..ceb701e
--- /dev/null
+++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/ProgressTaskFactory.java
@@ -0,0 +1,39 @@
+/*
+ * 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.ITask;
+import com.android.sdklib.internal.repository.ITaskFactory;
+
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * An {@link ITaskFactory} that creates a new {@link ProgressTask} dialog
+ * for each new task.
+ */
+public class ProgressTaskFactory implements ITaskFactory {
+
+ private final Shell mShell;
+
+ public ProgressTaskFactory(Shell shell) {
+ mShell = shell;
+ }
+
+ public void start(String title, ITask task) {
+ ProgressTask.start(mShell, title, task);
+ }
+}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java
new file mode 100755
index 0000000..1fe5ca4
--- /dev/null
+++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java
@@ -0,0 +1,242 @@
+/*
+ * 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.Archive;
+import com.android.sdklib.internal.repository.IDescription;
+
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+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.ITreeSelection;
+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.SelectionEvent;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+
+import java.util.ArrayList;
+
+/*
+ * TODO list
+ * - check source => toggle packages: all, none
+ * - check package => set source check to tri-state
+ * - check callback => install enable if has selection
+ * - select tree item: delete site enable if add-on source
+ * - select tree item: refresh enable if source
+ * - load add-on sites from pref
+ * - delete site callback, update pref
+ * - refresh callback
+ * - install selected callback
+ */
+
+public class RemotePackagesPage extends Composite {
+
+ private final UpdaterWindowImpl mUpdaterWindow;
+ private final UpdaterData mUpdaterData;
+
+ private CheckboxTreeViewer mTreeViewerSources;
+ private Tree mTreeSources;
+ private TreeColumn mColumnSource;
+ private Group mDescriptionContainer;
+ private Button mAddSiteButton;
+ private Button mRemoveSiteButton;
+ private Label mPlaceholder3;
+ private Button mRefreshButton;
+ private Button mInstallSelectedButton;
+ private Label mDescriptionLabel;
+
+
+ /**
+ * Create the composite.
+ * @param parent The parent of the composite.
+ * @param updaterData An instance of {@link UpdaterData}. If null, a local
+ * one will be allocated just to help with the SWT Designer.
+ * @param updaterWindow The parent window.
+ */
+ RemotePackagesPage(Composite parent,
+ UpdaterData updaterData,
+ UpdaterWindowImpl updaterWindow) {
+ super(parent, SWT.BORDER);
+ mUpdaterWindow = updaterWindow;
+
+ mUpdaterData = updaterData != null ? updaterData : new UpdaterData();
+
+ createContents(this);
+ postCreate(); //$hide$
+ }
+
+ private void createContents(Composite parent) {
+ parent.setLayout(new GridLayout(5, false));
+
+ mTreeViewerSources = new CheckboxTreeViewer(parent, SWT.BORDER);
+ mTreeViewerSources.addDoubleClickListener(new IDoubleClickListener() {
+ public void doubleClick(DoubleClickEvent event) {
+ onTreeDoubleClick(event); //$hide$
+ }
+ });
+ mTreeViewerSources.addCheckStateListener(new ICheckStateListener() {
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ onTreeCheckStateChanged(event); //$hide$
+ }
+ });
+ mTreeSources = mTreeViewerSources.getTree();
+ mTreeSources.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ onTreeSelected(); //$hide$
+ }
+ });
+ mTreeSources.setHeaderVisible(true);
+ mTreeSources.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 5, 1));
+
+ mColumnSource = new TreeColumn(mTreeSources, SWT.NONE);
+ mColumnSource.setWidth(289);
+ mColumnSource.setText("Sources, Packages and Archives");
+
+ mDescriptionContainer = new Group(parent, SWT.NONE);
+ mDescriptionContainer.setLayout(new GridLayout(1, false));
+ mDescriptionContainer.setText("Description");
+ mDescriptionContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 5, 1));
+
+ mDescriptionLabel = new Label(mDescriptionContainer, SWT.NONE);
+ mDescriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+ mDescriptionLabel.setText("Line1\nLine2\nLine3");
+
+ mAddSiteButton = new Button(parent, SWT.NONE);
+ mAddSiteButton.setText("Add Site...");
+
+ mRemoveSiteButton = new Button(parent, SWT.NONE);
+ mRemoveSiteButton.setText("Delete Site...");
+
+ mPlaceholder3 = new Label(parent, SWT.NONE);
+ mPlaceholder3.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1));
+
+ mRefreshButton = new Button(parent, SWT.NONE);
+ mRefreshButton.setText("Refresh");
+
+ mInstallSelectedButton = new Button(parent, SWT.NONE);
+ mInstallSelectedButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ onInstallSelectedArchives(); //$hide$
+ }
+ });
+ mInstallSelectedButton.setText("Install Selected");
+ }
+
+ @Override
+ protected void checkSubclass() {
+ // Disable the check that prevents subclassing of SWT components
+ }
+
+ // -- Start of internal part ----------
+ // Hide everything down-below from SWT designer
+ //$hide>>$
+
+ /**
+ * Must be called once to set the adapter input for the sources tree viewer.
+ */
+ public void setInput(RepoSourcesAdapter sources) {
+ mTreeViewerSources.setContentProvider(sources.getContentProvider());
+ mTreeViewerSources.setLabelProvider( sources.getLabelProvider());
+ mTreeViewerSources.setInput(sources);
+ onTreeSelected();
+ }
+
+ /**
+ * Called by the constructor right after {@link #createContents(Composite)}.
+ */
+ 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
+ mTreeSources.addControlListener(new ControlAdapter() {
+ @Override
+ public void controlResized(ControlEvent e) {
+ Rectangle r = mTreeSources.getClientArea();
+ mColumnSource.setWidth(r.width);
+ }
+ });
+ }
+
+ /**
+ * Called when an item in the package table viewer is selected.
+ * If the items is an {@link IDescription} (as it should), this will display its long
+ * description in the description area. Otherwise when the item is not of the expected
+ * type or there is no selection, it empties the description area.
+ */
+ private void onTreeSelected() {
+ ISelection sel = mTreeViewerSources.getSelection();
+ if (sel instanceof ITreeSelection) {
+ Object elem = ((ITreeSelection) sel).getFirstElement();
+ if (elem instanceof IDescription) {
+ mDescriptionLabel.setText(((IDescription) elem).getLongDescription());
+ mDescriptionContainer.layout(true);
+ return;
+ }
+ }
+ mDescriptionLabel.setText(""); //$NON-NLS1-$
+ }
+
+ private void onTreeCheckStateChanged(CheckStateChangedEvent event) {
+ boolean b = event.getChecked();
+ Object elem = event.getElement(); // Will be Archive or Package or RepoSource
+ Object src = event.getSource();
+ // TODO
+ }
+
+ 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
+ //$hide<<$
+}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java
new file mode 100755
index 0000000..3f020d1
--- /dev/null
+++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RepoSourcesAdapter.java
@@ -0,0 +1,157 @@
+/*
+ * 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.Archive;
+import com.android.sdklib.internal.repository.IDescription;
+import com.android.sdklib.internal.repository.Package;
+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.ILabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * A list of sdk-repository sources.
+ *
+ * This implementation is UI dependent.
+ */
+class RepoSourcesAdapter {
+
+ private final RepoSources mRepoSources;
+
+ public RepoSourcesAdapter(RepoSources repoSources) {
+ mRepoSources = repoSources;
+ }
+
+ public ILabelProvider getLabelProvider() {
+ return new ViewerLabelProvider();
+ }
+
+
+ public IContentProvider getContentProvider() {
+ return new TreeContentProvider();
+ }
+
+ // ------------
+
+ 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 TreeContentProvider implements ITreeContentProvider {
+
+ private RepoSourcesAdapter mInput;
+
+ // 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) {
+ assert newInput == null || newInput instanceof RepoSourcesAdapter;
+ mInput = (RepoSourcesAdapter) newInput;
+ // pass
+ }
+
+ /**
+ * Called to collect the root elements for the given input.
+ * The input here is a {@link RepoSourcesAdapter} object, this returns an array
+ * of {@link RepoSource}.
+ */
+ public Object[] getElements(Object inputElement) {
+ return getChildren(inputElement);
+ }
+
+ /**
+ * Get the children of the given parent. This is requested on-demand as
+ * nodes are expanded.
+ *
+ * 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 Package}, returns an array of {@link Archive}s.
+ */
+ public Object[] getChildren(Object parentElement) {
+ if (parentElement instanceof RepoSourcesAdapter) {
+ return ((RepoSourcesAdapter) parentElement).mRepoSources.getSources().toArray();
+
+ } else if (parentElement instanceof RepoSource) {
+ RepoSource source = (RepoSource) parentElement;
+ Package[] packages = source.getPackages();
+
+ if (packages == null) {
+ source.load(mInput.mRepoSources.getTaskFactory());
+ packages = source.getPackages();
+ }
+ if (packages != null) {
+ return packages;
+ }
+
+ } else if (parentElement instanceof Package) {
+ return ((Package) parentElement).getArchives();
+ }
+
+ return new Object[0];
+ }
+
+ /**
+ * Returns the parent of a given element.
+ * The input {@link RepoSourcesAdapter} is the parent of all {@link RepoSource} elements.
+ */
+ public Object getParent(Object element) {
+
+ if (element instanceof RepoSource) {
+ return mInput;
+
+ } else if (element instanceof Package) {
+ return ((Package) element).getParentSource();
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if a given element has children, which is used to display a
+ * "+/expand" box next to the tree node.
+ * All {@link RepoSource} and {@link Package} are expandable, whether they actually
+ * have any children or not.
+ */
+ public boolean hasChildren(Object element) {
+ return element instanceof RepoSource || element instanceof Package;
+ }
+ }
+
+}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java
new file mode 100755
index 0000000..47ce3ac
--- /dev/null
+++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterData.java
@@ -0,0 +1,76 @@
+/*
+ * 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.ISdkLog;
+import com.android.sdklib.internal.repository.LocalSdkParser;
+import com.android.sdklib.internal.repository.RepoSources;
+
+/**
+ * Data shared between {@link UpdaterWindowImpl} and its pages.
+ */
+class UpdaterData {
+ private ISdkLog mSdkLog;
+ private String mOsSdkRoot;
+ private boolean mUserCanChangeSdkRoot;
+
+ 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) {
+ mOsSdkRoot = osSdkRoot;
+ }
+
+ public String getOsSdkRoot() {
+ return mOsSdkRoot;
+ }
+
+ public void setUserCanChangeSdkRoot(boolean userCanChangeSdkRoot) {
+ mUserCanChangeSdkRoot = userCanChangeSdkRoot;
+ }
+
+ public boolean canUserChangeSdkRoot() {
+ return mUserCanChangeSdkRoot;
+ }
+
+ public RepoSources getSources() {
+ return mSources;
+ }
+
+ public RepoSourcesAdapter getSourcesAdapter() {
+ return mSourcesAdapter;
+ }
+
+ public LocalSdkParser getLocalSdkParser() {
+ return mLocalSdkParser;
+ }
+
+ public LocalSdkAdapter getLocalSdkAdapter() {
+ return mLocalSdkAdapter;
+ }
+
+ public void setSdkLog(ISdkLog sdkLog) {
+ mSdkLog = sdkLog;
+ }
+
+ public ISdkLog getSdkLog() {
+ return mSdkLog;
+ }
+}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java
new file mode 100755
index 0000000..8ab37bb
--- /dev/null
+++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java
@@ -0,0 +1,533 @@
+/*
+ * 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.ISdkLog;
+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.repository.SdkRepository;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.swt.widgets.Shell;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * This is the private implementation of the UpdateWindow.
+ */
+public class UpdaterWindowImpl {
+
+ private static final int NUM_FETCH_URL_MONITOR_INC = 10;
+
+ /** Internal data shared between the window and its pages. */
+ private final UpdaterData mUpdaterData = new UpdaterData();
+ /** The array of pages instances. Only one is visible at a time. */
+ private ArrayList<Composite> mPages = new ArrayList<Composite>();
+ /** Indicates a page change is due to an internal request. Prevents callbacks from looping. */
+ private boolean mInternalPageChange;
+ /** A list of extra pages to instantiate. Each entry is an object array with 2 elements:
+ * the string title and the Composite class to instantiate to create the page. */
+ private ArrayList<Object[]> mExtraPages;
+ /** A factory to create progress task dialogs. */
+ private ProgressTaskFactory mTaskFactory;
+
+
+ // --- UI members ---
+
+ protected Shell mAndroidSdkUpdater;
+ private SashForm mSashForm;
+ private List mPageList;
+ private Composite mPagesRootComposite;
+ private LocalPackagesPage mLocalPackagePage;
+ private RemotePackagesPage mRemotePackagesPage;
+ private StackLayout mStackLayout;
+ private Image mIconImage;
+
+ public UpdaterWindowImpl(ISdkLog sdkLog, String osSdkRoot, boolean userCanChangeSdkRoot) {
+ mUpdaterData.setSdkLog(sdkLog);
+ mUpdaterData.setOsSdkRoot(osSdkRoot);
+ mUpdaterData.setUserCanChangeSdkRoot(userCanChangeSdkRoot);
+ }
+
+ /**
+ * Open the window.
+ * @wbp.parser.entryPoint
+ */
+ public void open() {
+ Display display = Display.getDefault();
+ createContents();
+ mAndroidSdkUpdater.open();
+ mAndroidSdkUpdater.layout();
+
+ firstInit(); //$hide$ (hide from SWT designer)
+
+ while (!mAndroidSdkUpdater.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ }
+
+ /**
+ * Create contents of the window.
+ */
+ protected void createContents() {
+ mAndroidSdkUpdater = new Shell();
+ setWindowImage(mAndroidSdkUpdater);
+ mAndroidSdkUpdater.addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent e) {
+ onAndroidSdkUpdaterDispose(); //$hide$ (hide from SWT designer)
+ }
+ });
+
+ mAndroidSdkUpdater.setLayout(new FillLayout(SWT.HORIZONTAL));
+ mAndroidSdkUpdater.setMinimumSize(new Point(200, 50));
+ mAndroidSdkUpdater.setSize(745, 433);
+ mAndroidSdkUpdater.setText("Android SDK Updater");
+
+ mSashForm = new SashForm(mAndroidSdkUpdater, SWT.NONE);
+
+ mPageList = new List(mSashForm, SWT.BORDER);
+ mPageList.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ onPageListSelected(); //$hide$ (hide from SWT designer)
+ }
+ });
+
+ mPagesRootComposite = new Composite(mSashForm, SWT.NONE);
+ mStackLayout = new StackLayout();
+ mPagesRootComposite.setLayout(mStackLayout);
+
+ mLocalPackagePage = new LocalPackagesPage(mPagesRootComposite, mUpdaterData);
+ mRemotePackagesPage = new RemotePackagesPage(mPagesRootComposite, mUpdaterData, this);
+ mSashForm.setWeights(new int[] {150, 576});
+ }
+
+
+ // -- Start of internal part ----------
+ // Hide everything down-below from SWT designer
+ //$hide>>$
+
+ // --- UI Callbacks -----------
+
+
+ /**
+ * Registers an extra page for the updater window.
+ * <p/>
+ * Pages must derive from {@link Composite} and implement a constructor that takes
+ * a single parent {@link Composite} argument.
+ * <p/>
+ * All pages must be registered before the call to {@link #open()}.
+ *
+ * @param title The title of the page.
+ * @param pageClass The {@link Composite}-derived class that will implement the page.
+ */
+ public void registerExtraPage(String title, Class<? extends Composite> pageClass) {
+ if (mExtraPages == null) {
+ mExtraPages = new ArrayList<Object[]>();
+ }
+ mExtraPages.add(new Object[]{ title, pageClass });
+ }
+
+ /**
+ * Helper to return the SWT shell.
+ */
+ private Shell getShell() {
+ return mAndroidSdkUpdater;
+ }
+
+ /**
+ * Callback called when the window shell is disposed.
+ */
+ private void onAndroidSdkUpdaterDispose() {
+ if (mIconImage != null) {
+ mIconImage.dispose();
+ mIconImage = null;
+ }
+ }
+
+ /**
+ * Creates the icon of the window shell.
+ * The icon is disposed by {@link #onAndroidSdkUpdaterDispose()}.
+ */
+ private void setWindowImage(Shell androidSdkUpdater) {
+ InputStream stream = getClass().getResourceAsStream("android_icon_16.png"); //$NON-NLS-1$
+ if (stream != null) {
+ try {
+ ImageData imgData = new ImageData(stream);
+ mIconImage = new Image(mAndroidSdkUpdater.getDisplay(),
+ imgData,
+ imgData.getTransparencyMask());
+ mAndroidSdkUpdater.setImage(mIconImage);
+ } catch (SWTException e) {
+ mUpdaterData.getSdkLog().error(e, "Failed to set window icon"); //$NON-NLS-1$
+ } catch (IllegalArgumentException e) {
+ mUpdaterData.getSdkLog().error(e, "Failed to set window icon"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /**
+ * Once the UI has been created, initializes the content.
+ * This creates the pages, selects the first one, setup sources and scan for local folders.
+ */
+ private void firstInit() {
+ mTaskFactory = new ProgressTaskFactory(getShell());
+
+ addPage(mLocalPackagePage, "Installed Packages");
+ addPage(mRemotePackagesPage, "Available Packages");
+ addExtraPages();
+
+ displayPage(0);
+ mPageList.setSelection(0);
+
+ // TODO read and apply settings
+ // TODO read add-on sources from some file
+ setupSources();
+ scanLocalSdkFolders();
+ }
+
+ // --- page switching ---
+
+ /**
+ * Adds an instance of a page to the page list.
+ * <p/>
+ * Each page is a {@link Composite}. The title of the page is stored in the
+ * {@link Composite#getData()} field.
+ */
+ private void addPage(Composite page, String title) {
+ page.setData(title);
+ mPages.add(page);
+ mPageList.add(title);
+ }
+
+ /**
+ * Adds all extra pages. For each page, instantiates an instance of the {@link Composite}
+ * using the constructor that takes a single {@link Composite} argument and then adds it
+ * to the page list.
+ */
+ @SuppressWarnings("unchecked")
+ private void addExtraPages() {
+ for (Object[] extraPage : mExtraPages) {
+ String title = (String) extraPage[0];
+ Class<? extends Composite> clazz = (Class<? extends Composite>) extraPage[1];
+
+ // We want the constructor that takes a single Composite as parameter
+ Constructor<? extends Composite> cons;
+ try {
+ cons = clazz.getConstructor(new Class<?>[] { Composite.class });
+ Composite instance = cons.newInstance(new Object[] { mPagesRootComposite });
+ addPage(instance, title);
+
+ } catch (NoSuchMethodException e) {
+ // There is no such constructor.
+ mUpdaterData.getSdkLog().error(e,
+ "Failed to add extra page %1$s. Constructor args must be (Composite parent).", //$NON-NLS-1$
+ clazz.getSimpleName());
+
+ } catch (Exception e) {
+ // Log this instead of crashing the whole app.
+ mUpdaterData.getSdkLog().error(e,
+ "Failed to add extra page %1$s.", //$NON-NLS-1$
+ clazz.getSimpleName());
+ }
+ }
+ }
+
+ /**
+ * Callback invoked when an item is selected in the page list.
+ * If this is not an internal page change, displays the given page.
+ */
+ private void onPageListSelected() {
+ if (mInternalPageChange == false) {
+ int index = mPageList.getSelectionIndex();
+ if (index >= 0) {
+ displayPage(index);
+ }
+ }
+ }
+
+ /**
+ * Displays the page at the given index.
+ *
+ * @param index An index between 0 and {@link #mPages}'s length - 1.
+ */
+ private void displayPage(int index) {
+ Composite page = mPages.get(index);
+ if (page != null) {
+ mStackLayout.topControl = page;
+ mPagesRootComposite.layout(true);
+
+ if (!mInternalPageChange) {
+ mInternalPageChange = true;
+ mPageList.setSelection(index);
+ mInternalPageChange = false;
+ }
+ }
+ }
+
+ /**
+ * Used to initialize the sources.
+ */
+ private void setupSources() {
+ mUpdaterData.getSources().setTaskFactory(mTaskFactory);
+
+ mUpdaterData.getSources().add(
+ new RepoSource(SdkRepository.URL_GOOGLE_SDK_REPO_SITE, false /* addonOnly */));
+
+ String url = System.getenv("TEMP_SDK_URL"); // TODO STOPSHIP temporary remove before shipping
+ if (url != null) {
+ mUpdaterData.getSources().add(new RepoSource(url, false /* addonOnly */));
+ }
+
+ mRemotePackagesPage.setInput(mUpdaterData.getSourcesAdapter());
+ }
+
+ /**
+ * Used to scan the local SDK folders the first time.
+ */
+ private void scanLocalSdkFolders() {
+ mUpdaterData.getLocalSdkAdapter().setSdkRoot(mUpdaterData.getOsSdkRoot());
+
+ mLocalPackagePage.setInput(mUpdaterData.getLocalSdkAdapter());
+ }
+
+ /**
+ * Install the list of given {@link Archive}s.
+ * @param archives The archives to install. Incompatible ones will be skipped.
+ */
+ 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
+ //$hide<<$
+}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/android_icon_16.png b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/android_icon_16.png
similarity index 100%
rename from tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/android_icon_16.png
rename to tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/android_icon_16.png
Binary files differ
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/AvailablePackagesPage.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/AvailablePackagesPage.java
deleted file mode 100755
index 7c4565a..0000000
--- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/AvailablePackagesPage.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package com.android.sdkuilib.repository;
-
-import com.android.sdkuilib.repository.UpdaterWindow.UpdaterData;
-
-import org.eclipse.jface.viewers.CheckboxTreeViewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Group;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.TreeColumn;
-
-class AvailablePackagesPage extends Composite {
-
- private final UpdaterData mUpdaterData;
-
- private CheckboxTreeViewer mTreeViewAvailPkg;
- private Tree mTreeAvailPkg;
- private TreeColumn mColumnAvailSummary;
- private TreeColumn mColumnAvailApiLevel;
- private TreeColumn mColumnAvailRevision;
- private TreeColumn mColumnAvailOs;
- private TreeColumn mColumnAvailInstalled;
- private Group mAvailDescription;
- private Button mAvailAddSite;
- private Button mAvailRemoveSite;
- private Label mPlaceholder3;
- private Button mAvailRefresh;
- private Button mAvailInstallSelected;
-
-
- /**
- * Create the composite.
- * @param parent The parent of the composite.
- * @param updaterData An instance of {@link UpdaterWindow.UpdaterData}. If null, a local
- * one will be allocated just to help with the SWT Designer.
- */
- public AvailablePackagesPage(Composite parent, UpdaterData updaterData) {
- super(parent, SWT.BORDER);
-
- mUpdaterData = updaterData != null ? updaterData : new UpdaterWindow.UpdaterData();
-
- createContents(this);
- }
-
- private void createContents(Composite parent) {
- parent.setLayout(new GridLayout(5, false));
-
- mTreeViewAvailPkg = new CheckboxTreeViewer(parent, SWT.BORDER);
- mTreeViewAvailPkg.setContentProvider(mUpdaterData.getSources().getContentProvider());
- mTreeViewAvailPkg.setLabelProvider(mUpdaterData.getSources().getLabelProvider());
- mTreeAvailPkg = mTreeViewAvailPkg.getTree();
- mTreeAvailPkg.setHeaderVisible(true);
- mTreeAvailPkg.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 5, 1));
-
- mColumnAvailSummary = new TreeColumn(mTreeAvailPkg, SWT.NONE);
- mColumnAvailSummary.setWidth(289);
- mColumnAvailSummary.setText("Summary");
-
- mColumnAvailApiLevel = new TreeColumn(mTreeAvailPkg, SWT.NONE);
- mColumnAvailApiLevel.setWidth(66);
- mColumnAvailApiLevel.setText("API Level");
-
- mColumnAvailRevision = new TreeColumn(mTreeAvailPkg, SWT.NONE);
- mColumnAvailRevision.setWidth(63);
- mColumnAvailRevision.setText("Revision");
-
- mColumnAvailOs = new TreeColumn(mTreeAvailPkg, SWT.NONE);
- mColumnAvailOs.setWidth(100);
- mColumnAvailOs.setText("OS/Arch");
-
- mColumnAvailInstalled = new TreeColumn(mTreeAvailPkg, SWT.NONE);
- mColumnAvailInstalled.setWidth(59);
- mColumnAvailInstalled.setText("Installed");
-
- mAvailDescription = new Group(parent, SWT.NONE);
- mAvailDescription.setText("Description");
- mAvailDescription.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 5, 1));
-
- mAvailAddSite = new Button(parent, SWT.NONE);
- mAvailAddSite.setText("Add Site...");
-
- mAvailRemoveSite = new Button(parent, SWT.NONE);
- mAvailRemoveSite.setText("Delete Site...");
-
- mPlaceholder3 = new Label(parent, SWT.NONE);
- mPlaceholder3.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1));
-
- mAvailRefresh = new Button(parent, SWT.NONE);
- mAvailRefresh.setText("Refresh");
-
- mAvailInstallSelected = new Button(parent, SWT.NONE);
- mAvailInstallSelected.setText("Install Selected");
- }
-
- @Override
- protected void checkSubclass() {
- // Disable the check that prevents subclassing of SWT components
- }
-
- // -- Start of internal part ----------
- // Hide everything down-below from SWT designer
- //$hide>>$
-
- public void setInput(RepoSources sources) {
- mTreeViewAvailPkg.setInput(sources);
- }
-
-
- // End of hiding from SWT Designer
- //$hide<<$
-
-}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/ITaskMonitor.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/ITaskMonitor.java
deleted file mode 100755
index 72375ab..0000000
--- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/ITaskMonitor.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2009 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.repository;
-
-import org.eclipse.swt.widgets.ProgressBar;
-
-/**
- * A monitor interface for a {@link ProgressTask}
- */
-interface ITaskMonitor {
-
- /**
- * Sets the description in the current task dialog.
- * This method can be invoke from a non-UI thread.
- */
- public void setDescription(String description);
-
- /**
- * Sets the result text in the current task dialog.
- * This method can be invoked from a non-UI thread.
- */
- public void setResult(String result);
-
- /**
- * Sets the max value of the progress bar.
- * This method can be invoke from a non-UI thread.
- *
- * @see ProgressBar#setMaximum(int)
- */
- public void setProgressMax(int max);
-
- /**
- * Increments the current value of the progress bar.
- *
- * This method can be invoked from a non-UI thread.
- */
- public void incProgress(int delta);
-
- /**
- * Returns true if the "Cancel" button was selected.
- * It is up to the task thread to pool this and exit.
- */
- public boolean cancelRequested();
-
-
-}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/InstalledPackagesPage.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/InstalledPackagesPage.java
deleted file mode 100755
index 95d180d..0000000
--- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/InstalledPackagesPage.java
+++ /dev/null
@@ -1,168 +0,0 @@
-package com.android.sdkuilib.repository;
-
-import com.android.sdkuilib.repository.ProgressTask.ThreadTask;
-import com.android.sdkuilib.repository.UpdaterWindow.UpdaterData;
-
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Group;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.Text;
-
-public class InstalledPackagesPage extends Composite {
- private UpdaterData mUpdaterData;
-
- private Label mSdkLocLabel;
- private Text mSdkLocText;
- private Button mSdkLocBrowse;
- private Label mInstalledPkgLabel;
- private TableViewer mTableViewerInstPkg;
- private Table mTableInstPkg;
- private TableColumn mColumnInstSummary;
- private TableColumn mColumnInstApiLevel;
- private TableColumn mColumnInstRevision;
- private Group mInstDescription;
- private Composite mInstButtons;
- private Button mInstUpdate;
- private Label mPlaceholder1;
- private Button mInstDelete;
- private Label mPlaceholder2;
- private Button mInstHomePage;
-
- /**
- * Create the composite.
- * @param parent The parent of the composite.
- * @param updaterData An instance of {@link UpdaterWindow.UpdaterData}. If null, a local
- * one will be allocated just to help with the SWT Designer.
- */
- public InstalledPackagesPage(Composite parent, UpdaterData updaterData) {
- super(parent, SWT.BORDER);
-
- mUpdaterData = updaterData != null ? updaterData : new UpdaterWindow.UpdaterData();
-
- createContents(this);
- }
-
- private void createContents(Composite parent) {
- parent.setLayout(new GridLayout(3, false));
-
- createSdkLocation(parent);
-
- mInstalledPkgLabel = new Label(parent, SWT.NONE);
- mInstalledPkgLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1));
- mInstalledPkgLabel.setText("Installed Packages:");
-
- mTableViewerInstPkg = new TableViewer(parent, SWT.BORDER | SWT.FULL_SELECTION);
- mTableInstPkg = mTableViewerInstPkg.getTable();
- mTableInstPkg.setHeaderVisible(true);
- 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");
-
- mInstDescription = new Group(parent, SWT.NONE);
- mInstDescription.setText("Description");
- mInstDescription.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1));
-
- mInstButtons = new Composite(parent, SWT.NONE);
- mInstButtons.setLayout(new GridLayout(5, false));
- mInstButtons.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
-
- mInstUpdate = new Button(mInstButtons, SWT.NONE);
- mInstUpdate.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- onUpdateInstalledPackage(); //$hide$ (hide from SWT designer)
- }
- });
- mInstUpdate.setText("Update...");
-
- mPlaceholder1 = new Label(mInstButtons, SWT.NONE);
- mPlaceholder1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-
- mInstDelete = new Button(mInstButtons, SWT.NONE);
- mInstDelete.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
- mInstDelete.setText("Delete...");
-
- mPlaceholder2 = new Label(mInstButtons, SWT.NONE);
- mPlaceholder2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
-
- mInstHomePage = new Button(mInstButtons, SWT.NONE);
- mInstHomePage.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
- mInstHomePage.setText("Home Page...");
- }
-
- private void createSdkLocation(Composite parent) {
- mSdkLocLabel = new Label(parent, SWT.NONE);
- mSdkLocLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
- mSdkLocLabel.setText("SDK Location:");
-
- // If the sdk path is not user-customizable, do not create
- // the browse button and use horizSpan=2 on the text field.
-
- mSdkLocText = new Text(parent, SWT.BORDER);
- mSdkLocText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
-
- if (mUpdaterData.canUserChangeSdkRoot()) {
- mSdkLocBrowse = new Button(parent, SWT.NONE);
- mSdkLocBrowse.setText("Browse...");
- } else {
- mSdkLocText.setEditable(false);
- ((GridData)mSdkLocText.getLayoutData()).horizontalSpan++;
- }
-
- if (mUpdaterData.getOsSdkRoot() != null) {
- mSdkLocText.setText(mUpdaterData.getOsSdkRoot());
- }
- }
-
- @Override
- protected void checkSubclass() {
- // Disable the check that prevents subclassing of SWT components
- }
-
- // -- Start of internal part ----------
- // Hide everything down-below from SWT designer
- //$hide>>$
-
- protected void onUpdateInstalledPackage() {
- ProgressTask.start(getShell(), "Test", new ThreadTask() {
- public void PerformTask(ITaskMonitor monitor) {
- monitor.setDescription("Test");
- monitor.setProgressMax(100);
- int n = 0;
- int d = 1;
- while(!monitor.cancelRequested()) {
- monitor.incProgress(d);
- n += d;
- if (n == 0 || n == 100) d = -d;
- try {
- Thread.sleep(5);
- } catch (InterruptedException e) {
- }
- }
- }
- });
- }
-
-
- // End of hiding from SWT Designer
- //$hide<<$
-}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/RepoSources.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/RepoSources.java
deleted file mode 100755
index c06e16d..0000000
--- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/RepoSources.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2009 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.repository;
-
-import org.eclipse.jface.viewers.IContentProvider;
-import org.eclipse.jface.viewers.ILabelProvider;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.LabelProvider;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Shell;
-
-import java.util.ArrayList;
-
-/**
- *
- */
-class RepoSources {
-
- private Shell mShell;
- private ArrayList<RepoSource> mSources = new ArrayList<RepoSource>();
-
- public RepoSources() {
- }
-
- public void setShell(Shell shell) {
- mShell = shell;
- }
-
- public void add(RepoSource source) {
- mSources.add(source);
- }
-
- public ILabelProvider getLabelProvider() {
- return new ViewerLabelProvider();
- }
-
-
- public IContentProvider getContentProvider() {
- return new TreeContentProvider();
- }
-
- // ------------
-
- public 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) {
- return super.getText(element);
- }
- }
-
- // ------------
-
- private class TreeContentProvider implements ITreeContentProvider {
-
- private Object mInput;
-
- // 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) {
- mInput = newInput;
- // pass
- }
-
- /**
- * Called to collect the root elements for the given input.
- * The input here is a {@link RepoSources} object, this returns an array
- * of {@link RepoSource}.
- */
- public Object[] getElements(Object inputElement) {
- return getChildren(inputElement);
- }
-
- /**
- * Get the children of the given parent. This is requested on-demand as
- * nodes are expanded.
- *
- * For a {@link RepoSources} object, returns an array of {@link RepoSource}.
- * For a {@link RepoSource}, returns an array of packages.
- */
- public Object[] getChildren(Object parentElement) {
- if (parentElement instanceof RepoSources) {
- return ((RepoSources) parentElement).mSources.toArray();
-
- } else if (parentElement instanceof RepoSource) {
- RepoSource source = (RepoSource) parentElement;
- ArrayList<String> pkgs = source.getPackages();
-
- if (pkgs == null) {
- source.load(mShell);
- pkgs = source.getPackages();
- }
- if (pkgs != null) {
- return pkgs.toArray();
- }
- }
-
- return new Object[0];
- }
-
- /**
- * Returns the parent of a given element.
- * The input {@link RepoSources} is the parent of all {@link RepoSource} elements.
- */
- public Object getParent(Object element) {
- if (element instanceof RepoSource) {
- return mInput;
- }
- return null;
- }
-
- /**
- * Returns true if a given element has children, which is used to display a
- * "+/expand" box next to the tree node.
- * All {@link RepoSource} are expandable, whether they actually have any childre or not.
- */
- public boolean hasChildren(Object element) {
- return element instanceof RepoSource;
- }
- }
-
-}
diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/UpdaterWindow.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/UpdaterWindow.java
index a9f5cdd..8ca3324 100755
--- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/UpdaterWindow.java
+++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/repository/UpdaterWindow.java
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
- * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * 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.eclipse.org/org/documents/epl-v10.php
+ * 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,
@@ -16,230 +16,50 @@
package com.android.sdkuilib.repository;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.SWTException;
-import org.eclipse.swt.custom.SashForm;
-import org.eclipse.swt.custom.StackLayout;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.FillLayout;
+import com.android.sdklib.ISdkLog;
+import com.android.sdkuilib.internal.repository.UpdaterWindowImpl;
+
import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.List;
-import org.eclipse.swt.widgets.Shell;
-import java.io.InputStream;
-import java.util.ArrayList;
-
+/**
+ * Opens an SDK Updater Window.
+ *
+ * This is the public interface for using the window.
+ */
public class UpdaterWindow {
- static class UpdaterData {
- private String mOsSdkRoot;
- private boolean mUserCanChangeSdkRoot;
- private RepoSources mSources = new RepoSources();
+ private UpdaterWindowImpl mWindow;
- public void setOsSdkRoot(String osSdkRoot) {
- mOsSdkRoot = osSdkRoot;
- }
-
- public String getOsSdkRoot() {
- return mOsSdkRoot;
- }
-
- public void setUserCanChangeSdkRoot(boolean userCanChangeSdkRoot) {
- mUserCanChangeSdkRoot = userCanChangeSdkRoot;
- }
-
- public boolean canUserChangeSdkRoot() {
- return mUserCanChangeSdkRoot;
- }
-
- public void setSources(RepoSources sources) {
- mSources = sources;
- }
-
- public RepoSources getSources() {
- return mSources;
- }
- }
-
- private final UpdaterData mUpdaterData = new UpdaterData();
- private ArrayList<Composite> mPages = new ArrayList<Composite>();
- private boolean mInternalPageChange;
-
- // --- UI members ---
-
- protected Shell mAndroidSdkUpdater;
- private SashForm mSashForm;
- private List mPageList;
- private Composite mPagesRootComposite;
- private InstalledPackagesPage mInstalledPackagePage;
- private AvailablePackagesPage mAvailablePackagesPage;
- private StackLayout mStackLayout;
- private Image mIconImage;
-
- public UpdaterWindow(String osSdkRoot, boolean userCanChangeSdkRoot) {
- mUpdaterData.setOsSdkRoot(osSdkRoot);
- mUpdaterData.setUserCanChangeSdkRoot(userCanChangeSdkRoot);
+ /**
+ * Creates a new window. Caller must call open(), which will block.
+ * @param sdkLog
+ * @param osSdkRoot The OS path to the SDK root.
+ * @param userCanChangeSdkRoot If true, the window lets the user change the SDK path
+ * being browsed.
+ */
+ public UpdaterWindow(ISdkLog sdkLog, String osSdkRoot, boolean userCanChangeSdkRoot) {
+ mWindow = new UpdaterWindowImpl(sdkLog, osSdkRoot, userCanChangeSdkRoot);
}
/**
- * Open the window.
- * @wbp.parser.entryPoint
+ * Registers an extra page for the updater window.
+ * <p/>
+ * Pages must derive from {@link Composite} and implement a constructor that takes
+ * a single parent {@link Composite} argument.
+ * <p/>
+ * All pages must be registered before the call to {@link #open()}.
+ *
+ * @param title The title of the page.
+ * @param pageClass The {@link Composite}-derived class that will implement the page.
+ */
+ public void registerPage(String title, Class<? extends Composite> pageClass) {
+ mWindow.registerExtraPage(title, pageClass);
+ }
+
+ /**
+ * Opens the window.
*/
public void open() {
- Display display = Display.getDefault();
- createContents();
- mAndroidSdkUpdater.open();
- mAndroidSdkUpdater.layout();
-
- firstInit(); //$hide$ (hide from SWT designer)
-
- while (!mAndroidSdkUpdater.isDisposed()) {
- if (!display.readAndDispatch()) {
- display.sleep();
- }
- }
+ mWindow.open();
}
-
- /**
- * Create contents of the window.
- */
- protected void createContents() {
- mAndroidSdkUpdater = new Shell();
- setWindowImage(mAndroidSdkUpdater);
- mAndroidSdkUpdater.addDisposeListener(new DisposeListener() {
- public void widgetDisposed(DisposeEvent e) {
- onAndroidSdkUpdaterDispose(); //$hide$ (hide from SWT designer)
- }
- });
-
- mAndroidSdkUpdater.setLayout(new FillLayout(SWT.HORIZONTAL));
- mAndroidSdkUpdater.setMinimumSize(new Point(200, 50));
- mAndroidSdkUpdater.setSize(745, 433);
- mAndroidSdkUpdater.setText("Android SDK Updater");
-
- mSashForm = new SashForm(mAndroidSdkUpdater, SWT.NONE);
-
- mPageList = new List(mSashForm, SWT.BORDER);
- mPageList.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- onPageListSelected(e); //$hide$ (hide from SWT designer)
- }
- });
-
- mPagesRootComposite = new Composite(mSashForm, SWT.NONE);
- mStackLayout = new StackLayout();
- mPagesRootComposite.setLayout(mStackLayout);
-
- mInstalledPackagePage = new InstalledPackagesPage(mPagesRootComposite, mUpdaterData);
- mAvailablePackagesPage = new AvailablePackagesPage(mPagesRootComposite, mUpdaterData);
- mSashForm.setWeights(new int[] {150, 576});
- }
-
-
- // -- Start of internal part ----------
- // Hide everything down-below from SWT designer
- //$hide>>$
-
- // --- UI Callbacks -----------
-
- private void onAndroidSdkUpdaterDispose() {
- if (mIconImage != null) {
- mIconImage.dispose();
- mIconImage = null;
- }
- }
-
- private void setWindowImage(Shell androidSdkUpdater) {
- InputStream stream = getClass().getResourceAsStream("android_icon_16.png"); //$NON-NLS-1$
- if (stream != null) {
- try {
- ImageData imgData = new ImageData(stream);
- mIconImage = new Image(mAndroidSdkUpdater.getDisplay(),
- imgData,
- imgData.getTransparencyMask());
- mAndroidSdkUpdater.setImage(mIconImage);
- } catch (SWTException e) {
- // ignore
- } catch (IllegalArgumentException e) {
- // ignore
- }
- }
- }
-
- private Shell getShell() {
- return mAndroidSdkUpdater;
- }
-
- /**
- * Once the UI has been created, initialize the content
- */
- private void firstInit() {
- addPage(mInstalledPackagePage, "Installed Packages");
- addPage(mAvailablePackagesPage, "Available Packages");
- displayPage(0);
- mPageList.setSelection(0);
-
- setupSources();
- scanLocalSdkFolders();
- }
-
- // --- page switching ---
-
- private void addPage(Composite page, String title) {
- page.setData(title);
- mPages.add(page);
- mPageList.add(title);
- }
-
- private void onPageListSelected(SelectionEvent e) {
- if (mInternalPageChange == false) {
- int index = mPageList.getSelectionIndex();
- if (index >= 0) {
- displayPage(index);
- }
- }
- }
-
- private void displayPage(int index) {
- Composite page = mPages.get(index);
- if (page != null) {
- mStackLayout.topControl = page;
- mPagesRootComposite.layout(true);
-
- if (!mInternalPageChange) {
- mInternalPageChange = true;
- mPageList.setSelection(index);
- mInternalPageChange = false;
- }
- }
- }
-
- private void setupSources() {
- mUpdaterData.getSources().setShell(getShell());
-
- mUpdaterData.getSources().add(new RepoSource(
- "https://dl.google.com/android/eclipse/repository/index.xml", //$NON-NLS-1$
- false /* addonOnly */));
- mUpdaterData.getSources().add(new RepoSource(
- "http://www.corp.google.com/~raphael/android/sdk-repo/repository.xml", //$NON-NLS-1$
- false /* addonOnly */));
-
- mAvailablePackagesPage.setInput(mUpdaterData.getSources());
- }
-
- private void scanLocalSdkFolders() {
- // TODO Auto-generated method stub
-
- }
-
- // End of hiding from SWT Designer
- //$hide<<$
}