Merge change 26604 into eclair

* changes:
  Fix the simulator. libhardware now needs a property named "default" to be set to the value "default", otherwise it won't fall back to the default implementation for a module.
diff --git a/build/sdk.atree b/build/sdk.atree
index d3cfced..fc157fd 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -150,10 +150,11 @@
 external/qemu/android/avd/hardware-properties.ini tools/lib/hardware-properties.ini
 
 # emulator skins
-development/emulator/skins/HVGA     platforms/${PLATFORM_NAME}/skins/HVGA
-development/emulator/skins/QVGA     platforms/${PLATFORM_NAME}/skins/QVGA
-development/emulator/skins/WVGA800  platforms/${PLATFORM_NAME}/skins/WVGA800
-development/emulator/skins/WVGA854  platforms/${PLATFORM_NAME}/skins/WVGA854
+development/emulator/skins/QVGA      platforms/${PLATFORM_NAME}/skins/QVGA
+development/emulator/skins/WQVGA432  platforms/${PLATFORM_NAME}/skins/WQVGA432
+development/emulator/skins/HVGA      platforms/${PLATFORM_NAME}/skins/HVGA
+development/emulator/skins/WVGA800   platforms/${PLATFORM_NAME}/skins/WVGA800
+development/emulator/skins/WVGA854   platforms/${PLATFORM_NAME}/skins/WVGA854
 
 # NOTICE files are copied by build/core/Makefile
 development/tools/scripts/sdk_files_NOTICE.txt platforms/${PLATFORM_NAME}/templates/NOTICE.txt
diff --git a/tools/apkbuilder/src/com/android/apkbuilder/internal/ApkBuilderImpl.java b/tools/apkbuilder/src/com/android/apkbuilder/internal/ApkBuilderImpl.java
index 81cbc1c..9d21c22 100644
--- a/tools/apkbuilder/src/com/android/apkbuilder/internal/ApkBuilderImpl.java
+++ b/tools/apkbuilder/src/com/android/apkbuilder/internal/ApkBuilderImpl.java
@@ -133,7 +133,12 @@
                     throw new WrongOptionException("Missing value for -rj");
                 }
 
-                processJarFolder(args[index++], resourcesJars);
+                File f = new File(args[index]);
+                if (f.isDirectory()) {
+                    processJarFolder(args[index++], resourcesJars);
+                } else if (f.isFile()) {
+                    processJarFile(args[index++], resourcesJars);
+                }
             } else if ("-nf".equals(argument)) {
                 // quick check on the next argument.
                 if (index == args.length) {
diff --git a/tools/ddms/app/src/com/android/ddms/UIThread.java b/tools/ddms/app/src/com/android/ddms/UIThread.java
index 61df0ab..49d07b0 100644
--- a/tools/ddms/app/src/com/android/ddms/UIThread.java
+++ b/tools/ddms/app/src/com/android/ddms/UIThread.java
@@ -256,7 +256,6 @@
 
     private Image mTracingStopImage;
 
-
     private class TableFocusListener implements ITableFocusListener {
 
         private IFocusedTableActivator mCurrentActivator;
@@ -753,16 +752,16 @@
         actionMenu.addMenuListener(new MenuAdapter() {
             @Override
             public void menuShown(MenuEvent e) {
-                actionHaltItem.setEnabled(mTBHalt.getEnabled());
-                actionCauseGcItem.setEnabled(mTBCauseGc.getEnabled());
+                actionHaltItem.setEnabled(mTBHalt.getEnabled() && mCurrentClient != null);
+                actionCauseGcItem.setEnabled(mTBCauseGc.getEnabled() && mCurrentClient != null);
             }
         });
 
         // create Device menu items
-        item = new MenuItem(deviceMenu, SWT.NONE);
-        item.setText("&Screen capture...\tCTrl-S");
-        item.setAccelerator('S' | SWT.CONTROL);
-        item.addSelectionListener(new SelectionAdapter() {
+        final MenuItem screenShotItem = new MenuItem(deviceMenu, SWT.NONE);
+        screenShotItem.setText("&Screen capture...\tCTrl-S");
+        screenShotItem.setAccelerator('S' | SWT.CONTROL);
+        screenShotItem.addSelectionListener(new SelectionAdapter() {
             @Override
             public void widgetSelected(SelectionEvent e) {
                 if (mCurrentDevice != null) {
@@ -774,9 +773,9 @@
 
         new MenuItem(deviceMenu, SWT.SEPARATOR);
 
-        item = new MenuItem(deviceMenu, SWT.NONE);
-        item.setText("File Explorer...");
-        item.addSelectionListener(new SelectionAdapter() {
+        final MenuItem explorerItem = new MenuItem(deviceMenu, SWT.NONE);
+        explorerItem.setText("File Explorer...");
+        explorerItem.addSelectionListener(new SelectionAdapter() {
             @Override
             public void widgetSelected(SelectionEvent e) {
                 createFileExplorer();
@@ -785,9 +784,9 @@
 
         new MenuItem(deviceMenu, SWT.SEPARATOR);
 
-        item = new MenuItem(deviceMenu, SWT.NONE);
-        item.setText("Show &process status...");
-        item.addSelectionListener(new SelectionAdapter() {
+        final MenuItem processItem = new MenuItem(deviceMenu, SWT.NONE);
+        processItem.setText("Show &process status...");
+        processItem.addSelectionListener(new SelectionAdapter() {
             @Override
             public void widgetSelected(SelectionEvent e) {
                 DeviceCommandDialog dlg;
@@ -796,9 +795,9 @@
             }
         });
 
-        item = new MenuItem(deviceMenu, SWT.NONE);
-        item.setText("Dump &device state...");
-        item.addSelectionListener(new SelectionAdapter() {
+        final MenuItem deviceStateItem = new MenuItem(deviceMenu, SWT.NONE);
+        deviceStateItem.setText("Dump &device state...");
+        deviceStateItem.addSelectionListener(new SelectionAdapter() {
             @Override
             public void widgetSelected(SelectionEvent e) {
                 DeviceCommandDialog dlg;
@@ -808,10 +807,10 @@
             }
         });
 
-        item = new MenuItem(deviceMenu, SWT.NONE);
-        item.setText("Dump &app state...");
-        item.setEnabled(false);
-        item.addSelectionListener(new SelectionAdapter() {
+        final MenuItem appStateItem = new MenuItem(deviceMenu, SWT.NONE);
+        appStateItem.setText("Dump &app state...");
+        appStateItem.setEnabled(false);
+        appStateItem.addSelectionListener(new SelectionAdapter() {
             @Override
             public void widgetSelected(SelectionEvent e) {
                 DeviceCommandDialog dlg;
@@ -820,9 +819,9 @@
             }
         });
 
-        item = new MenuItem(deviceMenu, SWT.NONE);
-        item.setText("Dump &radio state...");
-        item.addSelectionListener(new SelectionAdapter() {
+        final MenuItem radioStateItem = new MenuItem(deviceMenu, SWT.NONE);
+        radioStateItem.setText("Dump &radio state...");
+        radioStateItem.addSelectionListener(new SelectionAdapter() {
             @Override
             public void widgetSelected(SelectionEvent e) {
                 DeviceCommandDialog dlg;
@@ -835,9 +834,9 @@
             }
         });
 
-        item = new MenuItem(deviceMenu, SWT.NONE);
-        item.setText("Run &logcat...");
-        item.addSelectionListener(new SelectionAdapter() {
+        final MenuItem logCatItem = new MenuItem(deviceMenu, SWT.NONE);
+        logCatItem.setText("Run &logcat...");
+        logCatItem.addSelectionListener(new SelectionAdapter() {
             @Override
             public void widgetSelected(SelectionEvent e) {
                 DeviceCommandDialog dlg;
@@ -847,6 +846,21 @@
             }
         });
 
+        // configure Action items based on current state
+        deviceMenu.addMenuListener(new MenuAdapter() {
+            @Override
+            public void menuShown(MenuEvent e) {
+                boolean deviceEnabled = mCurrentDevice != null;
+                screenShotItem.setEnabled(deviceEnabled);
+                explorerItem.setEnabled(deviceEnabled);
+                processItem.setEnabled(deviceEnabled);
+                deviceStateItem.setEnabled(deviceEnabled);
+                appStateItem.setEnabled(deviceEnabled);
+                radioStateItem.setEnabled(deviceEnabled);
+                logCatItem.setEnabled(deviceEnabled);
+            }
+        });
+
         // create Help menu items
         item = new MenuItem(helpMenu, SWT.NONE);
         item.setText("&Contents...");
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java
index 7857997..8a12e19 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/FolderConfiguration.java
@@ -49,6 +49,13 @@
     private final static int INDEX_COUNT              = 14;
 
     /**
+     * Returns the number of {@link ResourceQualifier} that make up a Folder configuration.
+     */
+    public static int getQualifierCount() {
+        return INDEX_COUNT;
+    }
+
+    /**
      * Sets the config from the qualifiers of a given <var>config</var>.
      * @param config
      */
@@ -147,6 +154,16 @@
         }
     }
 
+    /**
+     * Returns a qualifier by its index. The total number of qualifiers can be accessed by
+     * {@link #getQualifierCount()}.
+     * @param index the index of the qualifier to return.
+     * @return the qualifier or null if there are none at the index.
+     */
+    public ResourceQualifier getQualifier(int index) {
+        return mQualifiers[index];
+    }
+
     public void setCountryCodeQualifier(CountryCodeQualifier qualifier) {
         mQualifiers[INDEX_COUNTRY_CODE] = qualifier;
     }
@@ -446,7 +463,7 @@
     }
 
     /**
-     * Returns whether the configuration match the given reference config.
+     * Returns whether the configuration is a match for the given reference config.
      * <p/>A match means that:
      * <ul>
      * <li>This config does not use any qualifier not used by the reference config</li>
@@ -454,29 +471,24 @@
      * the reference config.</li>
      * </ul>
      * @param referenceConfig The reference configuration to test against.
-     * @return the number of matching qualifiers or -1 if the configurations are not compatible.
+     * @return true if the configuration matches.
      */
-    public int match(FolderConfiguration referenceConfig) {
-        int matchCount = 0;
-
+    public boolean isMatchFor(FolderConfiguration referenceConfig) {
         for (int i = 0 ; i < INDEX_COUNT ; i++) {
             ResourceQualifier testQualifier = mQualifiers[i];
             ResourceQualifier referenceQualifier = referenceConfig.mQualifiers[i];
 
-            // we only care if testQualifier is non null. If it's null, it's a match but
-            // without increasing the matchCount.
+            // we only care if testQualifier is non null.
             if (testQualifier != null) {
-                if (referenceQualifier == null) {
-                    return -1;
-                } else if (testQualifier.equals(referenceQualifier) == false) {
-                    return -1;
+                if (referenceQualifier == null) { // reference config doesn't specify anything
+                                                  // for this qualifier so we refuse it.
+                    return false;
+                } else if (testQualifier.isMatchFor(referenceQualifier) == false) {
+                    return false;
                 }
-
-                // the qualifier match, increment the count
-                matchCount++;
             }
         }
-        return matchCount;
+        return true;
     }
 
     /**
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/KeyboardStateQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/KeyboardStateQualifier.java
index 1aa9286..2777328 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/KeyboardStateQualifier.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/KeyboardStateQualifier.java
@@ -37,7 +37,8 @@
      */
     public static enum KeyboardState {
         EXPOSED("keysexposed", "Exposed"), //$NON-NLS-1$
-        HIDDEN("keyshidden", "Hidden"); //$NON-NLS-1$
+        HIDDEN("keyshidden", "Hidden"),    //$NON-NLS-1$
+        SOFT("keyssoft", "Soft");          //$NON-NLS-1$
 
         private String mValue;
         private String mDisplayValue;
@@ -141,6 +142,42 @@
     }
 
     @Override
+    public boolean isMatchFor(ResourceQualifier qualifier) {
+        if (qualifier instanceof KeyboardStateQualifier) {
+            KeyboardStateQualifier referenceQualifier = (KeyboardStateQualifier)qualifier;
+
+            // special case where EXPOSED can be used for SOFT
+            if (referenceQualifier.mValue == KeyboardState.SOFT &&
+                    mValue == KeyboardState.EXPOSED) {
+                return true;
+            }
+
+            return referenceQualifier.mValue == mValue;
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean isBetterMatchThan(ResourceQualifier compareTo, ResourceQualifier reference) {
+        if (compareTo == null) {
+            return true;
+        }
+
+        KeyboardStateQualifier compareQualifier = (KeyboardStateQualifier)compareTo;
+        KeyboardStateQualifier referenceQualifier = (KeyboardStateQualifier)reference;
+        if (referenceQualifier.mValue == KeyboardState.SOFT) { // only case where there could be a
+                                                               // better qualifier
+            // only return true if it's a better value.
+            if (compareQualifier.mValue == KeyboardState.EXPOSED && mValue == KeyboardState.SOFT) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
     public boolean equals(Object qualifier) {
         if (qualifier instanceof KeyboardStateQualifier) {
             return mValue == ((KeyboardStateQualifier)qualifier).mValue;
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/PixelDensityQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/PixelDensityQualifier.java
index f75e9cb..0ba2aac 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/PixelDensityQualifier.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/PixelDensityQualifier.java
@@ -17,6 +17,7 @@
 package com.android.ide.eclipse.adt.internal.resources.configurations;
 
 import com.android.ide.eclipse.adt.internal.editors.IconFactory;
+import com.android.layoutlib.api.IDensityBasedResourceValue;
 import com.android.sdklib.AndroidVersion;
 import com.android.sdklib.IAndroidTarget;
 
@@ -39,19 +40,22 @@
      * Screen Orientation enum.
      */
     public static enum Density {
-        HIGH("hdpi", 240, "High Density"), //$NON-NLS-1$
-        MEDIUM("mdpi", 160, "Medium Density"), //$NON-NLS-1$
-        LOW("ldpi", 120, "Low Density"), //$NON-NLS-1$
-        NODPI("nodpi", -1, "No Density"); //$NON-NLS-1$
+        HIGH("hdpi", 240, "High Density", IDensityBasedResourceValue.Density.HIGH), //$NON-NLS-1$
+        MEDIUM("mdpi", 160, "Medium Density", IDensityBasedResourceValue.Density.MEDIUM), //$NON-NLS-1$
+        LOW("ldpi", 120, "Low Density", IDensityBasedResourceValue.Density.LOW), //$NON-NLS-1$
+        NODPI("nodpi", -1, "No Density", IDensityBasedResourceValue.Density.NODPI); //$NON-NLS-1$
 
         private final String mValue;
         private final String mDisplayValue;
         private final int mDpiValue;
+        private final IDensityBasedResourceValue.Density mDensity;
 
-        private Density(String value, int dpiValue, String displayValue) {
+        private Density(String value, int dpiValue, String displayValue,
+                IDensityBasedResourceValue.Density density) {
             mValue = value;
             mDpiValue = dpiValue;
             mDisplayValue = displayValue;
+            mDensity = density;
         }
 
         /**
@@ -109,6 +113,14 @@
             return mDisplayValue;
         }
 
+        /**
+         * Returns the {@link com.android.layoutlib.api.IDensityBasedResourceValue.Density} value
+         * associated to this {@link Density}.
+         */
+        public IDensityBasedResourceValue.Density getDensity() {
+            return mDensity;
+        }
+
         public static int getIndex(Density value) {
             int i = 0;
             for (Density input : values()) {
@@ -184,6 +196,38 @@
     }
 
     @Override
+    public boolean isMatchFor(ResourceQualifier qualifier) {
+        if (qualifier instanceof PixelDensityQualifier) {
+            // as long as there's a density qualifier, it's always a match.
+            // The best match will be found later.
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean isBetterMatchThan(ResourceQualifier compareTo, ResourceQualifier reference) {
+        if (compareTo == null) {
+            return true;
+        }
+
+        PixelDensityQualifier compareQ = (PixelDensityQualifier)compareTo;
+        PixelDensityQualifier referenceQ = (PixelDensityQualifier)reference;
+
+        if (mValue == referenceQ.mValue && compareQ.mValue != referenceQ.mValue) {
+            // got exact value, this is the best!
+            return true;
+        } else {
+            // in all case we're going to prefer the higher dpi.
+            // if reference is high, we want highest dpi.
+            // if reference is medium, we'll prefer to scale down high dpi, than scale up low dpi
+            // if reference if low, we'll prefer to scale down high than medium (2:1 over 4:3)
+            return mValue.mDpiValue > compareQ.mValue.mDpiValue;
+        }
+    }
+
+    @Override
     public boolean equals(Object qualifier) {
         if (qualifier instanceof PixelDensityQualifier) {
             return mValue == ((PixelDensityQualifier)qualifier).mValue;
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ResourceQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ResourceQualifier.java
index bfee8d2..ba54ad0 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ResourceQualifier.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/ResourceQualifier.java
@@ -62,6 +62,32 @@
      */
     public abstract String getFolderSegment(IAndroidTarget target);
 
+    /**
+     * Returns whether the given qualifier is a match for the receiver.
+     * <p/>The default implementation returns the result of {@link #equals(Object)}.
+     * <p/>Children class that re-implements this must implement
+     * {@link #isBetterMatchThan(ResourceQualifier, ResourceQualifier)} too.
+     * @param qualifier the reference qualifier
+     * @return true if the receiver is a match.
+     */
+    public boolean isMatchFor(ResourceQualifier qualifier) {
+        return equals(qualifier);
+    }
+
+    /**
+     * Returns true if the receiver is a better match for the given <var>reference</var> than
+     * the given <var>compareTo</var> comparable.
+     * @param compareTo The {@link ResourceQualifier} to compare to. Can be null, in which
+     * case the method must return <code>true</code>.
+     * @param reference The reference qualifier value for which the match is.
+     * @return true if the receiver is a better match.
+     */
+    public boolean isBetterMatchThan(ResourceQualifier compareTo, ResourceQualifier reference) {
+        // the default is to always return false. This gives less overhead than always returning
+        // true, as it would only compare same values anyway.
+        return false;
+    }
+
     @Override
     public String toString() {
         return getFolderSegment(null);
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/MultiResourceFile.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/MultiResourceFile.java
index 7528441..2d2749d 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/MultiResourceFile.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/MultiResourceFile.java
@@ -45,7 +45,7 @@
 public final class MultiResourceFile extends ResourceFile implements IValueResourceRepository {
 
     private final static SAXParserFactory sParserFactory = SAXParserFactory.newInstance();
-    
+
     private final HashMap<ResourceType, HashMap<String, ResourceValue>> mResourceItems =
         new HashMap<ResourceType, HashMap<String, ResourceValue>>();
 
@@ -58,7 +58,7 @@
         update();
 
         Set<ResourceType> keys = mResourceItems.keySet();
-        
+
         return keys.toArray(new ResourceType[keys.size()]);
     }
 
@@ -69,21 +69,21 @@
         HashMap<String, ResourceValue> list = mResourceItems.get(type);
         return (list != null && list.size() > 0);
     }
-    
+
     @Override
     public Collection<ProjectResourceItem> getResources(ResourceType type,
             ProjectResources projectResources) {
         update();
 
         HashMap<String, ResourceValue> list = mResourceItems.get(type);
-        
+
         ArrayList<ProjectResourceItem> items = new ArrayList<ProjectResourceItem>();
-        
+
         if (list != null) {
             Collection<ResourceValue> values = list.values();
             for (ResourceValue res : values) {
                 ProjectResourceItem item = projectResources.findResourceItem(type, res.getName());
-                
+
                 if (item == null) {
                     if (type == ResourceType.ID) {
                         item = new IdResourceItem(res.getName(), false /* isDeclaredInline */);
@@ -99,7 +99,7 @@
 
         return items;
     }
-    
+
     /**
      * Updates the Resource items if necessary.
      */
@@ -110,7 +110,7 @@
 
             // need to parse the file and find the content.
             parseFile();
-            
+
             resetTouch();
         }
     }
@@ -128,7 +128,7 @@
         } catch (CoreException e) {
         }
     }
-    
+
     /**
      * Adds a resource item to the list
      * @param resType The type of the resource
@@ -138,7 +138,7 @@
         ResourceType type = ResourceType.getEnum(resType);
         if (type != null) {
             HashMap<String, ResourceValue> list = mResourceItems.get(type);
-    
+
             // if the list does not exist, create it.
             if (list == null) {
                 list = new HashMap<String, ResourceValue>();
@@ -146,13 +146,13 @@
             } else {
                 // look for a possible value already existing.
                 ResourceValue oldValue = list.get(value.getName());
-                
+
                 if (oldValue != null) {
                     oldValue.replaceWith(value);
                     return;
                 }
             }
-            
+
             // empty list or no match found? add the given resource
             list.put(value.getName(), value);
         }
@@ -168,7 +168,7 @@
         if (list != null) {
             return list.get(name);
         }
-        
+
         return null;
     }
 }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java
index e8c3687..9d715d0 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java
@@ -22,6 +22,7 @@
 import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
 import com.android.ide.eclipse.adt.internal.resources.configurations.LanguageQualifier;
 import com.android.ide.eclipse.adt.internal.resources.configurations.RegionQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ResourceQualifier;
 import com.android.ide.eclipse.adt.internal.resources.manager.files.IAbstractFolder;
 import com.android.layoutlib.api.IResourceValue;
 import com.android.layoutlib.utils.ResourceValue;
@@ -505,79 +506,102 @@
      * Returns the best matching {@link Resource}.
      * @param resources the list of {@link Resource} to choose from.
      * @param referenceConfig the {@link FolderConfiguration} to match.
+     * @see http://d.android.com/guide/topics/resources/resources-i18n.html#best-match
      */
     private Resource findMatchingConfiguredResource(List<? extends Resource> resources,
             FolderConfiguration referenceConfig) {
-        // look for resources with the maximum number of qualifier match.
-        int currentMax = -1;
+        //
+        // 1: eliminate resources that contradict the reference configuration
+        // 2: pick next qualifier type
+        // 3: check if any resources use this qualifier, if no, back to 2, else move on to 4.
+        // 4: eliminate resources that don't use this qualifier.
+        // 5: if more than one resource left, go back to 2.
+        //
+        // The precedence of the qualifiers is more important than the number of qualifiers that
+        // exactly match the device.
+
+        // 1: eliminate resources that contradict
         ArrayList<Resource> matchingResources = new ArrayList<Resource>();
         for (int i = 0 ; i < resources.size(); i++) {
             Resource res = resources.get(i);
 
-            int count = res.getConfiguration().match(referenceConfig);
-            if (count > currentMax) {
-                matchingResources.clear();
-                matchingResources.add(res);
-                currentMax = count;
-            } else if (count != -1 && count == currentMax) {
+            if (res.getConfiguration().isMatchFor(referenceConfig)) {
                 matchingResources.add(res);
             }
         }
 
-        // if we have more than one match, we look for the match with the qualifiers with the
-        // highest priority.
-        Resource resMatch = null;
+        // if there is only one match, just take it
         if (matchingResources.size() == 1) {
-            resMatch = matchingResources.get(0);
-        } else if (matchingResources.size() > 1) {
-            // More than one resource with the same number of qualifier match.
-            // We loop, looking for the resource with the highest priority qualifiers.
-            ArrayList<Resource> tmpResources = new ArrayList<Resource>();
-            int startIndex = 0;
-            while (matchingResources.size() > 1) {
-                int highest = -1;
-                for (int i = 0 ; i < matchingResources.size() ; i++) {
-                    Resource folder = matchingResources.get(i);
+            return matchingResources.get(0);
+        } else if (matchingResources.size() == 0) {
+            return null;
+        }
 
-                    // get highest priority qualifiers.
-                    int m = folder.getConfiguration().getHighestPriorityQualifier(startIndex);
+        // 2. Loop on the qualifiers, and eliminate matches
+        final int count = FolderConfiguration.getQualifierCount();
+        for (int q = 0 ; q < count ; q++) {
+            // look to see if one resource has this qualifier.
+            // At the same time also record the best match value for the qualifier (if applicable).
+            ResourceQualifier referenceQualifier = referenceConfig.getQualifier(q);
 
-                    // add to the list if highest.
-                    if (m != -1) {
-                        if (highest == -1 || m == highest) {
-                            tmpResources.add(folder);
-                            highest = m;
-                        } else if (m < highest) { // highest priority == lowest index.
-                            tmpResources.clear();
-                            tmpResources.add(folder);
+            if (referenceQualifier != null) { // no need to check if it's null, since the loop
+                                              // above will have removed the resources anyway.
+                boolean found = false;
+                ResourceQualifier bestMatch = null;
+                for (Resource res : matchingResources) {
+                    ResourceQualifier qualifier = res.getConfiguration().getQualifier(q);
+                    if (qualifier != null) {
+                        // set the flag.
+                        found = true;
+
+                        // now check for a best match.
+                        if (qualifier.isBetterMatchThan(bestMatch, referenceQualifier)) {
+                            bestMatch = qualifier;
                         }
                     }
                 }
 
-                // at this point, we have a list with 1+ resources that all have the same highest
-                // priority qualifiers. Go through the list again looking for the next highest
-                // priority qualifier.
-                startIndex = highest + 1;
+                // if a resources as a qualifier at the current index, remove all the resources that
+                // do not have one.
+                // If there is one, and we have a bestComparable, also check that it's equal to the
+                // best comparable.
+                if (found) {
+                    for (int i = 0 ; i < matchingResources.size(); ) {
+                        Resource res = matchingResources.get(i);
+                        ResourceQualifier qualifier = res.getConfiguration().getQualifier(q);
 
-                // this should not happen, but it's better to check.
-                if (matchingResources.size() == tmpResources.size() && highest == -1) {
-                    // this means all the resources match with the same qualifiers
-                    // (highest == -1 means we reached the end of the qualifier list)
-                    // In this case, we arbitrarily take the first resource.
-                    matchingResources.clear();
-                    matchingResources.add(tmpResources.get(0));
-                } else {
-                    matchingResources.clear();
-                    matchingResources.addAll(tmpResources);
+                        if (qualifier == null) { // no qualifier? remove the resources
+                            matchingResources.remove(res);
+                        } else if (bestMatch != null && bestMatch.equals(qualifier) == false) {
+                            // if there is a best match, only accept the resource if the qualifier
+                            // has the same best value.
+                            matchingResources.remove(res);
+                        } else {
+                            i++;
+                        }
+                    }
+
+                    // at this point we may have run out of matching resources before going
+                    // through all the qualifiers.
+                    if (matchingResources.size() == 1) {
+                        return matchingResources.get(0);
+                    } else if (matchingResources.size() == 0) {
+                        return null;
+                    }
                 }
-                tmpResources.clear();
             }
-
-            // we should have only one match here.
-            resMatch = matchingResources.get(0);
         }
 
-        return resMatch;
+        // went through all the qualifiers. We should not have more than one
+        switch (matchingResources.size()) {
+            case 0:
+                return null;
+            case 1:
+                return matchingResources.get(1);
+            case 2:
+                assert false;
+        }
+        return null;
     }
 
     /**
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/SingleResourceFile.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/SingleResourceFile.java
index 51bd793..8900500 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/SingleResourceFile.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/SingleResourceFile.java
@@ -17,8 +17,10 @@
 package com.android.ide.eclipse.adt.internal.resources.manager;
 
 import com.android.ide.eclipse.adt.internal.resources.ResourceType;
+import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier;
 import com.android.ide.eclipse.adt.internal.resources.manager.files.IAbstractFile;
 import com.android.layoutlib.api.IResourceValue;
+import com.android.layoutlib.utils.DensityBasedResourceValue;
 import com.android.layoutlib.utils.ResourceValue;
 
 import java.util.ArrayList;
@@ -40,24 +42,24 @@
     static {
         sParserFactory.setNamespaceAware(true);
     }
-    
+
     private final static Pattern sXmlPattern = Pattern.compile("^(.+)\\.xml", //$NON-NLS-1$
             Pattern.CASE_INSENSITIVE);
-    
+
     private final static Pattern[] sDrawablePattern = new Pattern[] {
         Pattern.compile("^(.+)\\.9\\.png", Pattern.CASE_INSENSITIVE), //$NON-NLS-1$
         Pattern.compile("^(.+)\\.png", Pattern.CASE_INSENSITIVE), //$NON-NLS-1$
         Pattern.compile("^(.+)\\.jpg", Pattern.CASE_INSENSITIVE), //$NON-NLS-1$
         Pattern.compile("^(.+)\\.gif", Pattern.CASE_INSENSITIVE), //$NON-NLS-1$
     };
-    
+
     private String mResourceName;
     private ResourceType mType;
     private IResourceValue mValue;
 
     public SingleResourceFile(IAbstractFile file, ResourceFolder folder) {
         super(file, folder);
-        
+
         // we need to infer the type of the resource from the folder type.
         // This is easy since this is a single Resource file.
         ResourceType[] types = FolderTypeRelationship.getRelatedResourceTypes(folder.getType());
@@ -65,9 +67,17 @@
 
         // compute the resource name
         mResourceName = getResourceName(mType);
-        
-        mValue = new ResourceValue(mType.getName(), getResourceName(mType), file.getOsLocation(),
-                isFramework());
+
+        // test if there's a density qualifier associated with the resource
+        PixelDensityQualifier qualifier = folder.getConfiguration().getPixelDensityQualifier();
+
+        if (qualifier == null) {
+            mValue = new ResourceValue(mType.getName(), getResourceName(mType),
+                    file.getOsLocation(), isFramework());
+        } else {
+            mValue = new DensityBasedResourceValue(mType.getName(), getResourceName(mType),
+                    file.getOsLocation(), qualifier.getValue().getDensity(), isFramework());
+        }
     }
 
     @Override
@@ -83,27 +93,27 @@
     @Override
     public Collection<ProjectResourceItem> getResources(ResourceType type,
             ProjectResources projectResources) {
-        
+
         // looking for an existing ResourceItem with this name and type
         ProjectResourceItem item = projectResources.findResourceItem(type, mResourceName);
-        
+
         ArrayList<ProjectResourceItem> items = new ArrayList<ProjectResourceItem>();
 
         if (item == null) {
             item = new ConfigurableResourceItem(mResourceName);
             items.add(item);
         }
-        
+
         // add this ResourceFile to the ResourceItem
         item.add(this);
-        
+
         return items;
     }
 
     /*
      * (non-Javadoc)
      * @see com.android.ide.eclipse.editors.resources.manager.ResourceFile#getValue(com.android.ide.eclipse.common.resources.ResourceType, java.lang.String)
-     * 
+     *
      * This particular implementation does not care about the type or name since a
      * SingleResourceFile represents a file generating only one resource.
      * The value returned is the full absolute path of the file in OS form.
@@ -112,14 +122,14 @@
     public IResourceValue getValue(ResourceType type, String name) {
         return mValue;
     }
-    
+
     /**
      * Returns the name of the resources.
      */
     private String getResourceName(ResourceType type) {
         // get the name from the filename.
         String name = getFile().getName();
-        
+
         if (type == ResourceType.ANIM || type == ResourceType.LAYOUT || type == ResourceType.MENU ||
                 type == ResourceType.COLOR || type == ResourceType.XML) {
             Matcher m = sXmlPattern.matcher(name);
@@ -133,7 +143,7 @@
                     return m.group(1);
                 }
             }
-            
+
             // also try the Xml pattern for selector/shape based drawable.
             Matcher m = sXmlPattern.matcher(name);
             if (m.matches()) {
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java b/tools/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java
index 63dc662..b59182b 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/DdmsPlugin.java
@@ -226,7 +226,7 @@
 
         // read the adb location from the prefs to attempt to start it properly without
         // having to wait for ADT to start
-        setAdbLocation(eclipseStore.getString(ADB_LOCATION));
+        final boolean adbValid = setAdbLocation(eclipseStore.getString(ADB_LOCATION));
 
         // start it in a thread to return from start() asap.
         new Thread() {
@@ -236,7 +236,9 @@
                 getDefault().initDdmlib();
 
                 // create and start the first bridge
-                AndroidDebugBridge.createBridge(sAdbLocation, true /* forceNewBridge */);
+                if (adbValid) {
+                    AndroidDebugBridge.createBridge(sAdbLocation, true /* forceNewBridge */);
+                }
             }
         }.start();
     }
@@ -295,18 +297,27 @@
         return sHprofConverter;
     }
 
-    private static void setAdbLocation(String adbLocation) {
-        sAdbLocation = adbLocation;
+    /**
+     * Stores the adb location. This returns true if the location is an existing file.
+     */
+    private static boolean setAdbLocation(String adbLocation) {
+        File adb = new File(adbLocation);
+        if (adb.isFile()) {
+            sAdbLocation = adbLocation;
 
-        File adb = new File(sAdbLocation);
-        File toolsFolder = adb.getParentFile();
-        sToolsFolder = toolsFolder.getAbsolutePath();
+            File toolsFolder = adb.getParentFile();
+            sToolsFolder = toolsFolder.getAbsolutePath();
 
-        File hprofConverter = new File(toolsFolder, DdmConstants.FN_HPROF_CONVERTER);
-        sHprofConverter = hprofConverter.getAbsolutePath();
+            File hprofConverter = new File(toolsFolder, DdmConstants.FN_HPROF_CONVERTER);
+            sHprofConverter = hprofConverter.getAbsolutePath();
 
-        File traceview = new File(toolsFolder, DdmConstants.FN_TRACEVIEW);
-        DdmUiPreferences.setTraceviewLocation(traceview.getAbsolutePath());
+            File traceview = new File(toolsFolder, DdmConstants.FN_TRACEVIEW);
+            DdmUiPreferences.setTraceviewLocation(traceview.getAbsolutePath());
+
+            return true;
+        }
+
+        return false;
     }
 
     /**
@@ -315,23 +326,26 @@
      * @param startAdb flag to start adb
      */
     public static void setAdb(String adb, boolean startAdb) {
-        setAdbLocation(adb);
+        if (adb != null) {
+            if (setAdbLocation(adb)) {
+                // store the location for future ddms only start.
+                sPlugin.getPreferenceStore().setValue(ADB_LOCATION, sAdbLocation);
 
-        // store the location for future ddms only start.
-        sPlugin.getPreferenceStore().setValue(ADB_LOCATION, sAdbLocation);
+                // starts the server in a thread in case this is blocking.
+                if (startAdb) {
+                    new Thread() {
+                        @Override
+                        public void run() {
+                            // init ddmlib if needed
+                            getDefault().initDdmlib();
 
-        // starts the server in a thread in case this is blocking.
-        if (startAdb) {
-            new Thread() {
-                @Override
-                public void run() {
-                    // init ddmlib if needed
-                    getDefault().initDdmlib();
-
-                    // create and start the bridge
-                    AndroidDebugBridge.createBridge(sAdbLocation, false /* forceNewBridge */);
+                            // create and start the bridge
+                            AndroidDebugBridge.createBridge(sAdbLocation,
+                                    false /* forceNewBridge */);
+                        }
+                    }.start();
                 }
-            }.start();
+            }
         }
     }
 
diff --git a/tools/layoutlib_utils/src/com/android/layoutlib/utils/DensityBasedResourceValue.java b/tools/layoutlib_utils/src/com/android/layoutlib/utils/DensityBasedResourceValue.java
new file mode 100644
index 0000000..59de463
--- /dev/null
+++ b/tools/layoutlib_utils/src/com/android/layoutlib/utils/DensityBasedResourceValue.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.utils;
+
+import com.android.layoutlib.api.IDensityBasedResourceValue;
+
+public class DensityBasedResourceValue extends ResourceValue implements IDensityBasedResourceValue {
+
+    private Density mDensity;
+
+    public DensityBasedResourceValue(String type, String name, String value, Density density,
+            boolean isFramework) {
+        super(type, name, value, isFramework);
+        mDensity = density;
+    }
+
+    public Density getDensity() {
+        return mDensity;
+    }
+}
diff --git a/tools/scripts/android_rules.xml b/tools/scripts/android_rules.xml
index e91dc0b..a14345b 100644
--- a/tools/scripts/android_rules.xml
+++ b/tools/scripts/android_rules.xml
@@ -22,9 +22,16 @@
         classname="com.android.ant.ApkBuilderTask"
         classpathref="android.antlibs" />
 
+    <taskdef name="xpath"
+        classname="com.android.ant.XPathTask"
+        classpathref="android.antlibs" />
+
     <!-- Properties -->
 
     <property name="android.tools.dir" location="${sdk.dir}/tools" />
+    <!-- Name of the application package extracted from manifest file -->
+    <xpath input="AndroidManifest.xml" expression="/manifest/@package"
+                output="manifest.package" />
 
     <!-- Input directories -->
     <property name="source.dir" value="src" />
@@ -329,22 +336,22 @@
 
     <target name="-uninstall-check">
         <condition property="uninstall.run">
-           <isset property="application.package" />
+           <isset property="manifest.package" />
         </condition>
     </target>
 
     <target name="-uninstall-error" depends="-uninstall-check" unless="uninstall.run">
-        <echo>Unable to run 'ant uninstall', application.package is not defined in build.properties
+        <echo>Unable to run 'ant uninstall', manifest.package property is not defined.
         </echo>
     </target>
 
     <!-- Uninstalls the package from the default emulator/device -->
     <target name="uninstall" depends="-uninstall-error" if="uninstall.run"
                 description="Uninstalls the application from a running emulator or device.">
-        <echo>Uninstalling ${application.package} from the default emulator or device...</echo>
+        <echo>Uninstalling ${manifest.package} from the default emulator or device...</echo>
         <exec executable="${adb}" failonerror="true">
             <arg value="uninstall" />
-            <arg value="${application.package}" />
+            <arg value="${manifest.package}" />
         </exec>
     </target>
 
diff --git a/tools/scripts/android_test_rules.xml b/tools/scripts/android_test_rules.xml
index 14bdb2f..fd8a521 100644
--- a/tools/scripts/android_test_rules.xml
+++ b/tools/scripts/android_test_rules.xml
@@ -8,11 +8,14 @@
     <property name="instrumentation.absolute.dir" location="${instrumentation.dir}" />
 
     <property name="test.runner" value="android.test.InstrumentationTestRunner" />
-    <property name="application.package.to.instrument" value="${application.package}.tests" />
+    <!-- Application package of the tested project extracted from its manifest file -->
+    <xpath input="${tested.project.absolute.dir}/AndroidManifest.xml"
+                expression="/manifest/@package" output="tested.manifest.package" />
 
     <!-- TODO: make it more configurable in the next CL's - now it is default for auto-generated
          project -->
-    <property name="emma.dump.file" value="/data/data/${application.package}/files/coverage.ec" />
+    <property name="emma.dump.file"
+                  value="/data/data/${tested.manifest.package}/files/coverage.ec" />
 
     <macrodef name="run-tests-helper">
         <attribute name="emma.enabled" default="false" />
@@ -28,7 +31,7 @@
                    <arg value="coverage" />
                    <arg value="@{emma.enabled}" />
                 <extra-instrument-args />
-                <arg value="${application.package.to.instrument}/${test.runner}" />
+                <arg value="${manifest.package}/${test.runner}" />
             </exec>
         </sequential>
     </macrodef>
diff --git a/tools/scripts/plugin.prop b/tools/scripts/plugin.prop
index af9613e..39a8c42 100644
--- a/tools/scripts/plugin.prop
+++ b/tools/scripts/plugin.prop
@@ -1,4 +1,3 @@
 # begin plugin.prop
-plugin.version=0.9.2
-plugin.platform=android
+plugin.version=0.9.4
 # end plugin.prop
\ No newline at end of file
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java
index 916fa7c..3e15e15 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java
@@ -203,6 +203,10 @@
             ProjectProperties buildProperties = ProjectProperties.create(folderPath,
                     PropertyType.BUILD);
             buildProperties.setProperty(ProjectProperties.PROPERTY_APP_PACKAGE, packageName);
+            if (isTestProject == true) {
+                buildProperties.setProperty(ProjectProperties.PROPERTY_TESTED_PROJECT, "..");
+            }
+
             buildProperties.save();
 
             // create the map for place-holders of values to replace in the templates
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java
index 5b35d50..694e285 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java
@@ -46,6 +46,8 @@
 
     public final static String PROPERTY_SPLIT_BY_DENSITY = "split.density";
 
+    public final static String PROPERTY_TESTED_PROJECT = "tested.project.dir";
+
     public static enum PropertyType {
         BUILD("build.properties", BUILD_HEADER),
         DEFAULT("default.properties", DEFAULT_HEADER),