auto import from //branches/cupcake/...@132276
diff --git a/apps/Development/AndroidManifest.xml b/apps/Development/AndroidManifest.xml
index 7bf8404..879e7d6 100644
--- a/apps/Development/AndroidManifest.xml
+++ b/apps/Development/AndroidManifest.xml
@@ -51,12 +51,6 @@
                 <category android:name="android.intent.category.TEST" />
             </intent-filter>
         </activity>
-        <activity android:name="PreferredPackages" android:label="Preferred Packages">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.TEST" />
-            </intent-filter>
-        </activity>
         <activity android:name="ExceptionBrowser" android:label="Exception Browser">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/apps/Development/src/com/android/development/PointerLocation.java b/apps/Development/src/com/android/development/PointerLocation.java
index 6453306..668e9ba 100644
--- a/apps/Development/src/com/android/development/PointerLocation.java
+++ b/apps/Development/src/com/android/development/PointerLocation.java
@@ -40,6 +40,11 @@
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         setContentView(new MyView(this));
+        
+        // Make the screen full bright for this activity.
+        WindowManager.LayoutParams lp = getWindow().getAttributes();
+        lp.screenBrightness = 1.0f;
+        getWindow().setAttributes(lp);
     }
     
     public class MyView extends View {
diff --git a/apps/Development/src/com/android/development/PreferredPackages.java b/apps/Development/src/com/android/development/PreferredPackages.java
deleted file mode 100644
index 1c6f23c..0000000
--- a/apps/Development/src/com/android/development/PreferredPackages.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.development;
-
-import android.app.ListActivity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.BroadcastReceiver;
-import android.content.pm.PackageInfo;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-public class PreferredPackages extends ListActivity {
-    private static final int ADD_APP_REQUEST = 1;
-    
-    private PackageListAdapter mAdapter;
-    private Handler mHandler;
-
-    final static class Entry {
-        final PackageInfo info;
-        final CharSequence label;
-        
-        Entry(PackageInfo _info, CharSequence _label) {
-            info = _info;
-            label = _label;
-        }
-    }
-    private final ArrayList<Entry> mPackageInfoList = new ArrayList<Entry>();
-    
-    final class PackageListAdapter extends ArrayAdapter<Entry> {
-        public PackageListAdapter(Context context) {
-            super(context, android.R.layout.simple_list_item_1);
-            List<PackageInfo> pkgs =
-                    context.getPackageManager().getPreferredPackages(0);
-            final int N = pkgs.size();
-            mPackageInfoList.clear();
-            for (int i=0; i<N; i++) {
-                PackageInfo pi = pkgs.get(i);
-                if (pi.applicationInfo == null) {
-                    continue;
-                }
-                mPackageInfoList.add(new Entry(pi,
-                        getPackageManager().getApplicationLabel(
-                                pi.applicationInfo)));
-            }
-            Collections.sort(mPackageInfoList, sDisplayNameComparator);
-            setSource(mPackageInfoList);
-        }
-    
-        public void bindView(View view, Entry info) {
-            TextView text = (TextView)view.findViewById(android.R.id.text1);
-            text.setText(info.label);
-        }
-    }
-
-    private final static Comparator<Entry> sDisplayNameComparator = new Comparator<Entry>() {
-        public final int
-        compare(Entry a, Entry b) {
-            return collator.compare(a.toString(), b.toString());
-        }
-
-        private final Collator   collator = Collator.getInstance();
-    };
-
-    /**
-     * Receives notifications when applications are added/removed.
-     */
-    private final BroadcastReceiver mAppsReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            setupAdapter();
-        }
-    };
-
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        setupAdapter();
-        mHandler = new Handler();
-        registerIntentReceivers();
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        unregisterIntentReceivers();
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        menu.add(0, 0, 0, "Add Package").setOnMenuItemClickListener(
-                new MenuItem.OnMenuItemClickListener() {
-            public boolean onMenuItemClick(MenuItem item) {
-                addPackage();
-                return true;
-            }
-        });
-        menu.add(0, 0, 0, "Remove Package").setOnMenuItemClickListener(
-                new MenuItem.OnMenuItemClickListener() {
-            public boolean onMenuItemClick(MenuItem item) {
-                removePackage();
-                return true;
-            }
-        });
-        return true;
-    }
-
-    @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
-        if (requestCode == ADD_APP_REQUEST && resultCode == RESULT_OK) {
-            getPackageManager().addPackageToPreferred(intent.getAction());
-            setupAdapter();
-        }
-    }
-    
-    @Override
-    protected void onListItemClick(ListView l, View v, int position, long id) {
-        Entry info =
-            mAdapter.itemForPosition(position);
-        if (info != null) {
-            Intent intent = new Intent(
-                Intent.ACTION_VIEW,
-                Uri.fromParts("package", info.info.packageName, null));
-            intent.setClass(this, PackageSummary.class);
-            startActivity(intent);
-        }
-    }
-
-    private void setupAdapter() {
-        mAdapter = new PackageListAdapter(this);
-        setListAdapter(mAdapter);
-    }
-
-    private void removePackage() {
-        final int curSelection = this.getSelectedItemPosition();
-        if (curSelection >= 0) {
-            final Entry packageInfo = mAdapter.itemForPosition(curSelection);
-            if (packageInfo != null) {
-                getPackageManager().removePackageFromPreferred(
-                        packageInfo.info.packageName);
-            }
-            setupAdapter();
-        }
-    }
-
-    private void addPackage() {
-        Intent intent = new Intent(Intent.ACTION_MAIN);
-        intent.setClass(this, AppPicker.class);
-        startActivityForResult(intent, ADD_APP_REQUEST);
-    }
-    
-    private void registerIntentReceivers() {
-        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
-        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        filter.addDataScheme("package");
-        registerReceiver(mAppsReceiver, filter);
-    }
-
-    private void unregisterIntentReceivers() {
-        unregisterReceiver(mAppsReceiver);
-    }
-}
diff --git a/build/sdk.atree b/build/sdk.atree
index 986ce62..365f2f7 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -19,8 +19,8 @@
 #
 
 # host tools from out/host/$(HOST_OS)-$(HOST_ARCH)/
-bin/aapt tools/aapt
-bin/aidl tools/aidl
+bin/aapt platforms/${PLATFORM_NAME}/tools/aapt
+bin/aidl platforms/${PLATFORM_NAME}/tools/aidl
 bin/adb tools/adb
 bin/sqlite3 tools/sqlite3
 bin/dmtracedump tools/dmtracedump
@@ -68,9 +68,9 @@
 development/samples/Snake platforms/${PLATFORM_NAME}/samples/Snake
 
 # dx
-bin/dx tools/dx
-bin/dexdump tools/dexdump
-framework/dx.jar tools/lib/dx.jar
+bin/dx platforms/${PLATFORM_NAME}/tools/dx
+bin/dexdump platforms/${PLATFORM_NAME}/tools/dexdump
+framework/dx.jar platforms/${PLATFORM_NAME}/tools/lib/dx.jar
 
 #androidprefs
 framework/androidprefs.jar tools/lib/androidprefs.jar
diff --git a/build/tools/make_windows_sdk.sh b/build/tools/make_windows_sdk.sh
index bf52679..a32546c 100755
--- a/build/tools/make_windows_sdk.sh
+++ b/build/tools/make_windows_sdk.sh
@@ -9,6 +9,10 @@
 
 set -e  # Fail this script as soon as a command fails -- fail early, fail fast
 
+# Set to 1 to force removal of old unzipped SDK. Only disable for debugging, as it
+# will make some rm/mv commands to fail.
+FORCE="1" 
+
 SDK_ZIP="$1"
 DIST_DIR="$2"
 
@@ -71,38 +75,52 @@
     DEST_NAME_ZIP="${DEST_NAME}.zip"
 
     # Unzip current linux/mac SDK and rename using the windows name
-    [ -e "$DEST" ] && rm -rfv "$DEST"  # cleanup dest first if exists
-    UNZIPPED=`basename "$SDK_ZIP"`
-    UNZIPPED="$DIST_DIR/${UNZIPPED/.zip/}"
-    [ -e "$UNZIPPED" ] && rm -rfv "$UNZIPPED"  # cleanup unzip dir (if exists)
-    unzip "$SDK_ZIP" -d "$DIST_DIR"
-    mv -v "$UNZIPPED" "$DEST"
+    if [[ -n "$FORCE" || ! -d "$DEST" ]]; then
+        [ -e "$DEST" ] && rm -rfv "$DEST"  # cleanup dest first if exists
+        UNZIPPED=`basename "$SDK_ZIP"`
+        UNZIPPED="$DIST_DIR/${UNZIPPED/.zip/}"
+        [ -e "$UNZIPPED" ] && rm -rfv "$UNZIPPED"  # cleanup unzip dir (if exists)
+        unzip "$SDK_ZIP" -d "$DIST_DIR"
+        mv -v "$UNZIPPED" "$DEST"
+    fi
     
+    # Assert that the package contains only one platform
+    PLATFORMS="$DEST/platforms"
+    THE_PLATFORM=`echo $PLATFORMS/*`
+    PLATFORM_TOOLS=$THE_PLATFORM/tools
+    echo "Platform found: " $THE_PLATFORM
+    [[ -d "$THE_PLATFORM" ]] || die \
+        "Error: One platform was expected in $SDK_ZIP. " \
+        "Instead found " $THE_PLATFORM
+    [[ -d "$PLATFORM_TOOLS" ]] || die "Missing folder $PLATFORM_TOOLS."
+
+
     # USB Driver for ADB
     mkdir -pv $DEST/usb_driver/x86
     cp -rv development/host/windows/prebuilt/usb/driver/* $DEST/usb_driver/x86/
     mkdir -pv $DEST/usb_driver/amd64
     cp -rv development/host/windows/prebuilt/usb/driver_amd_64/* $DEST/usb_driver/amd64/
 
-    # Remove obsolete stuff from tools
+    # Remove obsolete stuff from tools & platform
     TOOLS="$DEST/tools"
     LIB="$DEST/tools/lib"
-    rm -v "$TOOLS"/{aapt,aidl,adb,emulator,traceview,draw9patch,hierarchyviewer,dx,dexdump,apkbuilder,ddms,dmtracedump,mksdcard,sqlite3,android}
+    rm -v "$TOOLS"/{adb,emulator,traceview,draw9patch,hierarchyviewer,apkbuilder,ddms,dmtracedump,mksdcard,sqlite3,android}
     rm -v --force "$LIB"/*.so "$LIB"/*.jnilib
+    rm -v "$PLATFORM_TOOLS"/{aapt,aidl,dx,dexdump}
+
 
     # Copy all the new stuff in tools
+    # Note: some tools are first copied here and then moved in platforms/<name>/tools/
     cp -v out/host/windows-x86/bin/*.{exe,dll} "$TOOLS"
     cp -v prebuilt/windows/swt/*.{jar,dll} "$LIB"
-    # Do we want the emulator NOTICE in the tools dir? Cf http://b/930608.
-    # If yes, uncomment the following line:
-    # cp -v external/qemu/NOTICE "$TOOLS"/emulator_NOTICE.txt
 
+    # If you want the emulator NOTICE in the tools dir, uncomment the following line:
+    # cp -v external/qemu/NOTICE "$TOOLS"/emulator_NOTICE.txt
 
     # We currently need libz from MinGW for aapt
     cp -v /cygdrive/c/cygwin/bin/mgwz.dll "$TOOLS"
 
     # Update a bunch of bat files
-    cp -v dalvik/dx/etc/dx.bat "$TOOLS"
     cp -v development/tools/apkbuilder/etc/apkbuilder.bat "$TOOLS"
     cp -v development/tools/ddms/app/etc/ddms.bat "$TOOLS"
     cp -v development/tools/traceview/etc/traceview.bat "$TOOLS"
@@ -110,8 +128,15 @@
     cp -v development/tools/draw9patch/etc/draw9patch.bat "$TOOLS"
     cp -v development/tools/sdkmanager/app/etc/android.bat "$TOOLS"
 
+    # Copy or move platform specific tools to the default platform.
+    cp -v dalvik/dx/etc/dx.bat "$PLATFORM_TOOLS"
+    # Note: mgwz.dll must be in same folder than aapt.exe
+    mv -v "$TOOLS"/{aapt.exe,aidl.exe,dexdump.exe,mgwz.dll} "$PLATFORM_TOOLS"
+
     # Fix EOL chars to make window users happy - fix all files at the top level only
-    find "$DIST_DIR" -maxdepth 1 -type f -print | xargs unix2dos -D
+    # as well as all batch files including those in platforms/<name>/tools/
+    find "$DIST_DIR" -maxdepth 1 -type f -writable -print0 | xargs -0 unix2dos -D
+    find "$DIST_DIR" -maxdepth 3 -name "*.bat" -type f -writable -print0 | xargs -0 unix2dos -D
 
     # Done.. Zip it
     pushd "$DIST_DIR" > /dev/null
diff --git a/samples/GlobalTime/Android.mk b/samples/GlobalTime/Android.mk
index bd0e563..deb82f5 100644
--- a/samples/GlobalTime/Android.mk
+++ b/samples/GlobalTime/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/samples/NotePad/Android.mk b/samples/NotePad/Android.mk
index 490a31d..7939212 100644
--- a/samples/NotePad/Android.mk
+++ b/samples/NotePad/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := eng samples
+LOCAL_MODULE_TAGS := samples
 
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/samples/Snake/Android.mk b/samples/Snake/Android.mk
index e0cfdfd..56b642e 100644
--- a/samples/Snake/Android.mk
+++ b/samples/Snake/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := eng samples
+LOCAL_MODULE_TAGS := samples
 
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/samples/SoftKeyboard/Android.mk b/samples/SoftKeyboard/Android.mk
index dfd546e..883bf2f 100755
--- a/samples/SoftKeyboard/Android.mk
+++ b/samples/SoftKeyboard/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := eng samples
+LOCAL_MODULE_TAGS := samples
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/tools/anttasks/src/com/android/ant/AndroidInitTask.java b/tools/anttasks/src/com/android/ant/AndroidInitTask.java
index 30779c5..d5bc55b 100644
--- a/tools/anttasks/src/com/android/ant/AndroidInitTask.java
+++ b/tools/anttasks/src/com/android/ant/AndroidInitTask.java
@@ -55,6 +55,12 @@
     private final static String PROPERTY_ANDROID_JAR = "android-jar";
     // ant property with the path to the framework.jar
     private final static String PROPERTY_ANDROID_AIDL = "android-aidl";
+    // ant property with the path to the aapt tool
+    private final static String PROPERTY_AAPT = "aapt";
+    // ant property with the path to the aidl tool
+    private final static String PROPERTY_AIDL = "aidl";
+    // ant property with the path to the dx tool
+    private final static String PROPERTY_DX = "dx";
     // ref id to the <path> object containing all the boot classpaths.
     private final static String REF_CLASSPATH = "android.target.classpath";
 
@@ -122,15 +128,19 @@
         System.out.println("Project Target: " + androidTarget.getName());
         if (androidTarget.isPlatform() == false) {
             System.out.println("Vendor: " + androidTarget.getVendor());
+            System.out.println("Platform Version: " + androidTarget.getApiVersionName());
         }
-        System.out.println("Platform Version: " + androidTarget.getApiVersionName());
         System.out.println("API level: " + androidTarget.getApiVersionNumber());
         
-        // sets up the properties to find android.jar/framework.aidl
+        // sets up the properties to find android.jar/framework.aidl/target tools
         String androidJar = androidTarget.getPath(IAndroidTarget.ANDROID_JAR);
-        String androidAidl = androidTarget.getPath(IAndroidTarget.ANDROID_AIDL);
         antProject.setProperty(PROPERTY_ANDROID_JAR, androidJar);
-        antProject.setProperty(PROPERTY_ANDROID_AIDL, androidAidl);
+
+        antProject.setProperty(PROPERTY_ANDROID_AIDL,
+                androidTarget.getPath(IAndroidTarget.ANDROID_AIDL));
+        antProject.setProperty(PROPERTY_AAPT, androidTarget.getPath(IAndroidTarget.AAPT));
+        antProject.setProperty(PROPERTY_AIDL, androidTarget.getPath(IAndroidTarget.AIDL));
+        antProject.setProperty(PROPERTY_DX, androidTarget.getPath(IAndroidTarget.DX));
 
         // sets up the boot classpath
 
diff --git a/tools/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java b/tools/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java
index 74c432d..f3986ed 100644
--- a/tools/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java
+++ b/tools/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java
@@ -54,7 +54,7 @@
     private final static String HOST = "127.0.0.1";  //$NON-NLS-1$
 
     private final static String COMMAND_PING = "help\r\n"; //$NON-NLS-1$
-    private final static String COMMAND_AVD_NAME = "vm name\r\n"; //$NON-NLS-1$  // TODO change with emulator
+    private final static String COMMAND_AVD_NAME = "avd name\r\n"; //$NON-NLS-1$
     private final static String COMMAND_KILL = "kill\r\n"; //$NON-NLS-1$
     private final static String COMMAND_GSM_STATUS = "gsm status\r\n"; //$NON-NLS-1$
     private final static String COMMAND_GSM_CALL = "gsm call %1$s\r\n"; //$NON-NLS-1$
diff --git a/tools/ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java b/tools/ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java
index d168476..81b757e 100644
--- a/tools/ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java
+++ b/tools/ddms/libs/ddmuilib/src/com/android/ddmuilib/DevicePanel.java
@@ -205,6 +205,10 @@
                             String debuggable = device.getProperty(Device.PROP_DEBUGGABLE);
                             if (device.isEmulator()) {
                                 String avdName = device.getAvdName();
+                                if (avdName == null) {
+                                    avdName = "?"; // the device is probably not online yet, so
+                                                   // we don't know its AVD name just yet.
+                                }
                                 if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$
                                     return String.format("%1$s [%2$s, debug]", avdName,
                                             version);
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
index ddc93ac..9aa9354 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
@@ -20,7 +20,6 @@
 import com.android.ddmuilib.StackTracePanel.ISourceRevealer;
 import com.android.ddmuilib.console.DdmConsole;
 import com.android.ddmuilib.console.IDdmConsole;
-import com.android.ide.eclipse.adt.build.DexWrapper;
 import com.android.ide.eclipse.adt.debug.launching.AndroidLaunchController;
 import com.android.ide.eclipse.adt.preferences.BuildPreferencePage;
 import com.android.ide.eclipse.adt.project.ProjectHelper;
@@ -423,8 +422,6 @@
         
         stopEditors();
         
-        DexWrapper.unloadDex();
-
         mRed.dispose();
         synchronized (AdtPlugin.class) {
             sPlugin = null;
@@ -465,21 +462,11 @@
         return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_ADB;
     }
 
-    /** Returns the aapt path relative to the sdk folder */
-    public static String getOsRelativeAapt() {
-        return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_AAPT;
-    }
-
     /** Returns the emulator path relative to the sdk folder */
     public static String getOsRelativeEmulator() {
         return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_EMULATOR;
     }
 
-    /** Returns the aidl path relative to the sdk folder */
-    public static String getOsRelativeAidl() {
-        return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_AIDL;
-    }
-
     /** Returns the absolute adb path */
     public static String getOsAbsoluteAdb() {
         return getOsSdkFolder() + getOsRelativeAdb();
@@ -491,21 +478,11 @@
                 AndroidConstants.FN_TRACEVIEW;
     }
 
-    /** Returns the absolute aapt path */
-    public static String getOsAbsoluteAapt() {
-        return getOsSdkFolder() + getOsRelativeAapt();
-    }
-
     /** Returns the absolute emulator path */
     public static String getOsAbsoluteEmulator() {
         return getOsSdkFolder() + getOsRelativeEmulator();
     }
 
-    /** Returns the absolute aidl path */
-    public static String getOsAbsoluteAidl() {
-        return getOsSdkFolder() + getOsRelativeAidl();
-    }
-
     /**
      * Returns a Url file path to the javaDoc folder.
      */
@@ -968,8 +945,6 @@
         // check the path to various tools we use
         String[] filesToCheck = new String[] {
                 osSdkLocation + getOsRelativeAdb(),
-                osSdkLocation + getOsRelativeAapt(),
-                osSdkLocation + getOsRelativeAidl(),
                 osSdkLocation + getOsRelativeEmulator()
         };
         for (String file : filesToCheck) {
@@ -1058,17 +1033,6 @@
                         // FIXME: move this per platform, or somewhere else.
                         progress = SubMonitor.convert(monitor,
                                 Messages.AdtPlugin_Parsing_Resources, 20);
-                        DexWrapper.unloadDex();
-
-                        IStatus res = DexWrapper.loadDex(
-                                mOsSdkLocation + AndroidConstants.OS_SDK_LIBS_DX_JAR);
-                        if (res != Status.OK_STATUS) {
-                            synchronized (getSdkLockObject()) {
-                                mSdkIsLoaded = LoadStatus.FAILED;
-                                mPostLoadProjectsToResolve.clear();
-                            }
-                            return res;
-                        }
 
                         synchronized (getSdkLockObject()) {
                             mSdkIsLoaded = LoadStatus.LOADED;
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
index 43971b0..c359905 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
@@ -19,7 +19,7 @@
 import com.android.ide.eclipse.adt.AdtConstants;
 import com.android.ide.eclipse.adt.AdtPlugin;
 import com.android.ide.eclipse.adt.project.ProjectHelper;
-import com.android.ide.eclipse.adt.sdk.LoadStatus;
+import com.android.ide.eclipse.adt.sdk.AndroidTargetData;
 import com.android.ide.eclipse.adt.sdk.Sdk;
 import com.android.ide.eclipse.common.AndroidConstants;
 import com.android.ide.eclipse.common.project.BaseProjectHelper;
@@ -67,6 +67,8 @@
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
 
 public class ApkBuilder extends BaseBuilder {
 
@@ -280,8 +282,12 @@
             }
         }
 
-        // also check the final file!
-        String finalPackageName = project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE;
+        // get the extra configs for the project. This will give us a list of custom apk
+        // to build based on a restricted set of resources.
+        Map<String, String> configs = Sdk.getCurrent().getProjectConfigs(project);
+
+        // also check the final file(s)!
+        String finalPackageName = getFileName(project, null /*config*/);
         if (mBuildFinalPackage == false && outputFolder != null) {
             tmp = outputFolder.findMember(finalPackageName);
             if (tmp == null || (tmp instanceof IFile &&
@@ -290,6 +296,24 @@
                 AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
                 mBuildFinalPackage = true;
             }
+
+            if (configs != null) {
+                Set<Entry<String, String>> entrySet = configs.entrySet();
+                
+                for (Entry<String, String> entry : entrySet) {
+                    String filename = getFileName(project, entry.getKey());
+
+                    tmp = outputFolder.findMember(filename);
+                    if (tmp == null || (tmp instanceof IFile &&
+                            tmp.exists() == false)) {
+                        String msg = String.format(Messages.s_Missing_Repackaging,
+                                finalPackageName);
+                        AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
+                        mBuildFinalPackage = true;
+                        break;
+                    }
+                }
+            }
         }
 
         // store the build status in the persistent storage
@@ -358,6 +382,17 @@
             // handle already present .apk, and if that one failed as well, the user will be
             // notified.
             finalPackage.delete();
+            
+            if (configs != null) {
+                Set<Entry<String, String>> entrySet = configs.entrySet();
+                for (Entry<String, String> entry : entrySet) {
+                    String packageFilepath = osBinPath + File.separator +
+                            getFileName(project, entry.getKey());
+
+                    finalPackage = new File(packageFilepath);
+                    finalPackage.delete();
+                }
+            }
 
             // first we check if we need to package the resources.
             if (mPackageResources) {
@@ -401,13 +436,30 @@
                         osAssetsPath = assetsFolder.getLocation().toOSString();
                     }
 
+                    // build the default resource package
                     if (executeAapt(project, osManifestPath, osResPath,
                             osAssetsPath, osBinPath + File.separator +
-                            AndroidConstants.FN_RESOURCES_AP_) == false) {
+                            AndroidConstants.FN_RESOURCES_AP_, null /*configFilter*/) == false) {
                         // aapt failed. Whatever files that needed to be marked
                         // have already been marked. We just return.
                         return referencedProjects;
                     }
+                    
+                    // now do the same thing for all the configured resource packages.
+                    if (configs != null) {
+                        Set<Entry<String, String>> entrySet = configs.entrySet();
+                        for (Entry<String, String> entry : entrySet) {
+                            String outPathFormat = osBinPath + File.separator +
+                                    AndroidConstants.FN_RESOURCES_S_AP_;
+                            String outPath = String.format(outPathFormat, entry.getKey());
+                            if (executeAapt(project, osManifestPath, osResPath,
+                                    osAssetsPath, outPath, entry.getValue()) == false) {
+                                // aapt failed. Whatever files that needed to be marked
+                                // have already been marked. We just return.
+                                return referencedProjects;
+                            }
+                        }
+                    }
 
                     // build has been done. reset the state of the builder
                     mPackageResources = false;
@@ -433,25 +485,49 @@
             }
 
             // now we need to make the final package from the intermediary apk
-            // and classes.dex
+            // and classes.dex.
+            // This is the default package with all the resources.
             
+            String classesDexPath = osBinPath + File.separator + AndroidConstants.FN_CLASSES_DEX; 
             if (finalPackage(osBinPath + File.separator + AndroidConstants.FN_RESOURCES_AP_,
-                            osBinPath + File.separator + AndroidConstants.FN_CLASSES_DEX,
-                            osFinalPackagePath, javaProject, referencedJavaProjects) == false) {
+                            classesDexPath,osFinalPackagePath, javaProject,
+                            referencedJavaProjects) == false) {
                 return referencedProjects;
-            } else {
-                // get the resource to bin
-                outputFolder.refreshLocal(IResource.DEPTH_ONE, monitor);
-
-                // build has been done. reset the state of the builder
-                mBuildFinalPackage = false;
-
-                // and store it
-                saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage);
-                
-                AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(),
-                        "Build Success!");
             }
+            
+            // now do the same thing for all the configured resource packages.
+            if (configs != null) {
+                String resPathFormat = osBinPath + File.separator +
+                        AndroidConstants.FN_RESOURCES_S_AP_;
+
+                Set<Entry<String, String>> entrySet = configs.entrySet();
+                for (Entry<String, String> entry : entrySet) {
+                    // make the filename for the resource package.
+                    String resPath = String.format(resPathFormat, entry.getKey());
+                    
+                    // make the filename for the apk to generate
+                    String apkOsFilePath = osBinPath + File.separator +
+                            getFileName(project, entry.getKey());
+                    if (finalPackage(resPath, classesDexPath, apkOsFilePath, javaProject,
+                            referencedJavaProjects) == false) {
+                        return referencedProjects;
+                    }
+                }
+            }
+
+            // we are done.
+            
+            // get the resource to bin
+            outputFolder.refreshLocal(IResource.DEPTH_ONE, monitor);
+
+            // build has been done. reset the state of the builder
+            mBuildFinalPackage = false;
+
+            // and store it
+            saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage);
+            
+            AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(),
+                    "Build Success!");
         }
         return referencedProjects;
     }
@@ -475,19 +551,26 @@
      * @param osResPath The path to the res folder
      * @param osAssetsPath The path to the assets folder. This can be null.
      * @param osOutFilePath The path to the temporary resource file to create.
+     * @param configFilter The configuration filter for the resources to include
+     * (used with -c option)
      * @return true if success, false otherwise.
      */
     private boolean executeAapt(IProject project, String osManifestPath,
-            String osResPath, String osAssetsPath, String osOutFilePath) {
+            String osResPath, String osAssetsPath, String osOutFilePath, String configFilter) {
+        IAndroidTarget target = Sdk.getCurrent().getTarget(project);
 
         // Create the command line.
         ArrayList<String> commandArray = new ArrayList<String>();
-        commandArray.add(AdtPlugin.getOsAbsoluteAapt());
+        commandArray.add(target.getPath(IAndroidTarget.AAPT));
         commandArray.add("package"); //$NON-NLS-1$
         commandArray.add("-f");//$NON-NLS-1$
         if (AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE) {
             commandArray.add("-v"); //$NON-NLS-1$
         }
+        if (configFilter != null) {
+            commandArray.add("-c"); //$NON-NLS-1$
+            commandArray.add(configFilter);
+        }
         commandArray.add("-M"); //$NON-NLS-1$
         commandArray.add(osManifestPath);
         commandArray.add("-S"); //$NON-NLS-1$
@@ -497,8 +580,7 @@
             commandArray.add(osAssetsPath);
         }
         commandArray.add("-I"); //$NON-NLS-1$
-        commandArray.add(
-                Sdk.getCurrent().getTarget(project).getPath(IAndroidTarget.ANDROID_JAR));
+        commandArray.add(target.getPath(IAndroidTarget.ANDROID_JAR));
         commandArray.add("-F"); //$NON-NLS-1$
         commandArray.add(osOutFilePath);
 
@@ -576,14 +658,19 @@
      */
     private boolean executeDx(IJavaProject javaProject, String osBinPath, String osOutFilePath,
             IJavaProject[] referencedJavaProjects) throws CoreException {
+        IAndroidTarget target = Sdk.getCurrent().getTarget(javaProject.getProject());
+        AndroidTargetData targetData = Sdk.getCurrent().getTargetData(target);
+        if (targetData == null) {
+            throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+                    Messages.ApkBuilder_UnableBuild_Dex_Not_loaded));
+        }
+        
         // get the dex wrapper
-        DexWrapper wrapper = DexWrapper.getWrapper();
+        DexWrapper wrapper = targetData.getDexWrapper();
         
         if (wrapper == null) {
-            if (DexWrapper.getStatus() == LoadStatus.FAILED) {
-                throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
-                        Messages.ApkBuilder_UnableBuild_Dex_Not_loaded));
-            }
+            throw new CoreException(new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+                    Messages.ApkBuilder_UnableBuild_Dex_Not_loaded));
         }
 
         // make sure dx use the proper output streams.
@@ -1003,6 +1090,19 @@
 
         return list.toArray(new IJavaProject[list.size()]);
     }
+    
+    /**
+     * Returns the apk filename for the given project
+     * @param project The project.
+     * @param config An optional config name. Can be null.
+     */
+    private static String getFileName(IProject project, String config) {
+        if (config != null) {
+            return project.getName() + "-" + config + AndroidConstants.DOT_ANDROID_PACKAGE; //$NON-NLS-1$ 
+        }
+        
+        return project.getName() + AndroidConstants.DOT_ANDROID_PACKAGE;
+    }
 
     /**
      * Checks a {@link IFile} to make sure it should be packaged as standard resources.
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java
index aec703d..5d6793a 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java
@@ -192,11 +192,16 @@
                     IPath parentPath = path.removeLastSegments(1);
                     if (mOutputPath.equals(parentPath)) {
                         String resourceName = resource.getName();
+                        // check if classes.dex was removed
                         if (resourceName.equalsIgnoreCase(AndroidConstants.FN_CLASSES_DEX)) {
                             mConvertToDex = true;
                             mMakeFinalPackage = true;
                         } else if (resourceName.equalsIgnoreCase(
-                                AndroidConstants.FN_RESOURCES_AP_)) {
+                                AndroidConstants.FN_RESOURCES_AP_) ||
+                                AndroidConstants.PATTERN_RESOURCES_S_AP_.matcher(
+                                        resourceName).matches()) {
+                            // or if the default resources.ap_ or a configured version
+                            // (resources-###.ap_) was removed.
                             mPackageResources = true;
                             mMakeFinalPackage = true;
                         }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java
index cba8ad7..26d96d7 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java
@@ -17,7 +17,6 @@
 package com.android.ide.eclipse.adt.build;
 
 import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.sdk.LoadStatus;
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IStatus;
@@ -46,10 +45,6 @@
     
     private final static String MAIN_RUN = "run"; //$NON-NLS-1$
     
-    private static DexWrapper sWrapper;
-
-    private static LoadStatus sLoadStatus = LoadStatus.LOADING;
-
     private Method mRunMethod;
 
     private Constructor<?> mArgConstructor;
@@ -67,10 +62,8 @@
      * @param osFilepath the location of the dex.jar file.
      * @return an IStatus indicating the result of the load.
      */
-    public static synchronized IStatus loadDex(String osFilepath) {
+    public synchronized IStatus loadDex(String osFilepath) {
         try {
-            sWrapper = null;
-
             File f = new File(osFilepath);
             if (f.isFile() == false) {
                 return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, String.format(
@@ -86,45 +79,39 @@
             Class<?> consoleClass = loader.loadClass(DEX_CONSOLE);
             Class<?> argClass = loader.loadClass(DEX_ARGS);
             
-            sWrapper = new DexWrapper(mainClass, argClass, consoleClass);
-            
+            try {
+                // now get the fields/methods we need
+                mRunMethod = mainClass.getMethod(MAIN_RUN, argClass);
+                
+                mArgConstructor = argClass.getConstructor();
+                mArgOutName = argClass.getField("outName"); //$NON-NLS-1$
+                mArgJarOutput = argClass.getField("jarOutput"); //$NON-NLS-1$
+                mArgFileNames = argClass.getField("fileNames"); //$NON-NLS-1$
+                mArgVerbose = argClass.getField("verbose"); //$NON-NLS-1$
+                
+                mConsoleOut = consoleClass.getField("out"); //$NON-NLS-1$
+                mConsoleErr = consoleClass.getField("err"); //$NON-NLS-1$
+                
+            } catch (SecurityException e) {
+                return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_API, e);
+            } catch (NoSuchMethodException e) {
+                return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_Method, e);
+            } catch (NoSuchFieldException e) {
+                return createErrorStatus(Messages.DexWrapper_SecuryEx_Unable_To_Find_Field, e);
+            }
+
             return Status.OK_STATUS;
         } catch (MalformedURLException e) {
             // really this should not happen.
-            return createErrorStatus(String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e);
+            return createErrorStatus(
+                    String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e);
         } catch (ClassNotFoundException e) {
-            return createErrorStatus(String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e);
-        } catch (CoreException e) {
-            return e.getStatus();
-        } finally {
-            if (sWrapper == null) {
-                sLoadStatus = LoadStatus.FAILED;
-            } else {
-                sLoadStatus = LoadStatus.LOADED;
-            }
+            return createErrorStatus(
+                    String.format(Messages.DexWrapper_Failed_to_load_s, osFilepath), e);
         }
     }
     
     /**
-     * Unloads the loaded dex wrapper.
-     */
-    public static synchronized void unloadDex() {
-        sWrapper = null;
-        sLoadStatus = LoadStatus.LOADING;
-    }
-    
-    public static synchronized DexWrapper getWrapper() {
-        return sWrapper;
-    }
-    
-    /**
-     * Returns the {@link LoadStatus}.
-     */
-    public static synchronized LoadStatus getStatus() {
-        return sLoadStatus;
-    }
-
-    /**
      * Runs the dex command.
      * @param osOutFilePath the OS path to the outputfile (classes.dex
      * @param osFilenames list of input source files (.class and .jar files)
@@ -169,33 +156,6 @@
         }
     }
     
-    private DexWrapper(Class<?> mainClass, Class<?> argClass, Class<?> consoleClass)
-            throws CoreException {
-        try {
-            // now get the fields/methods we need
-            mRunMethod = mainClass.getMethod(MAIN_RUN, argClass);
-            
-            mArgConstructor = argClass.getConstructor();
-            mArgOutName = argClass.getField("outName"); //$NON-NLS-1$
-            mArgJarOutput = argClass.getField("jarOutput"); //$NON-NLS-1$
-            mArgFileNames = argClass.getField("fileNames"); //$NON-NLS-1$
-            mArgVerbose = argClass.getField("verbose"); //$NON-NLS-1$
-            
-            mConsoleOut = consoleClass.getField("out"); //$NON-NLS-1$
-            mConsoleErr = consoleClass.getField("err"); //$NON-NLS-1$
-            
-        } catch (SecurityException e) {
-            throw new CoreException(createErrorStatus(
-                    Messages.DexWrapper_SecuryEx_Unable_To_Find_API, e));
-        } catch (NoSuchMethodException e) {
-            throw new CoreException(createErrorStatus(
-                    Messages.DexWrapper_SecuryEx_Unable_To_Find_Method, e));
-        } catch (NoSuchFieldException e) {
-            throw new CoreException(createErrorStatus(
-                    Messages.DexWrapper_SecuryEx_Unable_To_Find_Field, e));
-        }
-    }
-    
     private static IStatus createErrorStatus(String message, Exception e) {
         AdtPlugin.log(e, message);
         AdtPlugin.printErrorToConsole(Messages.DexWrapper_Dex_Loader, message);
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java
index 2c15d55..958cac2 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java
@@ -235,6 +235,7 @@
         // get the project objects
         IProject project = getProject();
         IJavaProject javaProject = JavaCore.create(project);
+        IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project);
 
         // now we need to get the classpath list
         ArrayList<IPath> sourceList = BaseProjectHelper.getSourceClasspaths(javaProject);
@@ -407,8 +408,6 @@
                 String osResPath = resLocation.toOSString();
                 String osManifestPath = manifestLocation.toOSString();
 
-                IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project);
-
                 // remove the aapt markers
                 removeMarkersFromFile(manifest, AndroidConstants.MARKER_AAPT);
                 removeMarkersFromContainer(resFolder, AndroidConstants.MARKER_AAPT);
@@ -432,7 +431,7 @@
 
                 // launch aapt: create the command line
                 ArrayList<String> array = new ArrayList<String>();
-                array.add(AdtPlugin.getOsAbsoluteAapt());
+                array.add(projectTarget.getPath(IAndroidTarget.AAPT));
                 array.add("package"); //$NON-NLS-1$
                 array.add("-m"); //$NON-NLS-1$
                 if (AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE) {
@@ -541,7 +540,7 @@
         if (projectAidl != null && projectAidl.exists()) {
             folderAidlPath = projectAidl.getLocation().toOSString();
         }
-        boolean aidlStatus = handleAidl(sourceList, folderAidlPath, monitor);
+        boolean aidlStatus = handleAidl(projectTarget, sourceList, folderAidlPath, monitor);
 
         if (aidlStatus == false && mCompileResources == false) {
             AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
@@ -729,14 +728,15 @@
     /**
      * Compiles aidl files into java. This will also removes old java files
      * created from aidl files that are now gone.
+     * @param projectTarget Target of the project
      * @param sourceFolders the list of source folders, relative to the workspace.
      * @param folderAidlPath 
      * @param monitor the projess monitor
      * @returns true if it did something
      * @throws CoreException
      */
-    private boolean handleAidl(ArrayList<IPath> sourceFolders, String folderAidlPath,
-            IProgressMonitor monitor) throws CoreException {
+    private boolean handleAidl(IAndroidTarget projectTarget, ArrayList<IPath> sourceFolders,
+            String folderAidlPath, IProgressMonitor monitor) throws CoreException {
         if (mAidlToCompile.size() == 0 && mAidlToRemove.size() == 0) {
             return false;
         }
@@ -746,7 +746,7 @@
         String[] command = new String[4 + sourceFolders.size() + (folderAidlPath != null ? 1 : 0)];
         int index = 0;
         int aidlIndex;
-        command[index++] = AdtPlugin.getOsAbsoluteAidl();
+        command[index++] = projectTarget.getPath(IAndroidTarget.AIDL);
         command[aidlIndex = index++] = "-p"; //$NON-NLS-1$
         if (folderAidlPath != null) {
             command[index++] = "-p" + folderAidlPath; //$NON-NLS-1$
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java
index d4952b1..ac003df 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java
@@ -1519,6 +1519,7 @@
                     AdtPlugin.printErrorToConsole(launchInfo.mProject,
                             String.format(message1, launchInfo.mActivity));
                 }
+                launchInfo.mLaunch.stopLaunch();
             }
             for (DelayedLaunchInfo launchInfo : mWaitingForDebuggerApplications) {
                 if (launchInfo.mLaunchAction == LaunchConfigDelegate.ACTION_DO_NOTHING) {
@@ -1527,7 +1528,11 @@
                     AdtPlugin.printErrorToConsole(launchInfo.mProject,
                             String.format(message1, launchInfo.mActivity));
                 }
+                launchInfo.mLaunch.stopLaunch();
             }
+
+            mWaitingForReadyEmulatorList.clear();
+            mWaitingForDebuggerApplications.clear();
         }
     }
 
@@ -1573,24 +1578,31 @@
      * 
      * @see IDeviceChangeListener#deviceDisconnected(Device)
      */
+    @SuppressWarnings("unchecked")
     public void deviceDisconnected(Device device) {
         // any pending launch on this device must be canceled.
         String message = "%1$s disconnected! Cancelling '%2$s' launch!";
         synchronized (sListLock) {
-            for (DelayedLaunchInfo launchInfo : mWaitingForReadyEmulatorList) {
+            ArrayList<DelayedLaunchInfo> copyList =
+                (ArrayList<DelayedLaunchInfo>)mWaitingForReadyEmulatorList.clone();
+            for (DelayedLaunchInfo launchInfo : copyList) {
                 if (launchInfo.mDevice == device) {
                     AdtPlugin.printErrorToConsole(launchInfo.mProject,
                             String.format(message, device.getSerialNumber(), launchInfo.mActivity));
+                    launchInfo.mLaunch.stopLaunch();
+                    mWaitingForReadyEmulatorList.remove(launchInfo);
                 }
             }
-            for (DelayedLaunchInfo launchInfo : mWaitingForDebuggerApplications) {
+            copyList = (ArrayList<DelayedLaunchInfo>)mWaitingForDebuggerApplications.clone();
+            for (DelayedLaunchInfo launchInfo : copyList) {
                 if (launchInfo.mDevice == device) {
                     AdtPlugin.printErrorToConsole(launchInfo.mProject,
                             String.format(message, device.getSerialNumber(), launchInfo.mActivity));
+                    launchInfo.mLaunch.stopLaunch();
+                    mWaitingForDebuggerApplications.remove(launchInfo);
                 }
             }
         }
-
     }
 
     /**
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java
index d446e2b..a260350 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java
@@ -310,7 +310,7 @@
         top.setLayout(new GridLayout(1, true));
 
         mDeviceRadioButton = new Button(top, SWT.RADIO);
-        mDeviceRadioButton.setText("Choose an Android running device");
+        mDeviceRadioButton.setText("Choose a running Android device");
         mDeviceRadioButton.addSelectionListener(new SelectionAdapter() {
             @Override
             public void widgetSelected(SelectionEvent e) {
@@ -387,7 +387,7 @@
         });
         
         Button radio2 = new Button(top, SWT.RADIO);
-        radio2.setText("Launch a new Virtual Device");
+        radio2.setText("Launch a new Android Virtual Device");
 
         // offset the selector from the radio button
         offsetComp = new Composite(top, SWT.NONE);
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
index 30bf7ed..339dcd0 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
@@ -172,13 +172,7 @@
 
                 // if we are loaded and the target is non null, we create a valid ClassPathContainer
                 if (sdkIsLoaded && target != null) {
-                    String targetName = null;
-                    if (target.isPlatform()) {
-                        targetName = target.getName();
-                    } else {
-                        targetName = String.format("%1$s (%2$s)", target.getName(),
-                                target.getApiVersionName());
-                    }
+                    String targetName = target.getFullName();
 
                     return new AndroidClasspathContainer(
                             createClasspathEntries(iProject, target, targetName),
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java
index 60561ab..2309181 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java
@@ -16,6 +16,7 @@
 
 package com.android.ide.eclipse.adt.sdk;
 
+import com.android.ide.eclipse.adt.build.DexWrapper;
 import com.android.ide.eclipse.common.resources.IResourceRepository;
 import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider;
 import com.android.ide.eclipse.editors.layout.descriptors.LayoutDescriptors;
@@ -54,6 +55,8 @@
 
     private final IAndroidTarget mTarget;
 
+    private DexWrapper mDexWrapper;
+
     /**
      * mAttributeValues is a map { key => list [ values ] }.
      * The key for the map is "(element-xml-name,attribute-namespace:attribute-xml-local-name)".
@@ -64,27 +67,34 @@
      * This is used for attributes that do not have a unique name, but still need to be populated
      * with values in the UI. Uniquely named attributes have their values in {@link #mEnumValueMap}.
      */
-    private final Hashtable<String, String[]> mAttributeValues = new Hashtable<String, String[]>();
+    private Hashtable<String, String[]> mAttributeValues = new Hashtable<String, String[]>();
     
     private IResourceRepository mSystemResourceRepository;
 
-    private final AndroidManifestDescriptors mManifestDescriptors;
-    private final LayoutDescriptors mLayoutDescriptors;
-    private final MenuDescriptors mMenuDescriptors;
-    private final XmlDescriptors mXmlDescriptors;
+    private AndroidManifestDescriptors mManifestDescriptors;
+    private LayoutDescriptors mLayoutDescriptors;
+    private MenuDescriptors mMenuDescriptors;
+    private XmlDescriptors mXmlDescriptors;
 
-    private final Map<String, Map<String, Integer>> mEnumValueMap;
+    private Map<String, Map<String, Integer>> mEnumValueMap;
 
-    private final ProjectResources mFrameworkResources;
-    private final LayoutBridge mLayoutBridge;
+    private ProjectResources mFrameworkResources;
+    private LayoutBridge mLayoutBridge;
 
     private boolean mLayoutBridgeInit = false;
 
+    AndroidTargetData(IAndroidTarget androidTarget) {
+        mTarget = androidTarget;
+    }
+    
+    void setDexWrapper(DexWrapper wrapper) {
+        mDexWrapper = wrapper;
+    }
+    
     /**
      * Creates an AndroidTargetData object.
      */
-    AndroidTargetData(IAndroidTarget androidTarget,
-            IResourceRepository systemResourceRepository,
+    void setExtraData(IResourceRepository systemResourceRepository,
             AndroidManifestDescriptors manifestDescriptors,
             LayoutDescriptors layoutDescriptors,
             MenuDescriptors menuDescriptors,
@@ -98,7 +108,6 @@
             ProjectResources resources,
             LayoutBridge layoutBridge) {
         
-        mTarget = androidTarget;
         mSystemResourceRepository = systemResourceRepository;
         mManifestDescriptors = manifestDescriptors;
         mLayoutDescriptors = layoutDescriptors;
@@ -113,6 +122,10 @@
                 serviceIntentActionValues, intentCategoryValues);
     }
     
+    public DexWrapper getDexWrapper() {
+        return mDexWrapper;
+    }
+    
     public IResourceRepository getSystemResources() {
         return mSystemResourceRepository;
     }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java
index dfe876f..aab660d 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java
@@ -17,6 +17,7 @@
 package com.android.ide.eclipse.adt.sdk;
 
 import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.build.DexWrapper;
 import com.android.ide.eclipse.adt.sdk.AndroidTargetData.LayoutBridge;
 import com.android.ide.eclipse.common.AndroidConstants;
 import com.android.ide.eclipse.common.resources.AttrsXmlParser;
@@ -91,8 +92,25 @@
         try {
             SubMonitor progress = SubMonitor.convert(monitor,
                     String.format("Parsing SDK %1$s", mAndroidTarget.getName()),
-                    120);
+                    200);
             
+            AndroidTargetData targetData = new AndroidTargetData(mAndroidTarget);
+
+            // load DX.
+            DexWrapper dexWrapper = new DexWrapper();
+            IStatus res = dexWrapper.loadDex(mAndroidTarget.getPath(IAndroidTarget.DX_JAR));
+            if (res != Status.OK_STATUS) {
+                return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID,
+                        String.format("dx.jar loading failed for target '%1$s'",
+                                mAndroidTarget.getFullName()));
+            }
+            
+            // we have loaded dx.
+            targetData.setDexWrapper(dexWrapper);
+            
+            // parse the rest of the data.
+            progress.setWorkRemaining(120);
+
             AndroidJarLoader classLoader =
                 new AndroidJarLoader(mAndroidTarget.getPath(IAndroidTarget.ANDROID_JAR));
             
@@ -229,8 +247,7 @@
             progress.worked(10);
             
             // and finally create the PlatformData with all that we loaded.
-            AndroidTargetData targetData = new AndroidTargetData(mAndroidTarget,
-                    frameworkRepository,
+            targetData.setExtraData(frameworkRepository,
                     manifestDescriptors,
                     layoutDescriptors,
                     menuDescriptors,
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java
index 01b722f..5bfa8a2 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java
@@ -18,6 +18,8 @@
 
 import com.android.ide.eclipse.adt.AdtPlugin;
 import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerInitializer;
+import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor;
+import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener;
 import com.android.prefs.AndroidLocation.AndroidLocationException;
 import com.android.sdklib.IAndroidTarget;
 import com.android.sdklib.ISdkLog;
@@ -28,6 +30,8 @@
 import com.android.sdklib.project.ProjectProperties.PropertyType;
 
 import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaCore;
@@ -38,6 +42,9 @@
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
 
 /**
  * Central point to load, manipulate and deal with the Android SDK. Only one SDK can be used
@@ -48,18 +55,19 @@
  * 
  * To get the list of platforms or add-ons present in the SDK, call {@link #getTargets()}.
  */
-public class Sdk {
+public class Sdk implements IProjectListener {
     private static Sdk sCurrentSdk = null;
 
     private final SdkManager mManager;
     private final AvdManager mAvdManager;
 
-    private final HashMap<IProject, IAndroidTarget> mProjectMap =
+    private final HashMap<IProject, IAndroidTarget> mProjectTargetMap =
             new HashMap<IProject, IAndroidTarget>();
-    private final HashMap<IAndroidTarget, AndroidTargetData> mTargetMap = 
+    private final HashMap<IAndroidTarget, AndroidTargetData> mTargetDataMap = 
             new HashMap<IAndroidTarget, AndroidTargetData>();
+    private final HashMap<IProject, Map<String, String>> mProjectConfigMap =
+        new HashMap<IProject, Map<String, String>>();
     private final String mDocBaseUrl;
-
     
     /**
      * Loads an SDK and returns an {@link Sdk} object if success.
@@ -67,7 +75,7 @@
      */
     public static Sdk loadSdk(String sdkLocation) {
         if (sCurrentSdk != null) {
-            // manual unload?
+            sCurrentSdk.dispose();
             sCurrentSdk = null;
         }
 
@@ -159,16 +167,16 @@
      * Associates an {@link IProject} and an {@link IAndroidTarget}.
      */
     public void setProject(IProject project, IAndroidTarget target) {
-        synchronized (mProjectMap) {
+        synchronized (mProjectTargetMap) {
             // look for the current target of the project
-            IAndroidTarget previousTarget = mProjectMap.get(project);
+            IAndroidTarget previousTarget = mProjectTargetMap.get(project);
             
             if (target != previousTarget) {
                 // save the target hash string in the project persistent property
                 setProjectTargetHashString(project, target.hashString());
                 
                 // put it in a local map for easy access.
-                mProjectMap.put(project, target);
+                mProjectTargetMap.put(project, target);
 
                 // recompile the project if needed.
                 IJavaProject javaProject = JavaCore.create(project);
@@ -182,11 +190,11 @@
      * Returns the {@link IAndroidTarget} object associated with the given {@link IProject}.
      */
     public IAndroidTarget getTarget(IProject project) {
-        synchronized (mProjectMap) {
-            IAndroidTarget target = mProjectMap.get(project);
+        synchronized (mProjectTargetMap) {
+            IAndroidTarget target = mProjectTargetMap.get(project);
             if (target == null) {
                 // get the value from the project persistent property.
-                String targetHashString = getProjectTargetHashString(project);
+                String targetHashString = loadProjectProperties(project, this);
 
                 if (targetHashString != null) {
                     target = mManager.getTargetFromHashString(targetHashString);
@@ -197,14 +205,19 @@
         }
     }
     
+
     /**
-     * Returns the hash string uniquely identifying the target of a project. This methods reads
-     * the string from the project persistent preferences/properties.
-     * <p/>The string is equivalent to the return of {@link IAndroidTarget#hashString()}.
+     * Parses the project properties and returns the hash string uniquely identifying the
+     * target of the given project.
+     * <p/>
+     * This methods reads the content of the <code>default.properties</code> file present in
+     * the root folder of the project.
+     * <p/>The returned string is equivalent to the return of {@link IAndroidTarget#hashString()}.
      * @param project The project for which to return the target hash string.
+     * @param storeConfigs Whether the read configuration should be stored in the map. 
      * @return the hash string or null if the project does not have a target set.
      */
-    public static String getProjectTargetHashString(IProject project) {
+    private static String loadProjectProperties(IProject project, Sdk storeConfigs) {
         // load the default.properties from the project folder.
         ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(),
                 PropertyType.DEFAULT);
@@ -214,11 +227,46 @@
             return null;
         }
         
+        if (storeConfigs != null) {
+            // get the list of configs.
+            String configList = properties.getProperty(ProjectProperties.PROPERTY_CONFIGS);
+            
+            // this is a comma separated list
+            String[] configs = configList.split(","); //$NON-NLS-1$
+            
+            // read the value of each config and store it in a map
+            HashMap<String, String> configMap = new HashMap<String, String>();
+            
+            for (String config : configs) {
+                String configValue = properties.getProperty(config);
+                if (configValue != null) {
+                    configMap.put(config, configValue);
+                }
+            }
+            
+            if (configMap.size() > 0) {
+                storeConfigs.mProjectConfigMap.put(project, configMap);
+            }
+        }
+        
         return properties.getProperty(ProjectProperties.PROPERTY_TARGET);
     }
+    
+    /**
+     * Returns the hash string uniquely identifying the target of a project.
+     * <p/>
+     * This methods reads the content of the <code>default.properties</code> file present in
+     * the root folder of the project.
+     * <p/>The string is equivalent to the return of {@link IAndroidTarget#hashString()}.
+     * @param project The project for which to return the target hash string.
+     * @return the hash string or null if the project does not have a target set.
+     */
+    public static String getProjectTargetHashString(IProject project) {
+        return loadProjectProperties(project, null /*storeConfigs*/);
+    }
 
     /**
-     * Sets a target hash string in a project's persistent preferences/property storage.
+     * Sets a target hash string in given project's <code>default.properties</code> file.
      * @param project The project in which to save the hash string.
      * @param targetHashString The target hash string to save. This must be the result from
      * {@link IAndroidTarget#hashString()}.
@@ -249,12 +297,82 @@
      * Return the {@link AndroidTargetData} for a given {@link IAndroidTarget}.
      */
     public AndroidTargetData getTargetData(IAndroidTarget target) {
-        synchronized (mTargetMap) {
-            return mTargetMap.get(target);
+        synchronized (mTargetDataMap) {
+            return mTargetDataMap.get(target);
         }
     }
     
     /**
+     * Returns the configuration map for a given project.
+     * <p/>The Map key are name to be used in the apk filename, while the values are comma separated
+     * config values. The config value can be passed directly to aapt through the -c option.
+     */
+    public Map<String, String> getProjectConfigs(IProject project) {
+        return mProjectConfigMap.get(project);
+    }
+    
+    public void setProjectConfigs(IProject project, Map<String, String> configMap)
+            throws CoreException {
+        // first set the new map
+        mProjectConfigMap.put(project, configMap);
+        
+        // Now we write this in default.properties.
+        // Because we don't want to erase other properties from default.properties, we first load
+        // them
+        ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(),
+                PropertyType.DEFAULT);
+        if (properties == null) {
+            // doesn't exist yet? we create it.
+            properties = ProjectProperties.create(project.getLocation().toOSString(),
+                    PropertyType.DEFAULT);
+        }
+        
+        // load the current configs, in order to remove the value properties for each of them
+        // in case a config was removed.
+        
+        // get the list of configs.
+        String configList = properties.getProperty(ProjectProperties.PROPERTY_CONFIGS);
+        
+        // this is a comma separated list
+        String[] configs = configList.split(","); //$NON-NLS-1$
+        
+        boolean hasRemovedConfig = false;
+        
+        for (String config : configs) {
+            if (configMap.containsKey(config) == false) {
+                hasRemovedConfig = true;
+                properties.removeProperty(config);
+            }
+        }
+        
+        // now add the properties.
+        Set<Entry<String, String>> entrySet = configMap.entrySet();
+        StringBuilder sb = new StringBuilder();
+        for (Entry<String, String> entry : entrySet) {
+            if (sb.length() > 0) {
+                sb.append(",");
+            }
+            sb.append(entry.getKey());
+            properties.setProperty(entry.getKey(), entry.getValue());
+        }
+        properties.setProperty(ProjectProperties.PROPERTY_CONFIGS, sb.toString());
+
+        // and rewrite the file.
+        try {
+            properties.save();
+        } catch (IOException e) {
+            AdtPlugin.log(e, "Failed to save default.properties for project '%s'",
+                    project.getName());
+        }
+
+        // we're done, force a rebuild. If there was removed config, we clean instead of build
+        // (to remove the obsolete ap_ and apk file from removed configs). 
+        project.build(hasRemovedConfig ?
+                IncrementalProjectBuilder.CLEAN_BUILD : IncrementalProjectBuilder.FULL_BUILD,
+                null);
+    }
+
+    /**
      * Returns the {@link AvdManager}. If the AvdManager failed to parse the AVD folder, this could
      * be <code>null</code>.
      */
@@ -266,14 +384,25 @@
         mManager = manager;
         mAvdManager = avdManager;
         
+        // listen to projects closing
+        ResourceMonitor monitor = ResourceMonitor.getMonitor();
+        monitor.addProjectListener(this);
+        
         // pre-compute some paths
         mDocBaseUrl = getDocumentationBaseUrl(mManager.getLocation() +
                 SdkConstants.OS_SDK_DOCS_FOLDER);
     }
+
+    /**
+     *  Cleans and unloads the SDK.
+     */
+    private void dispose() {
+        ResourceMonitor.getMonitor().removeProjectListener(this);
+    }
     
     void setTargetData(IAndroidTarget target, AndroidTargetData data) {
-        synchronized (mTargetMap) {
-            mTargetMap.put(target, data);
+        synchronized (mTargetDataMap) {
+            mTargetDataMap.put(target, data);
         }
     }
     
@@ -314,6 +443,24 @@
         return null;
     }
 
+    public void projectClosed(IProject project) {
+        mProjectTargetMap.remove(project);
+        mProjectConfigMap.remove(project);
+    }
+
+    public void projectDeleted(IProject project) {
+        projectClosed(project);
+    }
+
+    public void projectOpened(IProject project) {
+        // ignore this. The project will be added to the map the first time the target needs
+        // to be resolved.
+    }
+
+    public void projectOpenedWithWorkspace(IProject project) {
+        // ignore this. The project will be added to the map the first time the target needs
+        // to be resolved.
+    }
 }
 
 
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java
index 65817c3..b1c57a6 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java
@@ -19,6 +19,7 @@
 import com.android.sdklib.SdkConstants;
 
 import java.io.File;
+import java.util.regex.Pattern;
 
 /**
  * Constant definition class.<br>
@@ -49,17 +50,6 @@
     /** Nature of android projects */
     public final static String NATURE = "com.android.ide.eclipse.adt.AndroidNature"; //$NON-NLS-1$
 
-    public final static int PLATFORM_UNKNOWN = 0;
-    public final static int PLATFORM_LINUX = 1;
-    public final static int PLATFORM_WINDOWS = 2;
-    public final static int PLATFORM_DARWIN = 3;
-
-    /**
-     * Returns current platform, one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
-     * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
-     */
-    public final static int CURRENT_PLATFORM = currentPlatform();
-
     /** Separator for workspace path, i.e. "/". */
     public final static String WS_SEP = "/"; //$NON-NLS-1$
     /** Separator character for workspace path, i.e. '/'. */
@@ -99,8 +89,6 @@
     public static final String FN_ANDROID_MANIFEST = "AndroidManifest.xml"; //$NON-NLS-1$
     public static final String FN_PROJECT_AIDL = "project.aidl"; //$NON-NLS-1$
 
-    /** dex.jar file */
-    public static final String FN_DX_JAR = "dx.jar"; //$NON-NLS-1$
     /** Name of the android sources directory */
     public static final String FD_ANDROID_SOURCES = "sources"; //$NON-NLS-1$
 
@@ -114,20 +102,21 @@
     public final static String FN_CLASSES_DEX = "classes.dex"; //$NON-NLS-1$
     /** Temporary packaged resources file name, i.e. "resources.ap_" */
     public final static String FN_RESOURCES_AP_ = "resources.ap_"; //$NON-NLS-1$
+    /** 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);
 
-    public final static String FN_ADB = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+    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_AAPT = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
-            "aapt.exe" : "aapt"; //$NON-NLS-1$ //$NON-NLS-2$
-
-    public final static String FN_AIDL = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
-            "aidl.exe" : "aidl"; //$NON-NLS-1$ //$NON-NLS-2$
-
-    public final static String FN_EMULATOR = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+    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_TRACEVIEW = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+    public final static String FN_TRACEVIEW =
+        (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ?
             "traceview.exe" : "traceview"; //$NON-NLS-1$ //$NON-NLS-2$
 
     /** Absolute path of the workspace root, i.e. "/" */
@@ -147,11 +136,6 @@
      *  FIXME: remove once the NPW is fixed. */
     public final static String OS_SDK_SAMPLES_FOLDER = SdkConstants.FD_SAMPLES + File.separator;
 
-    /** Path of the dx.jar file relative to the sdk folder. */
-    public final static String OS_SDK_LIBS_DX_JAR =
-        SdkConstants.OS_SDK_TOOLS_LIB_FOLDER + FN_DX_JAR;
-
-    /** Regexp for single dot */
     public final static String RE_DOT = "\\."; //$NON-NLS-1$
     /** Regexp for java extension, i.e. "\.java$" */
     public final static String RE_JAVA_EXT = "\\.java$"; //$NON-NLS-1$
@@ -229,22 +213,4 @@
     /** 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$
     
-    /**
-     * Returns current platform
-     * 
-     * @return one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
-     * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
-     */
-    private static int currentPlatform() {
-        String os = System.getProperty("os.name");          //$NON-NLS-1$
-        if (os.startsWith("Mac OS")) {                      //$NON-NLS-1$
-            return PLATFORM_DARWIN;
-        } else if (os.startsWith("Windows")) {              //$NON-NLS-1$
-            return PLATFORM_WINDOWS;
-        } else if (os.startsWith("Linux")) {                //$NON-NLS-1$
-            return PLATFORM_LINUX;
-        }
-
-        return PLATFORM_UNKNOWN;
-    }
 }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/IconFactory.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/IconFactory.java
index e3de3af..2c24772 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/IconFactory.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/IconFactory.java
@@ -18,7 +18,7 @@
 package com.android.ide.eclipse.editors;
 
 import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.common.AndroidConstants;
+import com.android.sdklib.SdkConstants;
 
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.swt.SWT;
@@ -231,7 +231,7 @@
             // Text measurement varies so slightly depending on the platform
             int ofx = 0;
             int ofy = 0;
-            if (AndroidConstants.CURRENT_PLATFORM == AndroidConstants.PLATFORM_WINDOWS) {
+            if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) {
                 ofx = +1;
                 ofy = -1;
             }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java
index 845db32..d1d8891 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java
@@ -160,6 +160,13 @@
         // set up the resource manager to send us resource change notification
         AdtPlugin.getDefault().getResourceMonitor().addResourceEventListener(this);
     }
+    
+    @Override
+    public void dispose() {
+        AdtPlugin.getDefault().getResourceMonitor().removeResourceEventListener(this);
+
+        super.dispose();
+    }
 
     @Override
     public void setFocus() {
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceMonitor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceMonitor.java
index dc0f505..59a72fb 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceMonitor.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceMonitor.java
@@ -189,20 +189,15 @@
                     // the project is opening or closing.
                     IProject project = (IProject)r;
                     
-                    // the OPEN flag represent a toggle in the open/close state of the
-                    // project, but this is sent before the project actually toggles
-                    // its state.
-                    // This means that if the project is closing, isOpen() will return true.
-                    boolean isClosing = project.isOpen();
-                    if (isClosing) {
+                    if (project.isOpen()) {
                         // notify the listeners.
                         for (IProjectListener pl : mProjectListeners) {
-                            pl.projectClosed(project);
+                            pl.projectOpened(project);
                         }
                     } else {
                         // notify the listeners.
                         for (IProjectListener pl : mProjectListeners) {
-                            pl.projectOpened(project);
+                            pl.projectClosed(project);
                         }
                     }
                 }
@@ -287,6 +282,20 @@
     }
 
     /**
+     * Removes an existing folder listener.
+     * @param listener the listener to remove.
+     */
+    public synchronized void removeFolderListener(IFolderListener listener) {
+        for (int i = 0 ; i < mFolderListeners.size() ; i++) {
+            FolderListenerBundle bundle = mFolderListeners.get(i);
+            if (bundle.listener == listener) {
+                mFolderListeners.remove(i);
+                return;
+            }
+        }
+    }
+
+    /**
      * Adds a project listener.
      * @param listener The listener to receive the events.
      */
@@ -305,11 +314,31 @@
         }
     }
     
+    /**
+     * Removes an existing project listener.
+     * @param listener the listener to remove.
+     */
+    public synchronized void removeProjectListener(IProjectListener listener) {
+        mProjectListeners.remove(listener);
+    }
+    
+    /**
+     * Adds a resource event listener.
+     * @param listener The listener to receive the events.
+     */
     public synchronized void addResourceEventListener(IResourceEventListener listener) {
         mEventListeners.add(listener);
     }
 
     /**
+     * Removes an existing Resource Event listener.
+     * @param listener the listener to remove.
+     */
+    public synchronized void removeResourceEventListener(IResourceEventListener listener) {
+        mEventListeners.remove(listener);
+    }
+
+    /**
      * Processes the workspace resource change events.
      */
     public void resourceChanged(IResourceChangeEvent event) {
diff --git a/tools/eclipse/scripts/collect_sources_for_sdk.sh b/tools/eclipse/scripts/collect_sources_for_sdk.sh
new file mode 100644
index 0000000..4637595
--- /dev/null
+++ b/tools/eclipse/scripts/collect_sources_for_sdk.sh
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+function usage() {
+    cat <<EOF
+ Description:
+   This script collects all framework Java sources from the current android
+   source code and places them in a source folder suitable for the eclipse ADT
+   plugin.
+
+ Usage:
+   $0 [-n] <android-git-repo root> <sdk/platforms/xyz/sources>
+ 
+ The source and destination directories must already exist.
+ Use -n for a dry-run.
+
+EOF
+}
+
+DRY=""
+if [ "-n" == "$1" ]; then
+    DRY="echo"
+    shift
+fi
+
+SRC="$1"
+DST="$2"
+
+if [ -z "$SRC" ] || [ -z "$DST" ] || [ ! -d "$SRC" ] || [ ! -d "$DST" ]; then
+    usage
+    exit 1
+fi
+
+function process() {
+    echo "Examine" $1
+}
+
+N=0
+E=0
+for i in `find -L "${SRC}/frameworks" -name "*.java"`; do
+    if [ -f "$i" ]; then
+        # look for ^package (android.view.blah);$
+        PACKAGE=`sed -n '/^package [^ ;]\+; */{s/[^ ]* *\([^ ;]*\).*/\1/p;q}' "$i"`
+        if [ -n "$PACKAGE" ]; then
+            PACKAGE=${PACKAGE//./\/}    # e.g. android.view => android/view
+            JAVA=`basename "$i"`        # e.g. View.java
+            [ -z $DRY ] && [ ! -d "$DST/$PACKAGE" ] && mkdir -p -v "$DST/$PACKAGE"
+            $DRY cp -v "$i" "$DST/$PACKAGE/$JAVA"
+            N=$((N+1))
+        else
+            echo "Warning: $i does not have a Java package."
+            E=$((E+1))
+        fi
+    fi
+done
+
+echo "$N java files copied"
+[ $E -gt 0 ] && echo "$E warnings"
+
diff --git a/tools/scripts/android_rules.xml b/tools/scripts/android_rules.xml
index 8e4f7a2..4698671 100644
--- a/tools/scripts/android_rules.xml
+++ b/tools/scripts/android_rules.xml
@@ -1,6 +1,18 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project name="android_rules" default="debug">
 
+    <!--
+        This rules file is meant to be imported by the custom Ant task:
+            com.android.ant.AndroidInitTask
+
+        The following properties are put in place by the importing task:
+            android-jar, android-aidl, aapt, aidl, and dx
+
+        Additionnaly, the task sets up the following classpath reference:
+            android.target.classpath
+        This is used by the compiler task as the boot classpath.
+    -->
+
     <property name="android-tools" value="${sdk-location}/tools" />
 
     <!-- Input directories -->
@@ -55,13 +67,10 @@
     <condition property="exe" value="exe" else=""><os family="windows"/></condition>
     <condition property="bat" value="bat" else=""><os family="windows"/></condition>
 
-    <property name="aapt" value="${android-tools}/aapt${exe}"/>
-    <property name="aidl" value="${android-tools}/aidl${exe}"/>
     <property name="adb" value="${android-tools}/adb${exe}"/>
-    <property name="dx" value="${android-tools}/dx${bat}"/>
     <property name="apk-builder" value="${android-tools}/apkbuilder${bat}"/>
 
-	<!-- rules -->
+    <!-- rules -->
 
     <!-- Create the output directories if they don't exist yet. -->
     <target name="dirs">
diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
index 3370e76..1a15fce 100644
--- a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
+++ b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
@@ -356,6 +356,7 @@
      */
     private void displaySkinList(IAndroidTarget target, String message) {
         String[] skins = target.getSkins();
+        String defaultSkin = target.getDefaultSkin();
         mSdkLog.printf(message);
         if (skins != null) {
             boolean first = true;
@@ -366,6 +367,10 @@
                     first = false;
                 }
                 mSdkLog.printf(skin);
+                
+                if (skin.equals(defaultSkin)) {
+                    mSdkLog.printf(" (default)");
+                }
             }
             mSdkLog.printf("\n");
         } else {
@@ -385,7 +390,7 @@
             int index = 1;
             for (AvdInfo info : avdManager.getAvds()) {
                 mSdkLog.printf("[%d] %s\n", index, info.getName());
-                mSdkLog.printf("    Path: %s\n", info.getPath());
+                mSdkLog.printf("      Path: %s\n", info.getPath());
 
                 // get the target of the AVD
                 IAndroidTarget target = info.getTarget();
@@ -395,9 +400,23 @@
                 } else {
                     mSdkLog.printf("    Target: %s (%s)\n", target.getName(), target
                             .getVendor());
-                    mSdkLog.printf("    Based on Android %s (API level %d)\n", target
+                    mSdkLog.printf("            Based on Android %s (API level %d)\n", target
                             .getApiVersionName(), target.getApiVersionNumber());
                 }
+                
+                // display some extra values.
+                Map<String, String> properties = info.getProperties();
+                String skin = properties.get(AvdManager.AVD_INI_SKIN_NAME);
+                if (skin != null) {
+                    mSdkLog.printf("      Skin: %s\n", skin);
+                }
+                String sdcard = properties.get(AvdManager.AVD_INI_SDCARD_SIZE);
+                if (sdcard == null) {
+                    sdcard = properties.get(AvdManager.AVD_INI_SDCARD_PATH);
+                }
+                if (sdcard != null) {
+                    mSdkLog.printf("    Sdcard: %s\n", sdcard);
+                }
 
                 index++;
             }
@@ -489,7 +508,7 @@
                     return;
                 }
             }
-
+            
             AvdInfo newAvdInfo = avdManager.createAvd(avdFolder,
                     avdName,
                     target,
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
index ada61f7..0a59107 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
@@ -69,6 +69,7 @@
     private final String mVendor;
     private final String mDescription;
     private String[] mSkins;
+    private String mDefaultSkin;
     private IOptionalLibrary[] mLibraries;
 
     /**
@@ -141,6 +142,10 @@
         return false;
     }
     
+    public IAndroidTarget getParent() {
+        return mBasePlatform;
+    }
+    
     public String getPath(int pathId) {
         switch (pathId) {
             case IMAGES:
@@ -157,6 +162,10 @@
     public String[] getSkins() {
         return mSkins;
     }
+    
+    public String getDefaultSkin() {
+        return mDefaultSkin;
+    }
 
     public IOptionalLibrary[] getOptionalLibraries() {
         return mLibraries;
@@ -236,7 +245,9 @@
     // ---- local methods.
 
 
-    public void setSkins(String[] skins) {
+    public void setSkins(String[] skins, String defaultSkin) {
+        mDefaultSkin = defaultSkin;
+
         // we mix the add-on and base platform skins
         HashSet<String> skinSet = new HashSet<String>();
         skinSet.addAll(Arrays.asList(skins));
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 acf1187..fa462bd 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
@@ -60,6 +60,14 @@
     public static int SOURCES             = 18;
     /** OS Path to the target specific docs */
     public static int DOCS                = 19;
+    /** OS Path to the target's version of the aapt tool. */
+    public static int AAPT                = 20;
+    /** OS Path to the target's version of the aidl tool. */
+    public static int AIDL                = 21;
+    /** OS Path to the target's version of the dx too. */
+    public static int DX                  = 22;
+    /** OS Path to the target's version of the dx.jar file. */
+    public static int DX_JAR              = 23;
     
     public interface IOptionalLibrary {
         String getName();
@@ -109,6 +117,12 @@
     boolean isPlatform();
     
     /**
+     * Returns the parent target. This is likely to only be non <code>null</code> if
+     * {@link #isPlatform()} returns <code>false</code>
+     */
+    IAndroidTarget getParent();
+    
+    /**
      * Returns the path of a platform component.
      * @param pathId the id representing the path to return. Any of the constants defined in the
      * {@link IAndroidTarget} interface can be used.
@@ -121,6 +135,11 @@
     String[] getSkins();
     
     /**
+     * Returns the default skin for this target.
+     */
+    String getDefaultSkin();
+    
+    /**
      * Returns the available optional libraries for this target.
      * @return an array of optional libraries or <code>null</code> if there is none.
      */
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
index 59fa81c..a3da70e 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
@@ -75,8 +75,13 @@
                 SdkConstants.FN_INTENT_ACTIONS_SERVICE);
         mPaths.put(CATEGORIES, mLocation + SdkConstants.OS_PLATFORM_DATA_FOLDER +
                 SdkConstants.FN_INTENT_CATEGORIES);
+        mPaths.put(AAPT, mLocation + SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_AAPT);
+        mPaths.put(AIDL, mLocation + SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_AIDL);
+        mPaths.put(DX, mLocation + SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_DX);
+        mPaths.put(DX_JAR, mLocation + SdkConstants.OS_SDK_TOOLS_LIB_FOLDER +
+                SdkConstants.FN_DX_JAR);
     }
-
+    
     public String getLocation() {
         return mLocation;
     }
@@ -123,6 +128,10 @@
         return true;
     }
     
+    public IAndroidTarget getParent() {
+        return null;
+    }
+    
     public String getPath(int pathId) {
         return mPaths.get(pathId);
     }
@@ -130,6 +139,11 @@
     public String[] getSkins() {
         return mSkins;
     }
+    
+    public String getDefaultSkin() {
+        // at this time, this is the default skin for all the platform.
+        return "HVGA";
+    }
 
     /*
      * Always returns null, as a standard platforms have no optional libraries.
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 b79dedb..87f9b56 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
@@ -30,7 +30,18 @@
  *
  */
 public final class SdkConstants {
+    public final static int PLATFORM_UNKNOWN = 0;
+    public final static int PLATFORM_LINUX = 1;
+    public final static int PLATFORM_WINDOWS = 2;
+    public final static int PLATFORM_DARWIN = 3;
 
+    /**
+     * Returns current platform, one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
+     * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
+     */
+    public final static int CURRENT_PLATFORM = currentPlatform();
+
+    
     /** An SDK Project's AndroidManifest.xml file */
     public static final String FN_ANDROID_MANIFEST_XML= "AndroidManifest.xml";
     /** An SDK Project's build.xml file */
@@ -69,6 +80,21 @@
     /** Skin layout file */
     public final static String FN_SKIN_LAYOUT = "layout";//$NON-NLS-1$
 
+    /** dex.jar file */
+    public static final String FN_DX_JAR = "dx.jar"; //$NON-NLS-1$
+
+    /** dx executable */
+    public final static String FN_DX = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+            "dx.bat" : "dx"; //$NON-NLS-1$ //$NON-NLS-2$
+
+    /** aapt executable */
+    public final static String FN_AAPT = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+            "aapt.exe" : "aapt"; //$NON-NLS-1$ //$NON-NLS-2$
+
+    /** aidl executable */
+    public final static String FN_AIDL = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
+            "aidl.exe" : "aidl"; //$NON-NLS-1$ //$NON-NLS-2$
+
     /* Folder Names for Android Projects . */
 
     /** Resources folder name, i.e. "res". */
@@ -142,11 +168,11 @@
      *  This is an OS path, ending with a separator. */
     public final static String OS_SDK_DOCS_FOLDER = FD_DOCS + File.separator;
 
-    /** Path of the tools directory relative to the sdk folder.
+    /** Path of the tools directory relative to the sdk folder, or to a platform folder.
      *  This is an OS path, ending with a separator. */
     public final static String OS_SDK_TOOLS_FOLDER = FD_TOOLS + File.separator;
 
-    /** Path of the lib directory relative to the sdk folder.
+    /** Path of the lib directory relative to the sdk folder, or to a platform folder.
      *  This is an OS path, ending with a separator. */
     public final static String OS_SDK_TOOLS_LIB_FOLDER =
             OS_SDK_TOOLS_FOLDER + FD_LIB + File.separator;
@@ -233,4 +259,22 @@
         return cmd;
     }
 
+    /**
+     * Returns current platform
+     * 
+     * @return one of {@link #PLATFORM_WINDOWS}, {@link #PLATFORM_DARWIN},
+     * {@link #PLATFORM_LINUX} or {@link #PLATFORM_UNKNOWN}.
+     */
+    private static int currentPlatform() {
+        String os = System.getProperty("os.name");          //$NON-NLS-1$
+        if (os.startsWith("Mac OS")) {                      //$NON-NLS-1$
+            return PLATFORM_DARWIN;
+        } else if (os.startsWith("Windows")) {              //$NON-NLS-1$
+            return PLATFORM_WINDOWS;
+        } else if (os.startsWith("Linux")) {                //$NON-NLS-1$
+            return PLATFORM_LINUX;
+        }
+
+        return PLATFORM_UNKNOWN;
+    }
 }
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 f6fb622..28227c6 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
@@ -44,6 +44,7 @@
     private final static String ADDON_API = "api";
     private final static String ADDON_DESCRIPTION = "description";
     private final static String ADDON_LIBRARIES = "libraries";
+    private final static String ADDON_DEFAULT_SKIN = "skin";
     
     private final static Pattern PATTERN_PROP = Pattern.compile(
             "^([a-zA-Z0-9._-]+)\\s*=\\s*(.*)\\s*$");
@@ -51,6 +52,17 @@
     private final static Pattern PATTERN_LIB_DATA = Pattern.compile(
             "^([a-zA-Z0-9._-]+\\.jar);(.*)$", Pattern.CASE_INSENSITIVE);
     
+    /** List of items in the platform to check when parsing it. These paths are relative to the
+     * platform root folder. */
+    private final static String[] sPlatformContentList = new String[] {
+        SdkConstants.FN_FRAMEWORK_LIBRARY,
+        SdkConstants.FN_FRAMEWORK_AIDL,
+        SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_AAPT,
+        SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_AIDL,
+        SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_DX,
+        SdkConstants.OS_SDK_TOOLS_LIB_FOLDER + SdkConstants.FN_DX_JAR,
+    };
+
     /** the location of the SDK */
     private final String mSdkLocation;
     private IAndroidTarget[] mTargets;
@@ -176,6 +188,10 @@
                     String apiNumber = map.get(PROP_VERSION_SDK);
                     String apiName = map.get(PROP_VERSION_RELEASE);
                     if (apiNumber != null && apiName != null) {
+                        // api number and name looks valid, perform a few more checks
+                        if (checkPlatformContent(platform, log) == false) {
+                            return null;
+                        }
                         // create the target.
                         PlatformTarget target = new PlatformTarget(
                                 platform.getAbsolutePath(),
@@ -351,7 +367,19 @@
                 
                 // need to parse the skins.
                 String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS));
-                target.setSkins(skins);
+                
+                // get the default skin, or take it from the base platform if needed.
+                String defaultSkin = propertyMap.get(ADDON_DEFAULT_SKIN);
+                
+                if (defaultSkin == null) {
+                    if (skins.length == 1) {
+                        defaultSkin = skins[1];
+                    } else {
+                        defaultSkin = baseTarget.getDefaultSkin();
+                    }
+                }
+                
+                target.setSkins(skins, defaultSkin);
 
                 return target;
             }
@@ -369,7 +397,28 @@
                     addonName, valueName, SdkConstants.FN_MANIFEST_INI);
         }
     }
+    
+    /**
+     * Checks the given platform has all the required files, and returns true if they are all
+     * present.
+     * <p/>This checks the presence of the following files: android.jar, framework.aidl, aapt(.exe),
+     * aidl(.exe), dx(.bat), and dx.jar
+     */
+    private boolean checkPlatformContent(File platform, ISdkLog log) {
+        for (String relativePath : sPlatformContentList) {
+            File f = new File(platform, relativePath);
+            if (f.exists() == false) {
+                log.error(null,
+                        "Ignoring platform '%1$s': %2$s is missing.",
+                        platform.getName(), relativePath);
+                return false;
+            }
+            
+        }
+        return true;
+    }
 
+    
     /**
      * Parses a property file and returns
      * @param buildProp the property file to parse
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java
index d466182..b44cf01 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java
@@ -44,28 +44,42 @@
 public final class AvdManager {
     
     public static final String AVD_FOLDER_EXTENSION = ".avd";
+
     private final static String AVD_INFO_PATH = "path";
     private final static String AVD_INFO_TARGET = "target";
+    
+    public final static String AVD_INI_SKIN_PATH = "skin.path";
+    public final static String AVD_INI_SKIN_NAME = "skin.name";
+    public final static String AVD_INI_SDCARD_PATH = "sdcard.path";
+    public final static String AVD_INI_SDCARD_SIZE = "sdcard.size";
+    public final static String AVD_INI_IMAGES_1 = "image.sysdir.1";
+    public final static String AVD_INI_IMAGES_2 = "image.sysdir.2";
 
-    private final static String IMAGE_USERDATA = "userdata.img";
+    private final static String USERDATA_IMG = "userdata.img";
     private final static String CONFIG_INI = "config.ini";
+    private final static String SDCARD_IMG = "sdcard.img";
 
-    private final static Pattern INI_NAME_PATTERN = Pattern.compile("(.+)\\.ini$",
+    private final static String INI_EXTENSION = ".ini";
+    private final static Pattern INI_NAME_PATTERN = Pattern.compile("(.+)\\" + INI_EXTENSION + "$",
             Pattern.CASE_INSENSITIVE);
 
     private final static Pattern SDCARD_SIZE_PATTERN = Pattern.compile("\\d+[MK]?");
 
     /** An immutable structure describing an Android Virtual Device. */
     public static final class AvdInfo {
-        private String mName;
-        private String mPath;
-        private IAndroidTarget mTarget;
+        private final String mName;
+        private final String mPath;
+        private final IAndroidTarget mTarget;
+        private final Map<String, String> mProperties;
         
-        /** Creates a new AVD info. Valures are immutable. */
-        public AvdInfo(String name, String path, IAndroidTarget target) {
+        /** Creates a new AVD info. Valures are immutable. 
+         * @param properties */
+        public AvdInfo(String name, String path, IAndroidTarget target,
+                Map<String, String> properties) {
             mName = name;
             mPath = path;
             mTarget = target;
+            mProperties = properties;
         }
 
         /** Returns the name of the AVD. */
@@ -90,7 +104,7 @@
         public static File getIniFile(String name) throws AndroidLocationException {
             String avdRoot;
             avdRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
-            return new File(avdRoot, name + ".ini");
+            return new File(avdRoot, name + INI_EXTENSION);
         }
         
         /** 
@@ -100,6 +114,13 @@
         public File getIniFile() throws AndroidLocationException {
             return getIniFile(mName);
         }
+        
+        /**
+         * Returns a map of properties for the AVD.
+         */
+        public Map<String, String> getProperties() {
+            return mProperties;
+        }
     }
 
     private final ArrayList<AvdInfo> mAvdList = new ArrayList<AvdInfo>();
@@ -149,6 +170,8 @@
             String skinName, String sdcard, Map<String,String> hardwareConfig,
             boolean removePrevious, ISdkLog log) {
         
+        File iniFile = null;
+        boolean needCleanup = false;
         try {
             if (avdFolder.exists()) {
                 if (removePrevious) {
@@ -170,14 +193,27 @@
             }
 
             // actually write the ini file
-            createAvdIniFile(name, avdFolder, target);
+            iniFile = createAvdIniFile(name, avdFolder, target);
 
             // writes the userdata.img in it.
             String imagePath = target.getPath(IAndroidTarget.IMAGES);
-            File userdataSrc = new File(imagePath, IMAGE_USERDATA);
+            File userdataSrc = new File(imagePath, USERDATA_IMG);
+            
+            if (userdataSrc.exists() == false && target.isPlatform() == false) {
+                imagePath = target.getParent().getPath(IAndroidTarget.IMAGES);
+                userdataSrc = new File(imagePath, USERDATA_IMG);
+            }
+            
+            if (userdataSrc.exists() == false) {
+                log.error(null, "Unable to find a '%1$s' file to copy into the AVD folder.",
+                        USERDATA_IMG);
+                needCleanup = true;
+                return null;
+            }
+            
             FileInputStream fis = new FileInputStream(userdataSrc);
             
-            File userdataDest = new File(avdFolder, IMAGE_USERDATA);
+            File userdataDest = new File(avdFolder, USERDATA_IMG);
             FileOutputStream fos = new FileOutputStream(userdataDest);
             
             byte[] buffer = new byte[4096];
@@ -189,23 +225,61 @@
             fos.close();
             fis.close();
             
-            // Config file
+            // Config file.
             HashMap<String, String> values = new HashMap<String, String>();
-            if (skinName != null) {
-                // assume skin name is valid
-                values.put("skin", skinName);
+
+            // First the image folders of the target itself
+            imagePath = getImageRelativePath(target, log);
+            if (imagePath == null) {
+                needCleanup = true;
+                return null;
             }
+            
+            values.put(AVD_INI_IMAGES_1, imagePath);
+            
+            // If the target is an add-on we need to add the Platform image as a backup.
+            IAndroidTarget parent = target.getParent();
+            if (parent != null) {
+                imagePath = getImageRelativePath(parent, log);
+                if (imagePath == null) {
+                    needCleanup = true;
+                    return null;
+                }
+
+                values.put(AVD_INI_IMAGES_2, imagePath);
+            }
+            
+            
+            // Now the skin.
+            if (skinName == null) {
+                skinName = target.getDefaultSkin();
+            }
+
+            // get the path of the skin (relative to the SDK)
+            // assume skin name is valid
+            String skinPath = getSkinRelativePath(skinName, target, log);
+            if (skinPath == null) {
+                needCleanup = true;
+                return null;
+            }
+
+            values.put(AVD_INI_SKIN_PATH, skinPath);
+            values.put(AVD_INI_SKIN_NAME, skinName);
 
             if (sdcard != null) {
                 File sdcardFile = new File(sdcard);
                 if (sdcardFile.isFile()) {
-                    values.put("sdcard", sdcard);
+                    // sdcard value is an external sdcard, so we put its path into the config.ini
+                    values.put(AVD_INI_SDCARD_PATH, sdcard);
                 } else {
-                    // check that it matches the pattern for sdcard size
+                    // Sdcard is possibly a size. In that case we create a file called 'sdcard.img'
+                    // in the AVD folder, and do not put any value in config.ini.
+                    
+                    // First, check that it matches the pattern for sdcard size
                     Matcher m = SDCARD_SIZE_PATTERN.matcher(sdcard);
                     if (m.matches()) {
                         // create the sdcard.
-                        sdcardFile = new File(avdFolder, "sdcard.img");
+                        sdcardFile = new File(avdFolder, SDCARD_IMG);
                         String path = sdcardFile.getAbsolutePath();
                         
                         // execute mksdcard with the proper parameters.
@@ -215,18 +289,27 @@
                         if (mkSdCard.isFile() == false) {
                             log.error(null, "'%1$s' is missing from the SDK tools folder.",
                                     mkSdCard.getName());
+                            needCleanup = true;
                             return null;
                         }
                         
                         if (createSdCard(mkSdCard.getAbsolutePath(), sdcard, path, log) == false) {
+                            needCleanup = true;
                             return null; // mksdcard output has already been displayed, no need to
                                          // output anything else.
                         }
                         
-                        // add its path to the values.
-                        values.put("sdcard", path);
+                        // add a property containing the size of the sdcard for display purpose
+                        // only when the dev does 'android list avd'
+                        values.put(AVD_INI_SDCARD_SIZE, sdcard);
                     } else {
-                        log.error(null, "'%1$s' is not recognized as a valid sdcard value", sdcard);
+                        log.error(null,
+                                "'%1$s' is not recognized as a valid sdcard value.\n" +
+                                "Value should be:\n" +
+                                "1. path to an sdcard.\n" +
+                                "2. size of the sdcard to create: <size>[K|M]",
+                                sdcard);
+                        needCleanup = true;
                         return null;
                     }
                 }
@@ -249,7 +332,7 @@
             }
             
             // create the AvdInfo object, and add it to the list
-            AvdInfo avdInfo = new AvdInfo(name, avdFolder.getAbsolutePath(), target);
+            AvdInfo avdInfo = new AvdInfo(name, avdFolder.getAbsolutePath(), target, values);
             
             mAvdList.add(avdInfo);
             
@@ -262,12 +345,84 @@
             if (log != null) {
                 log.error(e, null);
             }
+        } finally {
+            if (needCleanup) {
+                if (iniFile != null && iniFile.exists()) {
+                    iniFile.delete();
+                }
+                
+                recursiveDelete(avdFolder);
+                avdFolder.delete();
+            }
         }
         
         return null;
     }
 
     /**
+     * Returns the path to the target images folder as a relative path to the SDK.
+     */
+    private String getImageRelativePath(IAndroidTarget target, ISdkLog log) {
+        String imageFullPath = target.getPath(IAndroidTarget.IMAGES);
+
+        // make this path relative to the SDK location
+        String sdkLocation = mSdk.getLocation();
+        if (imageFullPath.startsWith(sdkLocation) == false) {
+            // this really really should not happen.
+            log.error(null, "Target location is not inside the SDK.");
+            assert false;
+            return null;
+        }
+
+        imageFullPath = imageFullPath.substring(sdkLocation.length());
+        if (imageFullPath.charAt(0) == File.separatorChar) {
+            imageFullPath = imageFullPath.substring(1);
+        }
+        return imageFullPath;
+    }
+    
+    /**
+     * Returns the path to the skin, as a relative path to the SDK.
+     */
+    private String getSkinRelativePath(String skinName, IAndroidTarget target, ISdkLog log) {
+        // first look to see if the skin is in the target
+        
+        String path = target.getPath(IAndroidTarget.SKINS);
+        File skin = new File(path, skinName);
+        
+        if (skin.exists() == false && target.isPlatform() == false) {
+            target = target.getParent();
+
+            path = target.getPath(IAndroidTarget.SKINS);
+            skin = new File(path, skinName);
+        }
+        
+        // skin really does not exist!
+        if (skin.exists() == false) {
+            log.error(null, "Skin '%1$s' does not exist.", skinName);
+            return null;
+        }
+        
+        // get the skin path
+        path = skin.getAbsolutePath();
+
+        // make this path relative to the SDK location
+        String sdkLocation = mSdk.getLocation();
+        if (path.startsWith(sdkLocation) == false) {
+            // this really really should not happen.
+            log.error(null, "Target location is not inside the SDK.");
+            assert false;
+            return null;
+        }
+
+        path = path.substring(sdkLocation.length());
+        if (path.charAt(0) == File.separatorChar) {
+            path = path.substring(1);
+        }
+        return path;
+    }
+
+    /**
      * Creates the ini file for an AVD.
      * 
      * @param name of the AVD.
@@ -276,13 +431,15 @@
      * @throws AndroidLocationException if there's a problem getting android root directory.
      * @throws IOException if {@link File#getAbsolutePath()} fails.
      */
-    private void createAvdIniFile(String name, File avdFolder, IAndroidTarget target)
+    private File createAvdIniFile(String name, File avdFolder, IAndroidTarget target)
             throws AndroidLocationException, IOException {
         HashMap<String, String> values = new HashMap<String, String>();
         File iniFile = AvdInfo.getIniFile(name);
         values.put(AVD_INFO_PATH, avdFolder.getAbsolutePath());
         values.put(AVD_INFO_TARGET, target.hashString());
         createConfigIni(iniFile, values);
+        
+        return iniFile;
     }
     
     /**
@@ -292,8 +449,8 @@
      * @throws AndroidLocationException if there's a problem getting android root directory.
      * @throws IOException if {@link File#getAbsolutePath()} fails.
      */
-    private void createAvdIniFile(AvdInfo info) throws AndroidLocationException, IOException {
-        createAvdIniFile(info.getName(), new File(info.getPath()), info.getTarget());
+    private File createAvdIniFile(AvdInfo info) throws AndroidLocationException, IOException {
+        return createAvdIniFile(info.getName(), new File(info.getPath()), info.getTarget());
     }
 
     /**
@@ -306,8 +463,6 @@
      */
     public void deleteAvd(AvdInfo avdInfo, ISdkLog log) {
         try {
-            String avdRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
-            
             File f = avdInfo.getIniFile();
             if (f.exists()) {
                 log.warning("Deleting file %s", f.getCanonicalPath());
@@ -359,7 +514,8 @@
                 }
     
                 // update avd info
-                AvdInfo info = new AvdInfo(avdInfo.getName(), paramFolderPath, avdInfo.getTarget());
+                AvdInfo info = new AvdInfo(avdInfo.getName(), paramFolderPath, avdInfo.getTarget(),
+                        avdInfo.getProperties());
                 mAvdList.remove(avdInfo);
                 mAvdList.add(info);
                 avdInfo = info;
@@ -380,7 +536,8 @@
                 }
 
                 // update avd info
-                AvdInfo info = new AvdInfo(newName, avdInfo.getPath(), avdInfo.getTarget());
+                AvdInfo info = new AvdInfo(newName, avdInfo.getPath(), avdInfo.getTarget(),
+                        avdInfo.getProperties());
                 mAvdList.remove(avdInfo);
                 mAvdList.add(info);
             }
@@ -458,18 +615,22 @@
         if (target == null) {
             return null;
         }
+        
+        // load the avd properties.
+        File configIniFile = new File(avdPath, CONFIG_INI);
+        Map<String, String> properties = SdkManager.parsePropertyFile(configIniFile, mSdkLog);
 
         Matcher matcher = INI_NAME_PATTERN.matcher(path.getName());
 
         AvdInfo info = new AvdInfo(
                 matcher.matches() ? matcher.group(1) : path.getName(), // should not happen
                 avdPath,
-                target
-                );
+                target,
+                properties);
         
         return info;
     }
-    
+
     private static void createConfigIni(File iniFile, Map<String, String> values)
             throws IOException {
         FileWriter writer = new FileWriter(iniFile);
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java
index 4e1c27f..1f6a047 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java
@@ -33,6 +33,7 @@
 public final class ProjectProperties {
     /** The property name for the project target */
     public final static String PROPERTY_TARGET = "target";
+    public final static String PROPERTY_CONFIGS = "configs";
     public final static String PROPERTY_SDK = "sdk-location";
     
     public static enum PropertyType {
@@ -201,6 +202,14 @@
     public String getProperty(String name) {
         return mProperties.get(name);
     }
+    
+    /**
+     * Removes a property and returns its previous value (or null if the property did not exist).
+     * @param name the name of the property to remove.
+     */
+    public String removeProperty(String name) {
+        return mProperties.remove(name);
+    }
 
     /**
      * Saves the property file.