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),