diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutConfigsXsd.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutConfigsXsd.java
new file mode 100755
index 000000000..871020ce0
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutConfigsXsd.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.sdk;
+
+
+import java.io.InputStream;
+
+/**
+ * Public constants for the sdk-repository XML Schema.
+ */
+public class LayoutConfigsXsd {
+
+ /** The XML namespace of the layout-configs XML. */
+ public static final String NS_LAYOUT_CONFIG_XSD =
+ "http://schemas.android.com/sdk/android/layout-configs/1"; //$NON-NLS-1$
+
+ /**
+ * The "layout-configs" element is the root element of this schema.
+ *
+ * It must contain one or more "device" elements that each define the configurations
+ * available for a given device.
+ *
+ * These definitions are used in the Graphical Layout Editor in the
+ * Android Development Tools (ADT) plugin for Eclipse.
+ */
+ public static final String NODE_LAYOUT_CONFIGS = "layout-configs"; //$NON-NLS-1$
+
+ /**
+ * A device element must contain at most one "default" element followed
+ * by one or more ""config" elements.
+ *
+ * The "default" element defines all the default parameters inherited
+ * by the following "config" elements. Each "config" element can override
+ * the default values, if any.
+ *
+ * A "device" element also has a required "name" attribute that represents
+ * the user-interface name of this device.
+ */
+ public static final String NODE_DEVICE = "device"; //$NON-NLS-1$
+
+ /**
+ * The "default" element contains zero or more of all the parameter elements
+ * listed below. It defines all the parameters that are common to all
+ * declared "config" elements.
+ */
+ public static final String NODE_DEFAULT = "default"; //$NON-NLS-1$
+
+ /**
+ * The "config" element contains zero or more of all the parameter elements
+ * listed below. The parameters from the "default" element (if present) are
+ * automatically inherited and can be overridden.
+ */
+ public static final String NODE_CONFIG = "config"; //$NON-NLS-1$
+
+
+ public static final String NODE_SCREEN_SIZE = "screen-size"; //$NON-NLS-1$
+
+ public static final String NODE_SCREEN_RATIO = "screen-ratio"; //$NON-NLS-1$
+
+ public static final String NODE_SCREEN_ORIENTATION = "screen-orientation"; //$NON-NLS-1$
+
+ public static final String NODE_PIXEL_DENSITY = "pixel-density"; //$NON-NLS-1$
+
+ public static final String NODE_TOUCH_TYPE = "touch-type"; //$NON-NLS-1$
+
+ public static final String NODE_KEYBOARD_STATE = "keyboard-state"; //$NON-NLS-1$
+
+ public static final String NODE_TEXT_INPUT_METHOD = "text-input-method"; //$NON-NLS-1$
+
+ public static final String NODE_NAV_METHOD = "nav-method"; //$NON-NLS-1$
+
+ public static final String NODE_SCREEN_DIMENSION = "screen-dimension"; //$NON-NLS-1$
+
+ public static final String NODE_SIZE = "size"; //$NON-NLS-1$
+
+ /**
+ * The "name" attribute, used by both the "device" and the "config"
+ * elements. It represents the user-interface name of these objects.
+ */
+ public static final String ATTR_NAME = "name"; //$NON-NLS-1$
+
+ /**
+ * Helper to get an input stream of the layout config XML schema.
+ */
+ public static InputStream getXsdStream() {
+ return LayoutConfigsXsd.class.getResourceAsStream("layout-configs.xsd"); //$NON-NLS-1$
+ }
+
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-configs.xsd b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-configs.xsd
new file mode 100755
index 000000000..e0452292b
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-configs.xsd
@@ -0,0 +1,209 @@
+
+
+
+
+
+
+
+ The "layout-configs" element is the root element of this schema.
+
+ It must contain one or more "device" elements that each define the configurations
+ available for a given device.
+
+ These definitions are used in the Graphical Layout Editor in the
+ Android Development Tools (ADT) plugin for Eclipse.
+
+
+
+
+
+
+
+
+
+
+ A device element must contain at most one "default" element
+ followed by one or more "config" elements.
+
+ The "default" element defines all the default parameters
+ inherited by the following "config" elements.
+ Each "config" element can override the default values, if any.
+
+ A "device" element also has a required "name" attribute that
+ represents the user-interface name of this device.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The parametersType define all the parameters that can happen either in a
+ "default" element or in a named "config" element.
+ Each parameter element can appear once at most.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The configType defines the content of a "config" element in a "device" element.
+
+ A "config" element can have all the parameters elements defined by
+ "parameterType". It also has a required "name" attribute that indicates the
+ user-interface name for this configuration.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutConfisXsd.java b/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutConfisXsd.java
new file mode 100755
index 000000000..f4ad1bb9b
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutConfisXsd.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.sdk;
+
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import java.io.InputStream;
+import java.io.StringReader;
+
+import javax.xml.XMLConstants;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests local validation of a Layout-Configs sample XMLs using an XML Schema validator.
+ */
+public class TestLayoutConfisXsd extends TestCase {
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * A SAX error handler that captures the errors and warnings.
+ * This allows us to capture *all* errors and just not get an exception on the first one.
+ */
+ private static class CaptureErrorHandler implements ErrorHandler {
+
+ private String mWarnings = "";
+ private String mErrors = "";
+
+ @SuppressWarnings("unused")
+ public String getErrors() {
+ return mErrors;
+ }
+
+ @SuppressWarnings("unused")
+ public String getWarnings() {
+ return mWarnings;
+ }
+
+ /**
+ * Verifies if the handler captures some errors or warnings.
+ * Prints them on stderr.
+ * Also fails the unit test if any error was generated.
+ */
+ public void verify() {
+ if (mWarnings.length() > 0) {
+ System.err.println(mWarnings);
+ }
+
+ if (mErrors.length() > 0) {
+ System.err.println(mErrors);
+ fail(mErrors);
+ }
+ }
+
+ /**
+ * @throws SAXException
+ */
+ public void error(SAXParseException ex) throws SAXException {
+ mErrors += "Error: " + ex.getMessage() + "\n";
+ }
+
+ /**
+ * @throws SAXException
+ */
+ public void fatalError(SAXParseException ex) throws SAXException {
+ mErrors += "Fatal Error: " + ex.getMessage() + "\n";
+ }
+
+ /**
+ * @throws SAXException
+ */
+ public void warning(SAXParseException ex) throws SAXException {
+ mWarnings += "Warning: " + ex.getMessage() + "\n";
+ }
+
+ }
+
+ // --- Helpers ------------
+
+ /** Helper method that returns a validator for our XSD */
+ private Validator getValidator(CaptureErrorHandler handler) throws SAXException {
+ InputStream xsdStream = LayoutConfigsXsd.getXsdStream();
+ SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ Schema schema = factory.newSchema(new StreamSource(xsdStream));
+ Validator validator = schema.newValidator();
+ if (handler != null) {
+ validator.setErrorHandler(handler);
+ }
+
+ return validator;
+ }
+
+ /** Validate a valid sample using an InputStream */
+ public void testValidateLocalRepositoryFile() throws Exception {
+
+ InputStream xmlStream =
+ TestLayoutConfisXsd.class.getResourceAsStream("config_sample.xml");
+ Source source = new StreamSource(xmlStream);
+
+ CaptureErrorHandler handler = new CaptureErrorHandler();
+ Validator validator = getValidator(handler);
+ validator.validate(source);
+ handler.verify();
+ }
+
+ /** An helper that validates a string against an expected regexp. */
+ private void assertRegex(String expectedRegexp, String actualString) {
+ assertNotNull(actualString);
+ assertTrue(
+ String.format("Regexp Assertion Failed:\nExpected: %s\nActual: %s\n",
+ expectedRegexp, actualString),
+ actualString.matches(expectedRegexp));
+ }
+
+ // --- Tests ------------
+
+ /** A document should at least have a root to be valid */
+ public void testEmptyXml() throws Exception {
+ String document = "";
+
+ Source source = new StreamSource(new StringReader(document));
+
+ CaptureErrorHandler handler = new CaptureErrorHandler();
+ Validator validator = getValidator(handler);
+
+ try {
+ validator.validate(source);
+ } catch (SAXParseException e) {
+ // We expect to get this specific exception message
+ assertRegex("Premature end of file.*", e.getMessage());
+ return;
+ }
+ // We shouldn't get here
+ handler.verify();
+ fail();
+ }
+
+ /** A document with an unknown element. */
+ public void testUnknownContentXml() throws Exception {
+ String document = "" +
+ "" +
+ "" +
+ "";
+
+ Source source = new StreamSource(new StringReader(document));
+
+ // don't capture the validator errors, we want it to fail and catch the exception
+ Validator validator = getValidator(null);
+ try {
+ validator.validate(source);
+ } catch (SAXParseException e) {
+ // We expect a parse expression referring to this grammar rule
+ assertRegex("cvc-complex-type.2.4.a: Invalid content was found.*", e.getMessage());
+ return;
+ }
+ // If we get here, the validator has not failed as we expected it to.
+ fail();
+ }
+
+ /** A document with an missing attribute in a device element. */
+ public void testIncompleteContentXml() throws Exception {
+ String document = "" +
+ "" +
+ "" +
+ "";
+
+ Source source = new StreamSource(new StringReader(document));
+
+ // don't capture the validator errors, we want it to fail and catch the exception
+ Validator validator = getValidator(null);
+ try {
+ validator.validate(source);
+ } catch (SAXParseException e) {
+ // We expect a parse error referring to this grammar rule
+ assertRegex("cvc-complex-type.4: Attribute 'name' must appear on element 'd:device'.", e.getMessage());
+ return;
+ }
+ // If we get here, the validator has not failed as we expected it to.
+ fail();
+ }
+
+ /** A document with a root element containing no device element is not valid. */
+ public void testEmptyRootXml() throws Exception {
+ String document = "" +
+ "";
+
+ Source source = new StreamSource(new StringReader(document));
+
+ // don't capture the validator errors, we want it to fail and catch the exception
+ Validator validator = getValidator(null);
+ try {
+ validator.validate(source);
+ } catch (SAXParseException e) {
+ // We expect a parse expression referring to this grammar rule
+ assertRegex("cvc-complex-type.2.4.b: The content of element 'd:layout-configs' is not complete.*", e.getMessage());
+ return;
+ }
+ // If we get here, the validator has not failed as we expected it to.
+ fail();
+ }
+
+ /** A document with an empty device element is not valid. */
+ public void testEmptyDeviceXml() throws Exception {
+ String document = "" +
+ "" +
+ "" +
+ "";
+
+ Source source = new StreamSource(new StringReader(document));
+
+ // don't capture the validator errors, we want it to fail and catch the exception
+ Validator validator = getValidator(null);
+ try {
+ validator.validate(source);
+ } catch (SAXParseException e) {
+ // We expect a parse error referring to this grammar rule
+ assertRegex("cvc-complex-type.2.4.b: The content of element 'd:device' is not complete.*", e.getMessage());
+ return;
+ }
+ // If we get here, the validator has not failed as we expected it to.
+ fail();
+ }
+
+ /** A document with two default elements in a device element is not valid. */
+ public void testTwoDefaultsXml() throws Exception {
+ String document = "" +
+ "" +
+ "" +
+ " " +
+ " " +
+ "" +
+ "";
+
+ Source source = new StreamSource(new StringReader(document));
+
+ // don't capture the validator errors, we want it to fail and catch the exception
+ Validator validator = getValidator(null);
+ try {
+ validator.validate(source);
+ } catch (SAXParseException e) {
+ // We expect a parse error referring to this grammar rule
+ assertRegex("cvc-complex-type.2.4.a: Invalid content was found starting with element 'd:default'.*", e.getMessage());
+ return;
+ }
+ // If we get here, the validator has not failed as we expected it to.
+ fail();
+ }
+
+ /** The default elements must be defined before the config one. It's invalid if after. */
+ public void testDefaultConfigOrderXml() throws Exception {
+ String document = "" +
+ "" +
+ "" +
+ " " +
+ " " +
+ "" +
+ "";
+
+ Source source = new StreamSource(new StringReader(document));
+
+ // don't capture the validator errors, we want it to fail and catch the exception
+ Validator validator = getValidator(null);
+ try {
+ validator.validate(source);
+ } catch (SAXParseException e) {
+ // We expect a parse error referring to this grammar rule
+ assertRegex("cvc-complex-type.2.4.a: Invalid content was found starting with element 'd:default'.*", e.getMessage());
+ return;
+ }
+ // If we get here, the validator has not failed as we expected it to.
+ fail();
+ }
+}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/config_sample.xml b/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/config_sample.xml
new file mode 100755
index 000000000..29f48cd10
--- /dev/null
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/config_sample.xml
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+ small
+ long
+ port
+ ldpi
+ notouch
+ keysexposed
+ nokeys
+ dpad
+
+ 240
+ 480
+
+
+
+
+ keyshidden
+ port
+
+
+ keyshidden
+ land
+
+
+ keysexposed
+ land
+
+
+
+ small
+
+
+ medium
+
+
+ large
+
+
+
+ long
+
+
+ notlong
+
+
+
+ port
+
+
+ land
+
+
+ square
+
+
+
+ ldpi
+
+
+ mdpi
+
+
+ hdpi
+
+
+
+ notouch
+
+
+ stylus
+
+
+ finger
+
+
+
+ nokeys
+
+
+ qwerty
+
+
+ 12key
+
+
+
+ dpad
+
+
+ trackball
+
+
+ wheel
+
+
+ nonav
+
+
+
+
+
+
+
+ medium
+
+
+
+