Added new devices schema

Also updated devices.xml to validate against it.

Change-Id: Ia9b5212b8273e39f7f22022661e2c755c3a9d279
diff --git a/build/product_sdk.mk b/build/product_sdk.mk
index 5646668..bb033ac 100644
--- a/build/product_sdk.mk
+++ b/build/product_sdk.mk
@@ -40,6 +40,7 @@
 	ddms \
 	ddmuilib \
 	draw9patch \
+	dvlib \
 	emulator \
 	hierarchyviewer \
 	ide_common \
diff --git a/build/tools.atree b/build/tools.atree
index 16fdaf5..6ec63c0 100644
--- a/build/tools.atree
+++ b/build/tools.atree
@@ -108,6 +108,7 @@
 framework/lint_api.jar           tools/lib/lint_api.jar
 framework/lint_checks.jar        tools/lib/lint_checks.jar
 framework/manifmerger.jar        tools/lib/manifmerger.jar
+framework/dvlib.jar              tools/lib/dvlib.jar
 
 
 # 3rd Party java libraries
@@ -163,6 +164,7 @@
 framework/sdklib-tests.jar        tests/libtests/sdklib-tests.jar
 framework/sdkuilib-tests.jar      tests/libtests/sdkuilib-tests.jar
 framework/layoutlib_api.jar       tests/libtests/layoutlib_api.jar
+framework/dvlib-tests.jar         tests/libtests/dvlib-tests.jar
 #FIXME breaks build, manifmerger jar files not properly built
 #framework/manifmerger-tests.jar   tests/libtests/manifmerger-tests.jar
 
diff --git a/device_validator/Android.mk b/device_validator/Android.mk
new file mode 100644
index 0000000..9e32461
--- /dev/null
+++ b/device_validator/Android.mk
@@ -0,0 +1,5 @@
+# Copyright 2012 The Android Open Source Project
+
+DEVICE_VALIDATOR_LOCAL_DIR := $(call my-dir)
+include $(DEVICE_VALIDATOR_LOCAL_DIR)/dvlib/Android.mk
+include $(DEVICE_VALIDATOR_LOCAL_DIR)/app/Android.mk
diff --git a/device_validator/MODULE_LICENSE_APACHE2 b/device_validator/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/device_validator/MODULE_LICENSE_APACHE2
diff --git a/device_validator/app/.classpath b/device_validator/app/.classpath
new file mode 100644
index 0000000..a1d7856
--- /dev/null
+++ b/device_validator/app/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/dvlib"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/device_validator/app/.project b/device_validator/app/.project
new file mode 100644
index 0000000..fda9e3d
--- /dev/null
+++ b/device_validator/app/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>device_validator</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/device_validator/app/.settings/org.eclipse.jdt.ui.prefs b/device_validator/app/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..c0fbc32
--- /dev/null
+++ b/device_validator/app/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,3 @@
+#Fri May 25 10:41:24 PDT 2012
+eclipse.preferences.version=1
+formatter_settings_version=11
diff --git a/device_validator/app/Android.mk b/device_validator/app/Android.mk
new file mode 100644
index 0000000..93e6226
--- /dev/null
+++ b/device_validator/app/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2012 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAR_MANIFEST := etc/manifest.txt
+
+LOCAL_JAVA_LIBRARIES := \
+	dvlib
+
+LOCAL_MODULE := device_validator
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Build all sub-directories
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/device_validator/app/etc/Android.mk b/device_validator/app/etc/Android.mk
new file mode 100644
index 0000000..69a948c
--- /dev/null
+++ b/device_validator/app/etc/Android.mk
@@ -0,0 +1,10 @@
+# Copyright 2012 The Android Open Source Project
+#
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_PREBUILT_EXECUTABLES := device_validator
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_PREBUILT)
+
diff --git a/device_validator/app/etc/device_validator b/device_validator/app/etc/device_validator
new file mode 100755
index 0000000..08a1023
--- /dev/null
+++ b/device_validator/app/etc/device_validator
@@ -0,0 +1,79 @@
+#!/bin/bash
+# Copyright 2012, 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.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+    newProg=`/bin/ls -ld "${prog}"`
+    newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+    if expr "x${newProg}" : 'x/' >/dev/null; then
+        prog="${newProg}"
+    else
+        progdir=`dirname "${prog}"`
+        prog="${progdir}/${newProg}"
+    fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+jarfile=device_validator.jar
+frameworkdir="$progdir"
+libdir="$progdir"
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+    frameworkdir=`dirname "$progdir"`/tools/lib
+    libdir=`dirname "$progdir"`/tools/lib
+fi
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+    frameworkdir=`dirname "$progdir"`/framework
+    libdir=`dirname "$progdir"`/lib
+fi
+if [ ! -r "$frameworkdir/$jarfile" ]
+then
+    echo `basename "$prog"`": can't find $jarfile"
+    exit 1
+fi
+
+
+# Check args.
+if [ debug = "$1" ]; then
+    # add this in for debugging
+    java_debug=-agentlib:jdwp=transport=dt_socket,server=y,address=8050,suspend=y
+    shift 1
+else
+    java_debug=
+fi
+
+javaCmd="java"
+
+# Mac OS X needs an additional arg, or you get an "illegal thread" complaint.
+if [ `uname` = "Darwin" ]; then
+    os_opts="-XstartOnFirstThread"
+else
+    os_opts=
+fi
+
+jarpath="$frameworkdir/$jarfile"
+
+exec "$javaCmd" \
+    -Xmx256M $os_opts $java_debug \
+    -classpath "$jarpath" \
+    com.android.validator.DeviceValidator "$@"
diff --git a/device_validator/app/etc/manifest.txt b/device_validator/app/etc/manifest.txt
new file mode 100644
index 0000000..55b9038
--- /dev/null
+++ b/device_validator/app/etc/manifest.txt
@@ -0,0 +1,3 @@
+Main-Class: com.android.validator.DeviceValidator
+Class-Path: dvlib.jar
+
diff --git a/device_validator/app/src/com/android/validator/DeviceValidator.java b/device_validator/app/src/com/android/validator/DeviceValidator.java
new file mode 100644
index 0000000..4b4b16d
--- /dev/null
+++ b/device_validator/app/src/com/android/validator/DeviceValidator.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 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.validator;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+import com.android.dvlib.DeviceSchema;
+
+public class DeviceValidator {
+
+    public static void main(String[] args) {
+        if (args.length == 0){
+            printHelp();
+            System.exit(1);
+        }
+        int ret = 0;
+        for (String a : args) {
+            File f = new File(a);
+            try {
+                if (!DeviceSchema.validate(new FileInputStream(f), System.err, f.getParentFile())) {
+                    System.err.println("Error validating " + f.getAbsolutePath());
+                    System.out.println();
+                    ret = 1;
+                } else {
+                    System.out.println(f.getAbsolutePath() + " validated successfully.");
+                }
+            } catch (FileNotFoundException e) {
+                System.err.println("File not found: " + a);
+                ret = 1;
+            }
+        }
+        System.exit(ret);
+    }
+
+    private static void printHelp() {
+        System.err.printf("Usage: device_validator [files to validate]...\n");
+    }
+
+}
diff --git a/device_validator/dvlib/.classpath b/device_validator/dvlib/.classpath
new file mode 100644
index 0000000..88fb9b4
--- /dev/null
+++ b/device_validator/dvlib/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" path="tests/src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/device_validator/dvlib/.gitignore b/device_validator/dvlib/.gitignore
new file mode 100644
index 0000000..e660fd9
--- /dev/null
+++ b/device_validator/dvlib/.gitignore
@@ -0,0 +1 @@
+bin/
diff --git a/device_validator/dvlib/.project b/device_validator/dvlib/.project
new file mode 100644
index 0000000..13abbdf
--- /dev/null
+++ b/device_validator/dvlib/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>dvlib</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/device_validator/dvlib/Android.mk b/device_validator/dvlib/Android.mk
new file mode 100644
index 0000000..1869adb
--- /dev/null
+++ b/device_validator/dvlib/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2012 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_JAVA_RESOURCE_DIRS := src
+
+LOCAL_MODULE := dvlib
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/device_validator/dvlib/src/com/android/dvlib/DeviceSchema.java b/device_validator/dvlib/src/com/android/dvlib/DeviceSchema.java
new file mode 100644
index 0000000..101baf4
--- /dev/null
+++ b/device_validator/dvlib/src/com/android/dvlib/DeviceSchema.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2012 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.dvlib;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class DeviceSchema {
+
+    public static final String NS_DEVICES_XSD = "http://schemas.android.com/sdk/devices/1";
+
+    /**
+     * The "devices" element is the root element of this schema.
+     *
+     * It must contain one or more "device" elements that each define the
+     * hardware, software, and states for a given device.
+     */
+    public static final String NODE_DEVICES = "devices";
+
+    /**
+     * A "device" element contains a "hardware" element, a "software" element
+     * for each API version it supports, and a "state" element for each possible
+     * state the device could be in.
+     */
+    public static final String NODE_DEVICE = "device";
+
+    /**
+     * The "hardware" element contains all of the hardware information for a
+     * given device.
+     */
+    public static final String NODE_HARDWARE = "hardware";
+
+    /**
+     * The "software" element contains all of the software information for an
+     * API version of the given device.
+     */
+    public static final String NODE_SOFTWARE = "software";
+
+    /**
+     * The "state" element contains all of the parameters for a given state of
+     * the device. It's also capable of redefining hardware configurations if
+     * they change based on state.
+     */
+    public static final String NODE_STATE = "state";
+
+    public static final String NODE_KEYBOARD = "keyboard";
+
+    public static final String NODE_TOUCH = "touch";
+
+    public static final String NODE_GL_EXTENSIONS = "gl-extensions";
+
+    public static final String NODE_GL_VERSION = "gl-version";
+
+    public static final String NODE_NETWORKING = "networking";
+
+    public static final String NODE_REMOVABLE_STORAGE = "removable-storage";
+
+    public static final String NODE_FLASH = "flash";
+
+    public static final String NODE_LIVE_WALLPAPER_SUPPORT = "live-wallpaper-support";
+
+    public static final String NODE_BUTTONS = "buttons";
+
+    public static final String NODE_CAMERA = "camera";
+
+    public static final String NODE_LOCATION = "location";
+
+    public static final String NODE_GPU = "gpu";
+
+    public static final String NODE_DOCK = "dock";
+
+    public static final String NODE_YDPI = "ydpi";
+
+    public static final String NODE_PLUGGED_IN = "plugged-in";
+
+    public static final String NODE_Y_DIMENSION = "y-dimension";
+
+    public static final String NODE_SCREEN_RATIO = "screen-ratio";
+
+    public static final String NODE_NAV_STATE = "nav-state";
+
+    public static final String NODE_HAS_MIC = "has-mic";
+
+    public static final String NODE_RAM = "ram";
+
+    public static final String NODE_XDPI = "xdpi";
+
+    public static final String NODE_DIMENSIONS = "dimensions";
+
+    public static final String NODE_ABI = "abi";
+
+    public static final String NODE_MECHANISM = "mechanism";
+
+    public static final String NODE_MULTITOUCH = "multitouch";
+
+    public static final String NODE_NAV = "nav";
+
+    public static final String NODE_PIXEL_DENSITY = "pixel-density";
+
+    public static final String NODE_SCREEN_ORIENTATION = "screen-orientation";
+
+    public static final String NODE_AUTOFOCUS = "autofocus";
+
+    public static final String NODE_SCREEN_SIZE = "screen-size";
+
+    public static final String NODE_DESCRIPTION = "description";
+
+    public static final String NODE_BLUETOOTH_PROFILES = "bluetooth-profiles";
+
+    public static final String NODE_SCREEN = "screen";
+
+    public static final String NODE_SENSORS = "sensors";
+
+    public static final String NODE_DIAGONAL_LENGTH = "diagonal-length";
+
+    public static final String NODE_SCREEN_TYPE = "screen-type";
+
+    public static final String NODE_KEYBOARD_STATE = "keyboard-state";
+
+    public static final String NODE_X_DIMENSION = "x-dimension";
+
+    public static final String NODE_CPU = "cpu";
+
+    public static final String NODE_INTERNAL_STORAGE = "internal-storage";
+
+    public static final String NODE_META = "meta";
+
+    public static final String NODE_ICONS = "icons";
+
+    public static final String NODE_SIXTY_FOUR = "sixty-four";
+
+    public static final String NODE_SIXTEEN = "sixteen";
+
+    public static final String NODE_FRAME = "frame";
+
+    public static final String NODE_PATH = "path";
+
+    public static final String NODE_PORTRAIT_X_OFFSET = "portrait-x-offset";
+
+    public static final String NODE_PORTRAIT_Y_OFFSET = "portrait-y-offset";
+
+    public static final String NODE_LANDSCAPE_X_OFFSET = "landscape-x-offset";
+
+    public static final String NODE_LANDSCAPE_Y_OFFSET = "landscape-y-offset";
+
+    public static final String NODE_NAME = "name";
+
+    public static final String NODE_API_LEVEL = "api-level";
+
+    public static final String NODE_MANUFACTURER = "manufacturer";
+
+    public static final String ATTR_DEFAULT = "default";
+
+    public static final String ATTR_UNIT = "unit";
+
+    /**
+     * Validates the input stream.
+     *
+     * @param deviceXml
+     *            The XML InputStream to validate.
+     * @param out
+     *            The OutputStream for error messages.
+     * @param parent
+     *            The parent directory of the input stream.
+     * @return Whether the given input constitutes a valid devices file.
+     */
+    public static boolean validate(InputStream deviceXml, OutputStream out, File parent) {
+        Schema s;
+        SAXParserFactory factory = SAXParserFactory.newInstance();
+        PrintWriter writer = new PrintWriter(out);
+        try {
+            s = DeviceSchema.getSchema();
+            factory.setValidating(false);
+            factory.setNamespaceAware(true);
+            factory.setSchema(s);
+            ValidationHandler validator = new ValidationHandler(parent, writer);
+            SAXParser parser = factory.newSAXParser();
+            parser.parse(deviceXml, validator);
+            return validator.isValidDevicesFile();
+        } catch (SAXException e) {
+            writer.println(e.getMessage());
+            return false;
+        } catch (ParserConfigurationException e) {
+            writer.println("Error creating SAX parser:");
+            writer.println(e.getMessage());
+            return false;
+        } catch (IOException e) {
+            writer.println("Error reading file stream:");
+            writer.println(e.getMessage());
+            return false;
+        } finally {
+            writer.flush();
+        }
+    }
+
+    /**
+     * Helper to get an input stream of the device config XML schema.
+     */
+    public static InputStream getXsdStream() {
+        return DeviceSchema.class.getResourceAsStream("devices.xsd"); //$NON-NLS-1$
+    }
+
+    /** Helper method that returns a {@link Validator} for our XSD */
+    public static Schema getSchema() throws SAXException {
+        InputStream xsdStream = getXsdStream();
+        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        Schema schema = factory.newSchema(new StreamSource(xsdStream));
+        return schema;
+    }
+
+    /**
+     * A DefaultHandler that parses only to validate the XML is actually a valid
+     * devices config, since validation can't be entirely encoded in the devices
+     * schema.
+     */
+    private static class ValidationHandler extends DefaultHandler {
+        private boolean mValidDevicesFile = true;
+        private boolean mDefaultSeen = false;
+        private String mDeviceName;
+        private final File mDirectory;
+        private final PrintWriter mWriter;
+        private final StringBuilder mStringAccumulator = new StringBuilder();
+
+        public ValidationHandler(File directory, PrintWriter writer) {
+            mDirectory = directory; // Possibly null
+            mWriter = writer;
+        }
+
+        @Override
+        public void startElement(String uri, String localName, String name, Attributes attributes)
+                throws SAXException {
+            if (NODE_DEVICE.equals(localName)) {
+                // Reset for a new device
+                mDefaultSeen = false;
+            } else if (NODE_STATE.equals(localName)) {
+                // Check if the state is set to be a default state
+                String val = attributes.getValue(ATTR_DEFAULT);
+                if (val != null && ("1".equals(val) || Boolean.parseBoolean(val))) {
+                    /*
+                     * If it is and we already have a default state for this
+                     * device, then the device configuration is invalid.
+                     * Otherwise, set that we've seen a default state for this
+                     * device and continue
+                     */
+
+                    if (mDefaultSeen) {
+                        validationError("More than one default state for device " + mDeviceName);
+                    } else {
+                        mDefaultSeen = true;
+                    }
+                }
+            }
+            mStringAccumulator.setLength(0);
+        }
+
+        @Override
+        public void characters(char[] ch, int start, int length) {
+            mStringAccumulator.append(ch, start, length);
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String name) throws SAXException {
+            // If this is the end of a device node, make sure we have at least
+            // one default state
+            if (NODE_DEVICE.equals(localName) && !mDefaultSeen) {
+                validationError("No default state for device " + mDeviceName);
+            } else if (NODE_NAME.equals(localName)) {
+                mDeviceName = mStringAccumulator.toString().trim();
+            } else if (NODE_PATH.equals(localName) || NODE_SIXTY_FOUR.equals(localName)
+                    || NODE_SIXTEEN.equals(localName)) {
+                if (mDirectory == null) {
+                    // There is no given parent directory, so this is not a
+                    // valid devices file
+                    validationError("No parent directory given, but relative paths exist.");
+                    return;
+                }
+                // This is going to break on any files that end with a space,
+                // but that should be an incredibly rare corner case.
+                String relativePath = mStringAccumulator.toString().trim();
+                File f = new File(mDirectory, relativePath);
+                if (f == null || !f.isFile()) {
+                    validationError(relativePath + " is not a valid path.");
+                    return;
+                }
+                String fileName = f.getName();
+                int extensionStart = fileName.lastIndexOf(".");
+                if (extensionStart == -1 || !fileName.substring(extensionStart + 1).equals("png")) {
+                    validationError(relativePath + " is not a valid file type.");
+                }
+            }
+        }
+
+        @Override
+        public void error(SAXParseException e) {
+            validationError(e.getMessage());
+        }
+
+        @Override
+        public void fatalError(SAXParseException e) {
+            validationError(e.getMessage());
+        }
+
+        public boolean isValidDevicesFile() {
+            return mValidDevicesFile;
+        }
+
+        private void validationError(String reason) {
+            mWriter.println("Error: " + reason);
+            mValidDevicesFile = false;
+        }
+
+    }
+}
diff --git a/device_validator/dvlib/src/com/android/dvlib/devices.xsd b/device_validator/dvlib/src/com/android/dvlib/devices.xsd
new file mode 100644
index 0000000..c3fa482
--- /dev/null
+++ b/device_validator/dvlib/src/com/android/dvlib/devices.xsd
@@ -0,0 +1,884 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Copyright (C) 2012 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.
+-->
+
+<xsd:schema
+    targetNamespace="http://schemas.android.com/sdk/devices/1"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:c="http://schemas.android.com/sdk/devices/1"
+    elementFormDefault="qualified"
+    attributeFormDefault="unqualified"
+    version="1">
+
+    <xsd:element name="devices" type="c:devicesType" />
+
+    <xsd:complexType name="devicesType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                The "devices" element is the root element of this schema.
+
+                It must contain one or more "device" elements that each define the configurations
+                and states available for a given device.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:sequence>
+            <xsd:element name="device" minOccurs="1" maxOccurs="unbounded">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        A device element contains one hardware profile for a device, along with
+                        1 or more software profiles and 1 or more states. Each software profile
+                        defines the supported software for a given API release, and each state
+                        profile defines a different possible state of the device (screen in
+                        portrait orientation, screen in landscape orientation with the keyboard
+                        out, etc.)
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:complexType>
+                    <xsd:sequence>
+                        <xsd:element name="name"         type= "xsd:token" />
+                        <xsd:element name="manufacturer" type= "xsd:token" />
+                        <xsd:element name="meta"         type= "c:metaType"     minOccurs="0" />
+                        <xsd:element name="hardware"     type= "c:hardwareType" />
+                        <xsd:element name="software"     type= "c:softwareType"
+                                     maxOccurs="unbounded" />
+                        <xsd:element name="state"        type= "c:stateType"
+                                     maxOccurs="unbounded" />
+                    </xsd:sequence>
+                </xsd:complexType>
+            </xsd:element>
+        </xsd:sequence>
+    </xsd:complexType>
+
+    <xsd:complexType name="hardwareType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                The hardwareType contains all of the hardware information for
+                a given device. This includes things like the GPU type, screen
+                size, mic presence, etc.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:sequence>
+            <xsd:element name="screen"            type= "c:screenType" />
+            <xsd:element name="networking"        type= "c:networkingType" />
+            <xsd:element name="sensors"           type= "c:sensorsType" />
+            <xsd:element name="mic"               type= "c:micType" />
+            <xsd:element name="camera"            type= "c:cameraType"
+                         minOccurs="0"            maxOccurs="unbounded" />
+            <xsd:element name="keyboard"          type= "c:keyboardType" />
+            <xsd:element name="nav"               type= "c:navType" />
+            <xsd:element name="ram"               type= "c:ramType" />
+            <xsd:element name="buttons"           type= "c:buttonsType" />
+            <xsd:element name="internal-storage"  type= "c:internalStorageType" />
+            <xsd:element name="removable-storage" type= "c:removableStorageType" />
+            <xsd:element name="cpu"               type= "c:cpuType" />
+            <xsd:element name="gpu"               type= "c:gpuType" />
+            <xsd:element name="abi"               type= "c:abiType" />
+            <xsd:element name="dock"              type= "c:dockType" />
+            <xsd:element name="plugged-in"        type= "c:pluggedInType" />
+        </xsd:sequence>
+    </xsd:complexType>
+
+    <xsd:complexType name="softwareType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                The softwareType contains all of the device's software
+                information for a given API version. This includes things like
+                live wallpaper support, OpenGL version, etc.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:sequence>
+            <xsd:element name="api-level">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies which API version(s) this this element is
+                        defining. This can in the form of a single number
+                        or a range of low to high, separated with a dash and
+                        with either limit missing. The default lower limit is
+                        one, and the default upper limit is unbounded.
+                        The following are valid:
+                            10
+                            7-10
+                            -10
+                            7-
+                            -
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:token">
+                        <xsd:pattern value="[\d]*-[\d]*|[\d]+" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+            <xsd:element name="live-wallpaper-support" type="xsd:boolean">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                       Specifies whether the device supports live wallpapers.
+                    </xsd:documentation>
+                </xsd:annotation>
+            </xsd:element>
+
+            <xsd:element name="bluetooth-profiles">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies all of the available Bluetooth profiles.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:list>
+                        <xsd:simpleType>
+                            <xsd:restriction base="xsd:NMTOKEN">
+                                <xsd:enumeration value="A2DP" />
+                                <xsd:enumeration value="ATT" />
+                                <xsd:enumeration value="AVRCP" />
+                                <xsd:enumeration value="AVDTP" />
+                                <xsd:enumeration value="BIP" />
+                                <xsd:enumeration value="BPP" />
+                                <xsd:enumeration value="CIP" />
+                                <xsd:enumeration value="CTP" />
+                                <xsd:enumeration value="DIP" />
+                                <xsd:enumeration value="DUN" />
+                                <xsd:enumeration value="FAX" />
+                                <xsd:enumeration value="FTP" />
+                                <xsd:enumeration value="GAVDP" />
+                                <xsd:enumeration value="GAP" />
+                                <xsd:enumeration value="GATT" />
+                                <xsd:enumeration value="GOEP" />
+                                <xsd:enumeration value="HCRP" />
+                                <xsd:enumeration value="HDP" />
+                                <xsd:enumeration value="HFP" />
+                                <xsd:enumeration value="HID" />
+                                <xsd:enumeration value="HSP" />
+                                <xsd:enumeration value="ICP" />
+                                <xsd:enumeration value="LAP" />
+                                <xsd:enumeration value="MAP" />
+                                <xsd:enumeration value="OPP" />
+                                <xsd:enumeration value="PAN" />
+                                <xsd:enumeration value="PBA" />
+                                <xsd:enumeration value="PBAP" />
+                                <xsd:enumeration value="SPP" />
+                                <xsd:enumeration value="SDAP" />
+                                <xsd:enumeration value="SAP" />
+                                <xsd:enumeration value="SIM" />
+                                <xsd:enumeration value="rSAP" />
+                                <xsd:enumeration value="SYNCH" />
+                                <xsd:enumeration value="VDP" />
+                                <xsd:enumeration value="WAPB" />
+                            </xsd:restriction>
+                        </xsd:simpleType>
+                    </xsd:list>
+                </xsd:simpleType>
+            </xsd:element>
+
+            <xsd:element name="gl-version">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the OpenGL version supported for this release.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:decimal">
+                        <xsd:pattern value="[0-9]\.[0-9]" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
+            <xsd:element name="gl-extensions">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies all of the supported OpenGL extensions for
+                        this release.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:list itemType="xsd:NMTOKEN" />
+                </xsd:simpleType>
+            </xsd:element>
+        </xsd:sequence>
+    </xsd:complexType>
+
+    <xsd:complexType name="stateType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                The stateType contains the information for a given state of
+                of the device. States include things like portrait mode,
+                landscape with the keyboard exposed, etc. States can also
+                modify the hardware attributes of a device. For instance, if
+                sliding out the keyboard increased the available screen
+                real estate, you can define a new screenType to override the
+                default one defined in the device's hardwareType.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:sequence>
+            <xsd:element name="description" type="xsd:token">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        A description of the defined state.
+                    </xsd:documentation>
+                </xsd:annotation>
+            </xsd:element>
+
+            <xsd:element name="screen-orientation">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Defines the orientation of the screen. Use square if
+                        the device's screen has equal height and width,
+                        otherwise use landscape or portrait.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:token">
+                        <xsd:enumeration value="portrait" />
+                        <xsd:enumeration value="landscape" />
+                        <xsd:enumeration value="square" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
+            <xsd:element name="keyboard-state">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Defines the state of the keyboard. If the device has no
+                        keyboard use keysoft, otherwise use keysexposed or keyshidden.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:token">
+                        <xsd:enumeration value="keyssoft" />
+                        <xsd:enumeration value="keyshidden" />
+                        <xsd:enumeration value="keysexposed" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+            <xsd:element name="nav-state">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Defines the state of the primary non-touchscreen
+                        navigation hardware on the devices. If the device
+                        doesn't have non-touchscreen navigation hardware use
+                        nonav, otherwise use navexposed or navhidden.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:token">
+                        <xsd:enumeration value="nonav" />
+                        <xsd:enumeration value="navhidden" />
+                        <xsd:enumeration value="navexposed" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+            <xsd:element name="screen"            type="c:screenType" minOccurs="0" />
+            <xsd:element name="networking"        type="c:networkingType"
+                         minOccurs="0" />
+            <xsd:element name="sensors"           type="c:sensorsType" minOccurs="0" />
+            <xsd:element name="mic"               type="c:micType" minOccurs="0" />
+            <xsd:element name="camera"            type="c:cameraType"
+                         minOccurs="0"            maxOccurs="unbounded" />
+            <xsd:element name="keyboard"          type="c:keyboardType" minOccurs="0" />
+            <xsd:element name="nav"               type="c:navType" minOccurs="0" />
+            <xsd:element name="ram"               type="c:ramType" minOccurs="0" />
+            <xsd:element name="buttons"           type="c:buttonsType" minOccurs="0" />
+            <xsd:element name="internal-storage"  type="c:internalStorageType"
+                         minOccurs="0" />
+            <xsd:element name="removable-storage" type="c:removableStorageType"
+                         minOccurs="0" />
+            <xsd:element name="cpu"               type="c:cpuType" minOccurs="0" />
+            <xsd:element name="gpu"               type="c:gpuType" minOccurs="0" />
+            <xsd:element name="abi"               type="c:abiType" minOccurs="0" />
+            <xsd:element name="dock"              type="c:dockType" minOccurs="0" />
+            <xsd:element name="plugged-in"        type="c:pluggedInType"
+                         minOccurs="0" />
+        </xsd:sequence>
+        <xsd:attribute name="name"    use="required" type="xsd:token" />
+        <xsd:attribute name="default" use="optional" type="xsd:boolean" />
+    </xsd:complexType>
+
+    <xsd:complexType name="metaType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Details where more device information can be found, such as
+                icons and frame images.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:sequence>
+            <xsd:element name="icons" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Contains the relative paths to the icon files for this
+                        device.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:complexType>
+                    <xsd:sequence>
+                        <xsd:element name="sixty-four" type="xsd:normalizedString">
+                            <xsd:annotation>
+                                <xsd:documentation xml:lang="en">
+                                    Relative path for the 64x64 icon.
+                                </xsd:documentation>
+                            </xsd:annotation>
+                        </xsd:element>
+                        <xsd:element name="sixteen" type="xsd:normalizedString"
+                                     minOccurs="0">
+                            <xsd:annotation>
+                                <xsd:documentation xml:lang="en">
+                                    Relative path for the 16x16 icon.
+                                </xsd:documentation>
+                            </xsd:annotation>
+                        </xsd:element>
+                    </xsd:sequence>
+                </xsd:complexType>
+            </xsd:element>
+            <xsd:element name="frame" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Contains information about the frame for the device.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:complexType>
+                    <xsd:sequence>
+                        <xsd:element name="path"
+                                     type="xsd:normalizedString">
+                            <xsd:annotation>
+                                <xsd:documentation xml:lang="en">
+                                    The relative path to the emulator frame for
+                                    the device.
+                                </xsd:documentation>
+                            </xsd:annotation>
+                        </xsd:element>
+                        <xsd:element name="portrait-x-offset"
+                                     type="xsd:nonNegativeInteger">
+                            <xsd:annotation>
+                                <xsd:documentation xml:lang="en">
+                                    The offset for the frame in the x direction,
+                                    in portrait mode.
+                                </xsd:documentation>
+                            </xsd:annotation>
+                        </xsd:element>
+                        <xsd:element name="portrait-y-offset"
+                                     type="xsd:nonNegativeInteger">
+                            <xsd:annotation>
+                                <xsd:documentation xml:lang="en">
+                                    The offset for the frame in the y direction,
+                                    in portrait mode.
+                                </xsd:documentation>
+                            </xsd:annotation>
+                        </xsd:element>
+                        <xsd:element name="landscape-x-offset"
+                                     type="xsd:nonNegativeInteger">
+                            <xsd:annotation>
+                                <xsd:documentation xml:lang="en">
+                                    The offset for the frame in the x direction,
+                                    in landscape mode.
+                                </xsd:documentation>
+                            </xsd:annotation>
+                        </xsd:element>
+                        <xsd:element name="landscape-y-offset"
+                                     type="xsd:nonNegativeInteger">
+                            <xsd:annotation>
+                                <xsd:documentation xml:lang="en">
+                                    The offset for the frame in the y direction,
+                                    in landscape mode.
+                                </xsd:documentation>
+                            </xsd:annotation>
+                        </xsd:element>
+                    </xsd:sequence>
+                </xsd:complexType>
+            </xsd:element>
+        </xsd:sequence>
+    </xsd:complexType>
+
+    <xsd:complexType name="screenType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Contains the specifications for the device's screen.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:sequence>
+            <xsd:element name="screen-size">
+                <xsd:simpleType>
+                    <xsd:annotation>
+                        <xsd:documentation xml:lang="en">
+                            Specifies the class of the screen.
+                        </xsd:documentation>
+                    </xsd:annotation>
+                    <xsd:restriction base="xsd:token">
+                        <xsd:enumeration value="small" />
+                        <xsd:enumeration value="normal" />
+                        <xsd:enumeration value="large" />
+                        <xsd:enumeration value="xlarge" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
+            <xsd:element name="diagonal-length">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the diagonal length of the screen in inches.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:decimal">
+                        <!-- Negative lengths are not valid -->
+                        <xsd:minInclusive value="0" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
+            <xsd:element name="pixel-density">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the screen density of the device. The
+                        medium density of traditional HVGA screens (mdpi)
+                        is defined to be approximately 160dpi; low density
+                        (ldpi) is 120, and high density (hdpi) is 240. There
+                        is thus a 4:3 scaling factor between each density,
+                        so a 9x9 bitmap in ldpi would be 12x12 in mdpi and
+                        16x16 in hdpi.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:token">
+                        <xsd:enumeration value="ldpi" />
+                        <xsd:enumeration value="mdpi" />
+                        <xsd:enumeration value="tvdpi" />
+                        <xsd:enumeration value="hdpi" />
+                        <xsd:enumeration value="xhdpi" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
+            <xsd:element name="screen-ratio">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies whether the configuration is for a taller or
+                        wider than traditional screen. This is based purely on
+                        the aspect ratio of the screen: QVGA, HVGA, and VGA are
+                        notlong; WQVGA, WVGA, FWVGA are long. Note that long may
+                        mean either wide or tall, depending on the current
+                        orientation.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:token">
+                        <xsd:enumeration value="notlong" />
+                        <xsd:enumeration value="long" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
+            <xsd:element name="dimensions">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the device screen resolution in pixels.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:complexType>
+                    <xsd:sequence>
+                        <xsd:element name="x-dimension">
+                            <xsd:annotation>
+                                <xsd:documentation xml:lang="en">
+                                    Specifies the x-dimension's resolution in
+                                    pixels.
+                                </xsd:documentation>
+                            </xsd:annotation>
+                            <xsd:simpleType>
+                                <xsd:restriction base="xsd:positiveInteger" />
+                            </xsd:simpleType>
+                        </xsd:element>
+                        <xsd:element name="y-dimension">
+                            <xsd:annotation>
+                                <xsd:documentation xml:lang="en">
+                                    Specifies the y-dimension's resolution in
+                                    pixels.
+                                </xsd:documentation>
+                            </xsd:annotation>
+                            <xsd:simpleType>
+                                <xsd:restriction base="xsd:positiveInteger" />
+                            </xsd:simpleType>
+                        </xsd:element>
+                    </xsd:sequence>
+                </xsd:complexType>
+            </xsd:element>
+
+            <xsd:element name="xdpi">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the actual density in X of the device screen.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:decimal">
+                        <!-- Negative DPIs are not valid -->
+                        <xsd:minInclusive value="0" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
+            <xsd:element name="ydpi">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the actual density in Y of the device screen.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:decimal">
+                        <!-- Negative DPIs are not valid -->
+                        <xsd:minInclusive value="0" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
+            <xsd:element name="touch">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the touch properties of the device.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:complexType>
+                    <xsd:sequence>
+                        <xsd:element name="multitouch">
+                            <xsd:annotation>
+                                <xsd:documentation xml:lang="en">
+                                    Specifies the multitouch capabilities of the
+                                    device. This can be none if multitouch is
+                                    not supported, basic if the device can track
+                                    only basic two finger gestures, distinct if
+                                    the device can track two or more fingers
+                                    simultaneously, or jazz-hands if the device
+                                    can track 5 or more fingers simultaneously.
+                                </xsd:documentation>
+                            </xsd:annotation>
+                            <xsd:simpleType>
+                                <xsd:restriction base="xsd:token">
+                                    <xsd:enumeration value="none" />
+                                    <xsd:enumeration value="basic" />
+                                    <xsd:enumeration value="distinct" />
+                                    <xsd:enumeration value="jazz-hands" />
+                                </xsd:restriction>
+                            </xsd:simpleType>
+                        </xsd:element>
+
+                        <xsd:element name="mechanism">
+                            <xsd:annotation>
+                                <xsd:documentation xml:lang="en">
+                                    Specifies the mechanism the device was
+                                    created for.
+                                </xsd:documentation>
+                            </xsd:annotation>
+                            <xsd:simpleType>
+                                <xsd:restriction base="xsd:token">
+                                    <xsd:enumeration value="notouch" />
+                                    <xsd:enumeration value="stylus" />
+                                    <xsd:enumeration value="finger" />
+                                </xsd:restriction>
+                            </xsd:simpleType>
+                        </xsd:element>
+
+                        <xsd:element name="screen-type">
+                            <xsd:annotation>
+                                <xsd:documentation xml:lang="en">
+                                    Specifies the type of touch screen on the
+                                    device.
+                                </xsd:documentation>
+                            </xsd:annotation>
+                            <xsd:simpleType>
+                                <xsd:restriction base="xsd:token">
+                                    <xsd:enumeration value="notouch" />
+                                    <xsd:enumeration value="capacitive" />
+                                    <xsd:enumeration value="resistive" />
+                                </xsd:restriction>
+                            </xsd:simpleType>
+                        </xsd:element>
+                    </xsd:sequence>
+                </xsd:complexType>
+            </xsd:element>
+
+        </xsd:sequence>
+    </xsd:complexType>
+
+    <xsd:simpleType name="networkingType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies the available networking hardware.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:list>
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:token">
+                    <xsd:enumeration value="NFC" />
+                    <xsd:enumeration value="Bluetooth" />
+                    <xsd:enumeration value="Wifi" />
+                </xsd:restriction>
+            </xsd:simpleType>
+        </xsd:list>
+    </xsd:simpleType>
+
+    <xsd:simpleType name="sensorsType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies the available sensors.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:list>
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:token">
+                    <xsd:enumeration value="Accelerometer" />
+                    <xsd:enumeration value="Barometer" />
+                    <xsd:enumeration value="Compass" />
+                    <xsd:enumeration value="GPS" />
+                    <xsd:enumeration value="Gyroscope" />
+                    <xsd:enumeration value="LightSensor" />
+                    <xsd:enumeration value="ProximitySensor" />
+                </xsd:restriction>
+            </xsd:simpleType>
+        </xsd:list>
+    </xsd:simpleType>
+
+    <xsd:simpleType name="micType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies whether the device has a mic or not.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:restriction base="xsd:boolean" />
+    </xsd:simpleType>
+
+    <xsd:complexType name="cameraType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies the attributes of the camera.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:sequence>
+            <xsd:element name="location">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the location of the camera.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:token">
+                        <xsd:enumeration value="front" />
+                        <xsd:enumeration value="back" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
+            <xsd:element name="autofocus" type="xsd:boolean">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies whether the camera can autofocus
+                    </xsd:documentation>
+                </xsd:annotation>
+            </xsd:element>
+
+            <xsd:element name="flash" type="xsd:boolean">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies whether the camera has flash.
+                    </xsd:documentation>
+                </xsd:annotation>
+            </xsd:element>
+        </xsd:sequence>
+    </xsd:complexType>
+
+    <xsd:simpleType name="keyboardType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies the type of keyboard on the device.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:restriction base="xsd:token">
+            <xsd:enumeration value="qwerty" />
+            <xsd:enumeration value="12key"  />
+            <xsd:enumeration value="nokeys" />
+        </xsd:restriction>
+    </xsd:simpleType>
+
+    <xsd:simpleType name="navType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies the primary non-touchscreen navigation
+                hardware on the device.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:restriction base="xsd:token">
+            <xsd:enumeration value="dpad" />
+            <xsd:enumeration value="trackball" />
+            <xsd:enumeration value="wheel" />
+            <xsd:enumeration value="nonav" />
+        </xsd:restriction>
+    </xsd:simpleType>
+
+    <xsd:complexType name="ramType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies the amount of RAM on the device in the unit provided.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:simpleContent>
+            <xsd:extension base="xsd:positiveInteger">
+                <xsd:attribute name="unit" type="c:storageUnitType" use="required" />
+            </xsd:extension>
+        </xsd:simpleContent>
+    </xsd:complexType>
+
+    <xsd:simpleType name="buttonsType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies whether the device has physical (hard) buttons
+                (Home, Search, etc.), or uses soft buttons.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:restriction base="xsd:token">
+            <xsd:enumeration value="hard" />
+            <xsd:enumeration value="soft" />
+        </xsd:restriction>
+    </xsd:simpleType>
+
+    <xsd:complexType name="internalStorageType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                A list specifying the sizes of internal storage in
+                the device, in the storage size unit provided.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:simpleContent>
+            <xsd:extension base="c:storageListType">
+                <xsd:attribute name="unit" type="c:storageUnitType"
+                               use="required" />
+            </xsd:extension>
+        </xsd:simpleContent>
+    </xsd:complexType>
+
+    <xsd:complexType name="removableStorageType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies the range of available removable storage sizes
+                in the unit provided. A positive value indicates the device is
+                available with that storage size included while a zero value
+                indicates an empty storage slot.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:simpleContent>
+            <xsd:extension base="c:storageListType">
+                <xsd:attribute name="unit" type="c:storageUnitType"
+                               use="required" />
+            </xsd:extension>
+        </xsd:simpleContent>
+    </xsd:complexType>
+
+    <xsd:simpleType name="storageListType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Defines a list for storage configurations such as internal or
+                removable storage. A positive value indicates the the device
+                has a storage unit of that size, while a zero value indicates
+                there is an empty location for a storage unit (such as an empty
+                SD card slot).
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:list>
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:nonNegativeInteger" />
+            </xsd:simpleType>
+        </xsd:list>
+    </xsd:simpleType>
+    <xsd:simpleType name="gpuType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies the device's GPU.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:restriction base="xsd:token">
+            <xsd:minLength value="1" />
+        </xsd:restriction>
+    </xsd:simpleType>
+
+    <xsd:simpleType name="cpuType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies the device's CPU.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:restriction base="xsd:token">
+            <xsd:minLength value="1" />
+        </xsd:restriction>
+    </xsd:simpleType>
+
+    <xsd:simpleType name="abiType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies which ABIs the device conforms to.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:list>
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:token">
+                    <xsd:enumeration value="armeabi" />
+                    <xsd:enumeration value="armeabi-v7a" />
+                    <xsd:enumeration value="x86" />
+                    <xsd:enumeration value="mips" />
+                </xsd:restriction>
+            </xsd:simpleType>
+        </xsd:list>
+    </xsd:simpleType>
+
+    <xsd:simpleType name="dockType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies the official docks available for the device.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:list>
+            <xsd:simpleType>
+                <xsd:restriction base="xsd:token">
+                    <xsd:enumeration value="desk" />
+                    <xsd:enumeration value="tv" />
+                    <xsd:enumeration value="car" />
+                </xsd:restriction>
+            </xsd:simpleType>
+        </xsd:list>
+    </xsd:simpleType>
+
+    <xsd:simpleType name="pluggedInType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies when the device is plugged in.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:restriction base="xsd:token">
+            <xsd:enumeration value="always" />
+            <xsd:enumeration value="charge" />
+            <xsd:enumeration value="never" />
+        </xsd:restriction>
+    </xsd:simpleType>
+
+    <xsd:simpleType name="storageUnitType">
+        <xsd:annotation>
+            <xsd:documentation xml:lang="en">
+                Specifies the unit of storage. This can be MiB, GiB, etc.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:restriction base="xsd:token">
+            <xsd:enumeration value="B" />
+            <xsd:enumeration value="KiB" />
+            <xsd:enumeration value="MiB" />
+            <xsd:enumeration value="GiB" />
+            <xsd:enumeration value="TiB" />
+        </xsd:restriction>
+    </xsd:simpleType>
+
+</xsd:schema>
diff --git a/device_validator/dvlib/tests/Android.mk b/device_validator/dvlib/tests/Android.mk
new file mode 100644
index 0000000..5094d7a
--- /dev/null
+++ b/device_validator/dvlib/tests/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2012 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_JAVA_RESOURCE_DIRS := src
+
+LOCAL_MODULE := dvlib-tests
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_JAVA_LIBRARIES := \
+	dvlib \
+	junit
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/DeviceSchemaTest.java b/device_validator/dvlib/tests/src/com/android/dvlib/DeviceSchemaTest.java
new file mode 100644
index 0000000..174f27c
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/DeviceSchemaTest.java
@@ -0,0 +1,311 @@
+package com.android.dvlib;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import junit.framework.TestCase;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class DeviceSchemaTest extends TestCase {
+
+    private void checkFailure(Map<String, String> replacements, String regex) throws Exception {
+        // Generate XML stream with replacements
+        InputStream xmlStream = getReplacedStream(replacements);
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        URL location = DeviceSchemaTest.class.getResource(".");
+        File parent = new File(location.toURI());
+        assertFalse(
+                "Validation Assertion Failed, XML failed to validate when it was expected to pass\n",
+                DeviceSchema.validate(xmlStream, baos, parent));
+        assertTrue(String.format("Regex Assertion Failed:\nExpected: %s\nActual: %s\n", regex, baos
+                .toString().trim()), baos.toString().trim().matches(regex));
+    }
+
+    private void checkFailure(String resource, String regex) throws Exception {
+        URL location = DeviceSchemaTest.class.getResource(resource);
+        File xml = new File(location.toURI());
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        assertFalse("Validation Assertion Failed, XML validated when it was expected to fail\n",
+                DeviceSchema.validate(new FileInputStream(xml), baos, xml.getParentFile()));
+        assertTrue(String.format("Regex Assertion Failed:\nExpected: %s\nActual: %s\n", regex, baos
+                .toString().trim()), baos.toString().trim().matches(regex));
+    }
+
+    private void checkSuccess(Map<String, String> replacements) throws Exception {
+        InputStream xmlStream = getReplacedStream(replacements);
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        URL location = DeviceSchemaTest.class.getResource(".");
+        File parent = new File(location.toURI());
+        assertTrue(DeviceSchema.validate(xmlStream, baos, parent));
+        assertTrue(baos.toString().trim().matches(""));
+    }
+
+    private InputStream getReplacedStream(Map<String, String> replacements) throws Exception {
+        URL location = DeviceSchema.class.getResource("devices_minimal.xml");
+        File xml = new File(location.toURI());
+        SAXParserFactory factory = SAXParserFactory.newInstance();
+        factory.setNamespaceAware(true);
+        SAXParser parser = factory.newSAXParser();
+        ReplacementHandler replacer = new ReplacementHandler(replacements);
+        parser.parse(xml, replacer);
+        Document doc = replacer.getGeneratedDocument();
+        Transformer tf = TransformerFactory.newInstance().newTransformer();
+        // Add indents so we're closer to user generated output
+        tf.setOutputProperty(OutputKeys.INDENT, "yes");
+        DOMSource source = new DOMSource(doc);
+        StringWriter out = new StringWriter();
+        StreamResult result = new StreamResult(out);
+        tf.transform(source, result);
+        return new ByteArrayInputStream(out.toString().getBytes("UTF-8"));
+    }
+
+    public void testValidXml() throws Exception {
+        URL location = DeviceSchemaTest.class.getResource("devices.xml");
+        File xml = new File(location.toURI());
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        boolean result = DeviceSchema.validate(new FileInputStream(xml), baos, xml.getParentFile());
+        String output = baos.toString().trim();
+        assertTrue(
+                String.format(
+                        "Validation Assertion Failed, XML failed to validate when it was expected to pass\n%s\n",output), result);
+        assertTrue(String.format("Regex Assertion Failed\nExpected No Output\nActual: %s\n", baos
+                .toString().trim()), baos.toString().trim().matches(""));
+    }
+
+    public void testNoHardware() throws Exception {
+        String regex = "Error: cvc-complex-type.2.4.a: Invalid content was found starting with "
+                + "element 'd:software'.*";
+        checkFailure("devices_no_hardware.xml", regex);
+    }
+
+    public void testNoSoftware() throws Exception {
+        String regex = "Error: cvc-complex-type.2.4.a: Invalid content was found starting with "
+                + "element 'd:state'.*";
+        checkFailure("devices_no_software.xml", regex);
+    }
+
+    public void testNoDefault() throws Exception {
+        String regex = "Error: No default state for device Galaxy Nexus.*";
+        checkFailure("devices_no_default.xml", regex);
+    }
+
+    public void testTooManyDefaults() throws Exception {
+        String regex = "Error: More than one default state for device Galaxy Nexus.*";
+        checkFailure("devices_too_many_defaults.xml", regex);
+    }
+
+    public void testNoStates() throws Exception {
+        String regex = "Error: cvc-complex-type.2.4.b: The content of element 'd:device' is not "
+                + "complete.*\nError: No default state for device Galaxy Nexus.*";
+        checkFailure("devices_no_states.xml", regex);
+    }
+
+    public void testBadMechanism() throws Exception {
+        Map<String, String> replacements = new HashMap<String, String>();
+        replacements.put(DeviceSchema.NODE_MECHANISM, "fanger");
+        checkFailure(replacements, "Error: cvc-enumeration-valid: Value 'fanger' is not "
+                + "facet-valid.*\nError: cvc-type.3.1.3: The value 'fanger' of element "
+                + "'d:mechanism' is not valid.*");
+    }
+
+    public void testNegativeXdpi() throws Exception {
+        Map<String, String> replacements = new HashMap<String, String>();
+        replacements.put(DeviceSchema.NODE_XDPI, "-1.0");
+        checkFailure(replacements, "Error: cvc-minInclusive-valid: Value '-1.0'.*\n"
+                + "Error: cvc-type.3.1.3: The value '-1.0' of element 'd:xdpi' is not valid.*");
+    }
+
+    public void testNegativeYdpi() throws Exception {
+        Map<String, String> replacements = new HashMap<String, String>();
+        replacements.put(DeviceSchema.NODE_YDPI, "-1");
+        checkFailure(replacements, "Error: cvc-minInclusive-valid: Value '-1'.*\n"
+                + "Error: cvc-type.3.1.3: The value '-1' of element 'd:ydpi' is not valid.*");
+
+    }
+
+    public void testNegativeDiagonalLength() throws Exception {
+        Map<String, String> replacements = new HashMap<String, String>();
+        replacements.put(DeviceSchema.NODE_DIAGONAL_LENGTH, "-1.0");
+
+        checkFailure(replacements, "Error: cvc-minInclusive-valid: Value '-1.0'.*\n"
+                + "Error: cvc-type.3.1.3: The value '-1.0' of element 'd:diagonal-length'.*");
+
+    }
+
+    public void testInvalidOpenGLVersion() throws Exception {
+        Map<String, String> replacements = new HashMap<String, String>();
+        replacements.put(DeviceSchema.NODE_GL_VERSION, "2");
+        checkFailure(replacements, "Error: cvc-pattern-valid: Value '2' is not facet-valid.*\n"
+                + "Error: cvc-type.3.1.3: The value '2' of element 'd:gl-version' is not valid.*");
+    }
+
+    public void testInvalidIconTypes() throws Exception {
+        Map<String, String> replacements = new HashMap<String, String>();
+        replacements.put(DeviceSchema.NODE_SIXTEEN, "extras/sixteen.jpeg");
+        replacements.put(DeviceSchema.NODE_SIXTY_FOUR, "extras/sixtyfour.jpeg");
+        replacements.put(DeviceSchema.NODE_PATH, "extras/frame.jpeg");
+        checkFailure(replacements, "Error: extras/sixtyfour.jpeg is not a valid file type.\n"
+                + "Error: extras/sixteen.jpeg is not a valid file type.\n"
+                + "Error: extras/frame.jpeg is not a valid file type.");
+    }
+
+    public void testMissingIcons() throws Exception {
+        Map<String, String> replacements = new HashMap<String, String>();
+        replacements.put(DeviceSchema.NODE_SIXTEEN, "extras/missing");
+        replacements.put(DeviceSchema.NODE_SIXTY_FOUR, "extras/missing");
+        replacements.put(DeviceSchema.NODE_PATH, "extras/missing");
+        checkFailure(replacements, "Error: extras/missing is not a valid path.\n"
+                + "Error: extras/missing is not a valid path.\n"
+                + "Error: extras/missing is not a valid path.");
+    }
+
+    public void testEmptyOpenGLExtensions() throws Exception {
+        Map<String, String> replacements = new HashMap<String, String>();
+        replacements.put(DeviceSchema.NODE_GL_EXTENSIONS, "");
+        checkSuccess(replacements);
+    }
+
+    public void testEmptySensors() throws Exception {
+        Map<String, String> replacements = new HashMap<String, String>();
+        replacements.put(DeviceSchema.NODE_SENSORS, "");
+        checkSuccess(replacements);
+    }
+
+    public void testEmptyNetworking() throws Exception {
+        Map<String, String> replacements = new HashMap<String, String>();
+        replacements.put(DeviceSchema.NODE_NETWORKING, "");
+        checkSuccess(replacements);
+    }
+
+    public void testEmptyCpu() throws Exception {
+        Map<String, String> replacements = new HashMap<String, String>();
+        replacements.put(DeviceSchema.NODE_CPU, "");
+        checkFailure(replacements, "Error: cvc-minLength-valid: Value '' with length = '0'.*\n"
+                + "Error: cvc-type.3.1.3: The value '' of element 'd:cpu' is not valid.*");
+    }
+
+    public void testEmptyGpu() throws Exception {
+        Map<String, String> replacements = new HashMap<String, String>();
+        replacements.put(DeviceSchema.NODE_GPU, "");
+        checkFailure(replacements, "Error: cvc-minLength-valid: Value '' with length = '0'.*\n"
+                + "Error: cvc-type.3.1.3: The value '' of element 'd:gpu' is not valid.*");
+    }
+
+    /**
+     * Reads in a valid devices XML file and if an element tag is in the
+     * replacements map, it replaces its text content with the corresponding
+     * value. Note this has no concept of namespaces or hierarchy, so it will
+     * replace the contents any and all elements with the specified tag name.
+     */
+    private static class ReplacementHandler extends DefaultHandler {
+        private Element mCurrElement = null;
+        private Document mDocument;
+        private final Stack<Element> mElementStack = new Stack<Element>();
+        private final Map<String, String> mPrefixes = new HashMap<String, String>();
+        private final Map<String, String> mReplacements;
+        private final StringBuilder mStringAccumulator = new StringBuilder();
+
+        public ReplacementHandler(Map<String, String> replacements) {
+            mReplacements = replacements;
+        }
+
+        @Override
+        public void startDocument() {
+            try {
+                mDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+            } catch (ParserConfigurationException e) {
+                fail(e.getMessage());
+            }
+        }
+
+        @Override
+        public void startElement(String uri, String localName, String name, Attributes attributes) {
+            Element element = mDocument.createElement(name);
+            for (int i = 0; i < attributes.getLength(); i++) {
+                element.setAttribute(attributes.getQName(i), attributes.getValue(i));
+            }
+            for (String key : mPrefixes.keySet()) {
+                element.setAttribute(XMLConstants.XMLNS_ATTRIBUTE + ":" + key, mPrefixes.get(key));
+            }
+            mPrefixes.clear();
+            if (mCurrElement != null) {
+                mElementStack.push(mCurrElement);
+            }
+            mCurrElement = element;
+        }
+
+        @Override
+        public void startPrefixMapping(String prefix, String uri) throws SAXException {
+            mPrefixes.put(prefix, uri);
+        }
+
+        @Override
+        public void characters(char[] ch, int start, int length) {
+            mStringAccumulator.append(ch, start, length);
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String name) throws SAXException {
+            if (mReplacements.containsKey(localName)) {
+                mCurrElement.appendChild(mDocument.createTextNode(mReplacements.get(localName)));
+            } else {
+                String content = mStringAccumulator.toString().trim();
+                if (!content.isEmpty()) {
+                    mCurrElement.appendChild(mDocument.createTextNode(content));
+                }
+            }
+
+            if (mElementStack.empty()) {
+                mDocument.appendChild(mCurrElement);
+                mCurrElement = null;
+            } else {
+                Element parent = mElementStack.pop();
+                parent.appendChild(mCurrElement);
+                mCurrElement = parent;
+            }
+            mStringAccumulator.setLength(0);
+        }
+
+        @Override
+        public void error(SAXParseException e) {
+            fail(e.getMessage());
+        }
+
+        @Override
+        public void fatalError(SAXParseException e) {
+            fail(e.getMessage());
+        }
+
+        public Document getGeneratedDocument() {
+            return mDocument;
+        }
+
+    }
+}
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/devices.xml b/device_validator/dvlib/tests/src/com/android/dvlib/devices.xml
new file mode 100644
index 0000000..aeb0f04
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/devices.xml
@@ -0,0 +1,290 @@
+<?xml version="1.0"?>
+<d:devices
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:d="http://schemas.android.com/sdk/devices/1">
+
+    <d:device>
+        <d:name>
+            Galaxy Nexus
+        </d:name>
+        <d:manufacturer>
+            Samsung
+        </d:manufacturer>
+        <d:meta>
+            <d:icons>
+                <d:sixty-four>
+                    extras/sixtyfour.png
+                </d:sixty-four>
+                <d:sixteen>
+                    extras/sixteen.png
+                </d:sixteen>
+            </d:icons>
+            <d:frame>
+                <d:path>
+                    extras/frame.png
+                </d:path>
+                <d:portrait-x-offset>0</d:portrait-x-offset>
+                <d:portrait-y-offset>0</d:portrait-y-offset>
+                <d:landscape-x-offset>0</d:landscape-x-offset>
+                <d:landscape-y-offset>0</d:landscape-y-offset>
+            </d:frame>
+        </d:meta>
+        <d:hardware>
+            <d:screen>
+                <d:screen-size>normal</d:screen-size>
+                <d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
+                <d:pixel-density>xhdpi</d:pixel-density>
+                <d:screen-ratio>long</d:screen-ratio>
+                <d:dimensions>
+                    <d:x-dimension>720</d:x-dimension>
+                    <d:y-dimension>1280</d:y-dimension>
+                </d:dimensions>
+                <d:xdpi>316</d:xdpi>
+                <d:ydpi>316</d:ydpi>
+                <d:touch>
+                    <d:multitouch>jazz-hands</d:multitouch>
+                    <d:mechanism>finger</d:mechanism>
+                    <d:screen-type>capacitive</d:screen-type>
+                </d:touch>
+            </d:screen>
+            <d:networking>
+                Bluetooth
+                Wifi
+                NFC
+            </d:networking>
+            <d:sensors>
+                Accelerometer
+                Barometer
+                Gyroscope
+                Compass
+                GPS
+                ProximitySensor
+            </d:sensors>
+            <d:mic>true</d:mic>
+            <d:camera>
+                <d:location>front</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>false</d:flash>
+            </d:camera>
+            <d:camera>
+                <d:location>back</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>true</d:flash>
+            </d:camera>
+            <d:keyboard>nokeys</d:keyboard>
+            <d:nav>nonav</d:nav>
+            <d:ram unit="GiB">1</d:ram>
+            <d:buttons>soft</d:buttons>
+            <d:internal-storage unit="GiB">16</d:internal-storage>
+            <d:removable-storage unit="KiB"></d:removable-storage>
+            <d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
+            <d:gpu>PowerVR SGX540</d:gpu>
+            <d:abi>
+                armeabi
+                armeabi-v7a
+            </d:abi>
+            <!--dock (car, desk, tv, none)-->
+            <d:dock>
+            </d:dock>
+            <!-- plugged in (never, charge, always) -->
+            <d:plugged-in>charge</d:plugged-in>
+        </d:hardware>
+        <d:software>
+            <d:api-level>14-</d:api-level>
+            <d:live-wallpaper-support>true</d:live-wallpaper-support>
+            <d:bluetooth-profiles>
+                HSP
+                HFP
+                SPP
+                A2DP
+                AVRCP
+                OPP
+                PBAP
+                GAVDP
+                AVDTP
+                HID
+                HDP
+                PAN
+            </d:bluetooth-profiles>
+            <d:gl-version>2.0</d:gl-version>
+            <!--
+             These can be gotten via
+             javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
+            -->
+            <d:gl-extensions>
+                GL_EXT_discard_framebuffer
+                GL_EXT_multi_draw_arrays
+                GL_EXT_shader_texture_lod
+                GL_EXT_texture_format_BGRA8888
+                GL_IMG_multisampled_render_to_texture
+                GL_IMG_program_binary
+                GL_IMG_read_format
+                GL_IMG_shader_binary
+                GL_IMG_texture_compression_pvrtc
+                GL_IMG_texture_format_BGRA8888
+                GL_IMG_texture_npot
+                GL_OES_compressed_ETC1_RGB8_texture
+                GL_OES_depth_texture
+                GL_OES_depth24
+                GL_OES_EGL_image
+                GL_OES_EGL_image_external
+                GL_OES_egl_sync
+                GL_OES_element_index_uint
+                GL_OES_fragment_precision_high
+                GL_OES_get_program_binary
+                GL_OES_mapbuffer
+                GL_OES_packed_depth_stencil
+                GL_OES_required_internalformat
+                GL_OES_rgb8_rgba8
+                GL_OES_standard_derivatives
+                GL_OES_texture_float
+                GL_OES_texture_half_float
+                GL_OES_vertex_array_object
+                GL_OES_vertex_half_float
+            </d:gl-extensions>
+        </d:software>
+        <d:state name="Portrait" default="true">
+            <d:description>The phone in portrait view</d:description>
+            <d:screen-orientation>portrait</d:screen-orientation>
+            <d:keyboard-state>keyssoft</d:keyboard-state>
+            <d:nav-state>nonav</d:nav-state>
+        </d:state>
+        <d:state name="Landscape">
+            <d:description>The phone in landscape view</d:description>
+            <d:screen-orientation>landscape</d:screen-orientation>
+            <d:keyboard-state>keyssoft</d:keyboard-state>
+            <d:nav-state>nonav</d:nav-state>
+        </d:state>
+    </d:device>
+    <d:device>
+        <d:name>Droid</d:name>
+        <d:manufacturer>Motorola</d:manufacturer>
+        <d:hardware>
+            <d:screen>
+                <d:screen-size>normal</d:screen-size>
+                <d:diagonal-length>3.7</d:diagonal-length>
+                <d:pixel-density>hdpi</d:pixel-density>
+                <d:screen-ratio>long</d:screen-ratio>
+                <d:dimensions>
+                    <d:x-dimension>480</d:x-dimension>
+                    <d:y-dimension>854</d:y-dimension>
+                </d:dimensions>
+                <d:xdpi>265</d:xdpi>
+                <d:ydpi>265</d:ydpi>
+                <d:touch>
+                    <d:multitouch>distinct</d:multitouch>
+                    <d:mechanism>finger</d:mechanism>
+                    <d:screen-type>capacitive</d:screen-type>
+                </d:touch>
+            </d:screen>
+            <d:networking>
+                Bluetooth
+                Wifi
+                NFC
+            </d:networking>
+            <d:sensors>
+                Accelerometer
+                Barometer
+                Compass
+                GPS
+                ProximitySensor
+                LightSensor
+            </d:sensors>
+            <d:mic>true</d:mic>
+            <d:camera>
+                <d:location>back</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>true</d:flash>
+            </d:camera>
+            <d:keyboard>qwerty</d:keyboard>
+            <d:nav>dpad</d:nav>
+            <d:ram unit="MiB">256</d:ram>
+            <d:buttons>hard</d:buttons>
+            <d:internal-storage unit="MiB">512</d:internal-storage>
+            <d:removable-storage unit="GiB">16</d:removable-storage>
+            <d:cpu>OMAP 3430</d:cpu>
+            <d:gpu>PowerVR SGX 53</d:gpu>
+            <d:abi>
+                armeabi
+                armeabi-v7a
+            </d:abi>
+            <d:dock>
+                car
+                desk
+            </d:dock>
+            <d:plugged-in>charge</d:plugged-in>
+        </d:hardware>
+        <d:software>
+            <d:api-level>5-8</d:api-level>
+            <d:live-wallpaper-support>false</d:live-wallpaper-support>
+            <d:bluetooth-profiles>
+                GAP
+                SPP
+                HSP
+                HFP
+                A2DP
+                AVRCP
+                SDAP
+            </d:bluetooth-profiles>
+            <d:gl-version>1.1</d:gl-version>
+            <!--
+             These can be gotten via
+             javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
+            -->
+            <d:gl-extensions>
+                GL_OES_byte_coordinates
+                GL_OES_fixed_point
+                GL_OES_single_precision
+                GL_OES_matrix_get
+                GL_OES_read_format
+                GL_OES_compressed_paletted_texture
+                GL_OES_point_sprite
+                GL_OES_point_size_array
+                GL_OES_matrix_palette
+                GL_OES_draw_texture
+                GL_OES_query_matrix
+                GL_OES_texture_env_crossbar
+                GL_OES_texture_mirrored_repeat
+                GL_OES_texture_cube_map
+                GL_OES_blend_subtract
+                GL_OES_blend_func_separate
+                GL_OES_blend_equation_separate
+                GL_OES_stencil_wrap
+                GL_OES_extended_matrix_palette
+                GL_OES_framebuffer_object
+                GL_OES_rgb8_rgba8
+                GL_OES_depth24
+                GL_OES_stencil8
+                GL_OES_compressed_ETC1_RGB8_texture
+                GL_OES_mapbuffer
+                GL_OES_EGL_image
+                GL_EXT_multi_draw_arrays
+                GL_OES_required_internalformat
+                GL_IMG_read_format
+                GL_IMG_texture_compression_pvrtc
+                GL_IMG_texture_format_BGRA8888
+                GL_EXT_texture_format_BGRA8888
+                GL_IMG_texture_stream
+                GL_IMG_vertex_program
+            </d:gl-extensions>
+        </d:software>
+        <d:state name="Portrait" default="true">
+            <d:description>The phone in portrait view</d:description>
+            <d:screen-orientation>portrait</d:screen-orientation>
+            <d:keyboard-state>keyshidden</d:keyboard-state>
+            <d:nav-state>navhidden</d:nav-state>
+        </d:state>
+        <d:state name="Landscape, closed">
+            <d:description>The phone in landscape view with the keyboard closed</d:description>
+            <d:screen-orientation>landscape</d:screen-orientation>
+            <d:keyboard-state>keyshidden</d:keyboard-state>
+            <d:nav-state>navhidden</d:nav-state>
+        </d:state>
+        <d:state name="Landscape, open">
+            <d:description>The phone in landscape view with the keyboard open</d:description>
+            <d:screen-orientation>landscape</d:screen-orientation>
+            <d:keyboard-state>keysexposed</d:keyboard-state>
+            <d:nav-state>navexposed</d:nav-state>
+        </d:state>
+    </d:device>
+</d:devices>
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/devices_minimal.xml b/device_validator/dvlib/tests/src/com/android/dvlib/devices_minimal.xml
new file mode 100644
index 0000000..71ab61a
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/devices_minimal.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0"?>
+<d:devices
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:d="http://schemas.android.com/sdk/devices/1">
+
+    <d:device>
+        <d:name>
+            Galaxy Nexus
+        </d:name>
+        <d:manufacturer>
+            Samsung
+        </d:manufacturer>
+        <d:meta>
+            <d:icons>
+                <d:sixty-four>
+                    extras/sixtyfour.png
+                </d:sixty-four>
+                <d:sixteen>
+                    extras/sixteen.png
+                </d:sixteen>
+            </d:icons>
+            <d:frame>
+                <d:path>
+                    extras/frame.png
+                </d:path>
+                <d:portrait-x-offset>0</d:portrait-x-offset>
+                <d:portrait-y-offset>0</d:portrait-y-offset>
+                <d:landscape-x-offset>0</d:landscape-x-offset>
+                <d:landscape-y-offset>0</d:landscape-y-offset>
+            </d:frame>
+        </d:meta>
+        <d:hardware>
+            <d:screen>
+                <d:screen-size>normal</d:screen-size>
+                <d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
+                <d:pixel-density>xhdpi</d:pixel-density>
+                <d:screen-ratio>long</d:screen-ratio>
+                <d:dimensions>
+                    <d:x-dimension>720</d:x-dimension>
+                    <d:y-dimension>1280</d:y-dimension>
+                </d:dimensions>
+                <d:xdpi>316</d:xdpi>
+                <d:ydpi>316</d:ydpi>
+                <d:touch>
+                    <d:multitouch>jazz-hands</d:multitouch>
+                    <d:mechanism>finger</d:mechanism>
+                    <d:screen-type>capacitive</d:screen-type>
+                </d:touch>
+            </d:screen>
+            <d:networking>
+                Bluetooth
+                Wifi
+                NFC
+            </d:networking>
+            <d:sensors>
+                Accelerometer
+                Barometer
+                Gyroscope
+                Compass
+                GPS
+                ProximitySensor
+            </d:sensors>
+            <d:mic>true</d:mic>
+            <d:camera>
+                <d:location>front</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>false</d:flash>
+            </d:camera>
+            <d:camera>
+                <d:location>back</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>true</d:flash>
+            </d:camera>
+            <d:keyboard>nokeys</d:keyboard>
+            <d:nav>nonav</d:nav>
+            <d:ram unit="GiB">1</d:ram>
+            <d:buttons>soft</d:buttons>
+            <d:internal-storage unit="GiB">16</d:internal-storage>
+            <d:removable-storage unit="KiB"></d:removable-storage>
+            <d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
+            <d:gpu>PowerVR SGX540</d:gpu>
+            <d:abi>
+                armeabi
+                armeabi-v7a
+            </d:abi>
+            <!--dock (car, desk, tv, none)-->
+            <d:dock>
+            </d:dock>
+            <!-- plugged in (never, charge, always) -->
+            <d:plugged-in>charge</d:plugged-in>
+        </d:hardware>
+        <d:software>
+            <d:api-level>15</d:api-level>
+            <d:live-wallpaper-support>true</d:live-wallpaper-support>
+            <d:bluetooth-profiles>
+                HSP
+                HFP
+                SPP
+                A2DP
+                AVRCP
+                OPP
+                PBAP
+                GAVDP
+                AVDTP
+                HID
+                HDP
+                PAN
+            </d:bluetooth-profiles>
+            <d:gl-version>2.0</d:gl-version>
+            <d:gl-extensions>
+                GL_EXT_discard_framebuffer
+                GL_EXT_multi_draw_arrays
+                GL_EXT_shader_texture_lod
+                GL_EXT_texture_format_BGRA8888
+                GL_IMG_multisampled_render_to_texture
+                GL_IMG_program_binary
+                GL_IMG_read_format
+                GL_IMG_shader_binary
+                GL_IMG_texture_compression_pvrtc
+                GL_IMG_texture_format_BGRA8888
+                GL_IMG_texture_npot
+                GL_OES_compressed_ETC1_RGB8_texture
+                GL_OES_depth_texture
+                GL_OES_depth24
+                GL_OES_EGL_image
+                GL_OES_EGL_image_external
+                GL_OES_egl_sync
+                GL_OES_element_index_uint
+                GL_OES_fragment_precision_high
+                GL_OES_get_program_binary
+                GL_OES_mapbuffer
+                GL_OES_packed_depth_stencil
+                GL_OES_required_internalformat
+                GL_OES_rgb8_rgba8
+                GL_OES_standard_derivatives
+                GL_OES_texture_float
+                GL_OES_texture_half_float
+                GL_OES_vertex_array_object
+                GL_OES_vertex_half_float
+            </d:gl-extensions>
+        </d:software>
+        <d:state name="Portrait" default="true">
+            <d:description>The phone in portrait view</d:description>
+            <d:screen-orientation>portrait</d:screen-orientation>
+            <d:keyboard-state>keyssoft</d:keyboard-state>
+            <d:nav-state>nonav</d:nav-state>
+        </d:state>
+        <d:state name="Landscape">
+            <d:description>The phone in landscape view</d:description>
+            <d:screen-orientation>landscape</d:screen-orientation>
+            <d:keyboard-state>keyssoft</d:keyboard-state>
+            <d:nav-state>nonav</d:nav-state>
+        </d:state>
+    </d:device>
+</d:devices>
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/devices_no_default.xml b/device_validator/dvlib/tests/src/com/android/dvlib/devices_no_default.xml
new file mode 100644
index 0000000..3ebcedb
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/devices_no_default.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0"?>
+<d:devices
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:d="http://schemas.android.com/sdk/devices/1">
+
+    <d:device>
+        <d:name>
+            Galaxy Nexus
+        </d:name>
+        <d:manufacturer>
+            Samsung
+        </d:manufacturer>
+        <d:hardware>
+            <d:screen>
+                <d:screen-size>normal</d:screen-size>
+                <d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
+                <d:pixel-density>xhdpi</d:pixel-density>
+                <d:screen-ratio>long</d:screen-ratio>
+                <d:dimensions>
+                    <d:x-dimension>720</d:x-dimension>
+                    <d:y-dimension>1280</d:y-dimension>
+                </d:dimensions>
+                <d:xdpi>316</d:xdpi>
+                <d:ydpi>316</d:ydpi>
+                <d:touch>
+                    <d:multitouch>jazz-hands</d:multitouch>
+                    <d:mechanism>finger</d:mechanism>
+                    <d:screen-type>capacitive</d:screen-type>
+                </d:touch>
+            </d:screen>
+            <d:networking>
+                Bluetooth
+                Wifi
+                NFC
+            </d:networking>
+            <d:sensors>
+                Accelerometer
+                Barometer
+                Gyroscope
+                Compass
+                GPS
+                ProximitySensor
+            </d:sensors>
+            <d:mic>true</d:mic>
+            <d:camera>
+                <d:location>front</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>false</d:flash>
+            </d:camera>
+            <d:camera>
+                <d:location>back</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>true</d:flash>
+            </d:camera>
+            <d:keyboard>nokeys</d:keyboard>
+            <d:nav>nonav</d:nav>
+            <d:ram unit="GiB">1</d:ram>
+            <d:buttons>soft</d:buttons>
+            <d:internal-storage unit="GiB">16</d:internal-storage>
+            <d:removable-storage unit="KiB"></d:removable-storage>
+            <d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
+            <d:gpu>PowerVR SGX540</d:gpu>
+            <d:abi>
+                armeabi
+                armeabi-v7a
+            </d:abi>
+            <!--dock (car, desk, tv, none)-->
+            <d:dock>
+            </d:dock>
+            <!-- plugged in (never, charge, always) -->
+            <d:plugged-in>charge</d:plugged-in>
+        </d:hardware>
+        <d:software>
+            <d:api-level>14</d:api-level>
+            <d:live-wallpaper-support>true</d:live-wallpaper-support>
+            <d:bluetooth-profiles>
+                HSP
+                HFP
+                SPP
+                A2DP
+                AVRCP
+                OPP
+                PBAP
+                GAVDP
+                AVDTP
+                HID
+                HDP
+                PAN
+            </d:bluetooth-profiles>
+            <d:gl-version>2.0</d:gl-version>
+            <!--
+             These can be gotten via
+             javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
+            -->
+            <d:gl-extensions>
+                GL_EXT_discard_framebuffer
+                GL_EXT_multi_draw_arrays
+                GL_EXT_shader_texture_lod
+                GL_EXT_texture_format_BGRA8888
+                GL_IMG_multisampled_render_to_texture
+                GL_IMG_program_binary
+                GL_IMG_read_format
+                GL_IMG_shader_binary
+                GL_IMG_texture_compression_pvrtc
+                GL_IMG_texture_format_BGRA8888
+                GL_IMG_texture_npot
+                GL_OES_compressed_ETC1_RGB8_texture
+                GL_OES_depth_texture
+                GL_OES_depth24
+                GL_OES_EGL_image
+                GL_OES_EGL_image_external
+                GL_OES_egl_sync
+                GL_OES_element_index_uint
+                GL_OES_fragment_precision_high
+                GL_OES_get_program_binary
+                GL_OES_mapbuffer
+                GL_OES_packed_depth_stencil
+                GL_OES_required_internalformat
+                GL_OES_rgb8_rgba8
+                GL_OES_standard_derivatives
+                GL_OES_texture_float
+                GL_OES_texture_half_float
+                GL_OES_vertex_array_object
+                GL_OES_vertex_half_float
+            </d:gl-extensions>
+        </d:software>
+        <d:state name="Portrait">
+            <d:description>The phone in portrait view</d:description>
+            <d:screen-orientation>portrait</d:screen-orientation>
+            <d:keyboard-state>keyssoft</d:keyboard-state>
+            <d:nav-state>nonav</d:nav-state>
+        </d:state>
+    </d:device>
+</d:devices>
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/devices_no_hardware.xml b/device_validator/dvlib/tests/src/com/android/dvlib/devices_no_hardware.xml
new file mode 100644
index 0000000..a5c3da1
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/devices_no_hardware.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<d:devices
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:d="http://schemas.android.com/sdk/devices/1">
+
+    <d:device>
+        <d:name>
+            Galaxy Nexus
+        </d:name>
+        <d:manufacturer>
+            Samsung
+        </d:manufacturer>
+        <d:software>
+            <d:api-level>14</d:api-level>
+            <d:live-wallpaper-support>true</d:live-wallpaper-support>
+            <d:bluetooth-profiles>
+                HSP
+                HFP
+                SPP
+                A2DP
+                AVRCP
+                OPP
+                PBAP
+                GAVDP
+                AVDTP
+                HID
+                HDP
+                PAN
+            </d:bluetooth-profiles>
+            <d:gl-version>2.0</d:gl-version>
+            <!--
+             These can be gotten via
+             javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
+            -->
+            <d:gl-extensions>
+                GL_EXT_discard_framebuffer
+                GL_EXT_multi_draw_arrays
+                GL_EXT_shader_texture_lod
+                GL_EXT_texture_format_BGRA8888
+                GL_IMG_multisampled_render_to_texture
+                GL_IMG_program_binary
+                GL_IMG_read_format
+                GL_IMG_shader_binary
+                GL_IMG_texture_compression_pvrtc
+                GL_IMG_texture_format_BGRA8888
+                GL_IMG_texture_npot
+                GL_OES_compressed_ETC1_RGB8_texture
+                GL_OES_depth_texture
+                GL_OES_depth24
+                GL_OES_EGL_image
+                GL_OES_EGL_image_external
+                GL_OES_egl_sync
+                GL_OES_element_index_uint
+                GL_OES_fragment_precision_high
+                GL_OES_get_program_binary
+                GL_OES_mapbuffer
+                GL_OES_packed_depth_stencil
+                GL_OES_required_internalformat
+                GL_OES_rgb8_rgba8
+                GL_OES_standard_derivatives
+                GL_OES_texture_float
+                GL_OES_texture_half_float
+                GL_OES_vertex_array_object
+                GL_OES_vertex_half_float
+            </d:gl-extensions>
+        </d:software>
+        <d:state name="Portrait" default="true">
+            <d:description>The phone in portrait view</d:description>
+            <d:screen-orientation>portrait</d:screen-orientation>
+            <d:keyboard-state>keyssoft</d:keyboard-state>
+            <d:nav-state>nonav</d:nav-state>
+        </d:state>
+        <d:state name="Landscape">
+            <d:description>The phone in landscape view</d:description>
+            <d:screen-orientation>landscape</d:screen-orientation>
+            <d:keyboard-state>keyssoft</d:keyboard-state>
+            <d:nav-state>nonav</d:nav-state>
+        </d:state>
+    </d:device>
+</d:devices>
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/devices_no_software.xml b/device_validator/dvlib/tests/src/com/android/dvlib/devices_no_software.xml
new file mode 100644
index 0000000..899110a
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/devices_no_software.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<d:devices
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:d="http://schemas.android.com/sdk/devices/1">
+
+    <d:device>
+        <d:name>
+            Galaxy Nexus
+        </d:name>
+        <d:manufacturer>
+            Samsung
+        </d:manufacturer>
+        <d:hardware>
+            <d:screen>
+                <d:screen-size>normal</d:screen-size>
+                <d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
+                <d:pixel-density>xhdpi</d:pixel-density>
+                <d:screen-ratio>long</d:screen-ratio>
+                <d:dimensions>
+                    <d:x-dimension>720</d:x-dimension>
+                    <d:y-dimension>1280</d:y-dimension>
+                </d:dimensions>
+                <d:xdpi>316</d:xdpi>
+                <d:ydpi>316</d:ydpi>
+                <d:touch>
+                    <d:multitouch>jazz-hands</d:multitouch>
+                    <d:mechanism>finger</d:mechanism>
+                    <d:screen-type>capacitive</d:screen-type>
+                </d:touch>
+            </d:screen>
+            <d:networking>
+                Bluetooth
+                Wifi
+                NFC
+            </d:networking>
+            <d:sensors>
+                Accelerometer
+                Barometer
+                Gyroscope
+                Compass
+                GPS
+                ProximitySensor
+            </d:sensors>
+            <d:mic>true</d:mic>
+            <d:camera>
+                <d:location>front</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>false</d:flash>
+            </d:camera>
+            <d:camera>
+                <d:location>back</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>true</d:flash>
+            </d:camera>
+            <d:keyboard>nokeys</d:keyboard>
+            <d:nav>nonav</d:nav>
+            <d:ram unit="GiB">1</d:ram>
+            <d:buttons>soft</d:buttons>
+            <d:internal-storage unit="GiB">16</d:internal-storage>
+            <d:removable-storage unit="KiB"></d:removable-storage>
+            <d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
+            <d:gpu>PowerVR SGX540</d:gpu>
+            <d:abi>
+                armeabi
+                armeabi-v7a
+            </d:abi>
+            <!--dock (car, desk, tv, none)-->
+            <d:dock>
+            </d:dock>
+            <!-- plugged in (never, charge, always) -->
+            <d:plugged-in>charge</d:plugged-in>
+        </d:hardware>
+        <d:state name="Portrait" default="true">
+            <d:description>The phone in portrait view</d:description>
+            <d:screen-orientation>portrait</d:screen-orientation>
+            <d:keyboard-state>keyssoft</d:keyboard-state>
+            <d:nav-state>nonav</d:nav-state>
+        </d:state>
+    </d:device>
+</d:devices>
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/devices_no_states.xml b/device_validator/dvlib/tests/src/com/android/dvlib/devices_no_states.xml
new file mode 100644
index 0000000..c4955b4
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/devices_no_states.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0"?>
+<d:devices
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:d="http://schemas.android.com/sdk/devices/1">
+
+    <d:device>
+        <d:name>
+            Galaxy Nexus
+        </d:name>
+        <d:manufacturer>
+            Samsung
+        </d:manufacturer>
+        <d:hardware>
+            <d:screen>
+                <d:screen-size>normal</d:screen-size>
+                <d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
+                <d:pixel-density>xhdpi</d:pixel-density>
+                <d:screen-ratio>long</d:screen-ratio>
+                <d:dimensions>
+                    <d:x-dimension>720</d:x-dimension>
+                    <d:y-dimension>1280</d:y-dimension>
+                </d:dimensions>
+                <d:xdpi>316</d:xdpi>
+                <d:ydpi>316</d:ydpi>
+                <d:touch>
+                    <d:multitouch>jazz-hands</d:multitouch>
+                    <d:mechanism>finger</d:mechanism>
+                    <d:screen-type>capacitive</d:screen-type>
+                </d:touch>
+            </d:screen>
+            <d:networking>
+                Bluetooth
+                Wifi
+                NFC
+            </d:networking>
+            <d:sensors>
+                Accelerometer
+                Barometer
+                Gyroscope
+                Compass
+                GPS
+                ProximitySensor
+            </d:sensors>
+            <d:mic>true</d:mic>
+            <d:camera>
+                <d:location>front</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>false</d:flash>
+            </d:camera>
+            <d:camera>
+                <d:location>back</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>true</d:flash>
+            </d:camera>
+            <d:keyboard>nokeys</d:keyboard>
+            <d:nav>nonav</d:nav>
+            <d:ram unit="GiB">1</d:ram>
+            <d:buttons>soft</d:buttons>
+            <d:internal-storage unit="GiB">16</d:internal-storage>
+            <d:removable-storage unit="KiB"></d:removable-storage>
+            <d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
+            <d:gpu>PowerVR SGX540</d:gpu>
+            <d:abi>
+                armeabi
+                armeabi-v7a
+            </d:abi>
+            <!--dock (car, desk, tv, none)-->
+            <d:dock>
+            </d:dock>
+            <!-- plugged in (never, charge, always) -->
+            <d:plugged-in>charge</d:plugged-in>
+        </d:hardware>
+        <d:software>
+            <d:api-level>14</d:api-level>
+            <d:live-wallpaper-support>true</d:live-wallpaper-support>
+            <d:bluetooth-profiles>
+                HSP
+                HFP
+                SPP
+                A2DP
+                AVRCP
+                OPP
+                PBAP
+                GAVDP
+                AVDTP
+                HID
+                HDP
+                PAN
+            </d:bluetooth-profiles>
+            <d:gl-version>2.0</d:gl-version>
+            <!--
+             These can be gotten via
+             javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
+            -->
+            <d:gl-extensions>
+                GL_EXT_discard_framebuffer
+                GL_EXT_multi_draw_arrays
+                GL_EXT_shader_texture_lod
+                GL_EXT_texture_format_BGRA8888
+                GL_IMG_multisampled_render_to_texture
+                GL_IMG_program_binary
+                GL_IMG_read_format
+                GL_IMG_shader_binary
+                GL_IMG_texture_compression_pvrtc
+                GL_IMG_texture_format_BGRA8888
+                GL_IMG_texture_npot
+                GL_OES_compressed_ETC1_RGB8_texture
+                GL_OES_depth_texture
+                GL_OES_depth24
+                GL_OES_EGL_image
+                GL_OES_EGL_image_external
+                GL_OES_egl_sync
+                GL_OES_element_index_uint
+                GL_OES_fragment_precision_high
+                GL_OES_get_program_binary
+                GL_OES_mapbuffer
+                GL_OES_packed_depth_stencil
+                GL_OES_required_internalformat
+                GL_OES_rgb8_rgba8
+                GL_OES_standard_derivatives
+                GL_OES_texture_float
+                GL_OES_texture_half_float
+                GL_OES_vertex_array_object
+                GL_OES_vertex_half_float
+            </d:gl-extensions>
+        </d:software>
+    </d:device>
+</d:devices>
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/devices_too_many_defaults.xml b/device_validator/dvlib/tests/src/com/android/dvlib/devices_too_many_defaults.xml
new file mode 100644
index 0000000..a4e464c
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/devices_too_many_defaults.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0"?>
+<d:devices
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:d="http://schemas.android.com/sdk/devices/1">
+
+    <d:device>
+        <d:name>
+            Galaxy Nexus
+        </d:name>
+        <d:manufacturer>
+            Samsung
+        </d:manufacturer>
+        <d:hardware>
+            <d:screen>
+                <d:screen-size>normal</d:screen-size>
+                <d:diagonal-length>4.65</d:diagonal-length> <!-- In inches -->
+                <d:pixel-density>xhdpi</d:pixel-density>
+                <d:screen-ratio>long</d:screen-ratio>
+                <d:dimensions>
+                    <d:x-dimension>720</d:x-dimension>
+                    <d:y-dimension>1280</d:y-dimension>
+                </d:dimensions>
+                <d:xdpi>316</d:xdpi>
+                <d:ydpi>316</d:ydpi>
+                <d:touch>
+                    <d:multitouch>jazz-hands</d:multitouch>
+                    <d:mechanism>finger</d:mechanism>
+                    <d:screen-type>capacitive</d:screen-type>
+                </d:touch>
+            </d:screen>
+            <d:networking>
+                Bluetooth
+                Wifi
+                NFC
+            </d:networking>
+            <d:sensors>
+                Accelerometer
+                Barometer
+                Gyroscope
+                Compass
+                GPS
+                ProximitySensor
+            </d:sensors>
+            <d:mic>true</d:mic>
+            <d:camera>
+                <d:location>front</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>false</d:flash>
+            </d:camera>
+            <d:camera>
+                <d:location>back</d:location>
+                <d:autofocus>true</d:autofocus>
+                <d:flash>true</d:flash>
+            </d:camera>
+            <d:keyboard>nokeys</d:keyboard>
+            <d:nav>nonav</d:nav>
+            <d:ram unit="GiB">1</d:ram>
+            <d:buttons>soft</d:buttons>
+            <d:internal-storage unit="GiB">16</d:internal-storage>
+            <d:removable-storage unit="KiB"></d:removable-storage>
+            <d:cpu>OMAP 4460</d:cpu> <!-- cpu type (Tegra3) freeform -->
+            <d:gpu>PowerVR SGX540</d:gpu>
+            <d:abi>
+                armeabi
+                armeabi-v7a
+            </d:abi>
+            <!--dock (car, desk, tv, none)-->
+            <d:dock>
+            </d:dock>
+            <!-- plugged in (never, charge, always) -->
+            <d:plugged-in>charge</d:plugged-in>
+        </d:hardware>
+        <d:software>
+            <d:api-level>14</d:api-level>
+            <d:live-wallpaper-support>true</d:live-wallpaper-support>
+            <d:bluetooth-profiles>
+                HSP
+                HFP
+                SPP
+                A2DP
+                AVRCP
+                OPP
+                PBAP
+                GAVDP
+                AVDTP
+                HID
+                HDP
+                PAN
+            </d:bluetooth-profiles>
+            <d:gl-version>2.0</d:gl-version>
+            <!--
+             These can be gotten via
+             javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
+            -->
+            <d:gl-extensions>
+                GL_EXT_discard_framebuffer
+                GL_EXT_multi_draw_arrays
+                GL_EXT_shader_texture_lod
+                GL_EXT_texture_format_BGRA8888
+                GL_IMG_multisampled_render_to_texture
+                GL_IMG_program_binary
+                GL_IMG_read_format
+                GL_IMG_shader_binary
+                GL_IMG_texture_compression_pvrtc
+                GL_IMG_texture_format_BGRA8888
+                GL_IMG_texture_npot
+                GL_OES_compressed_ETC1_RGB8_texture
+                GL_OES_depth_texture
+                GL_OES_depth24
+                GL_OES_EGL_image
+                GL_OES_EGL_image_external
+                GL_OES_egl_sync
+                GL_OES_element_index_uint
+                GL_OES_fragment_precision_high
+                GL_OES_get_program_binary
+                GL_OES_mapbuffer
+                GL_OES_packed_depth_stencil
+                GL_OES_required_internalformat
+                GL_OES_rgb8_rgba8
+                GL_OES_standard_derivatives
+                GL_OES_texture_float
+                GL_OES_texture_half_float
+                GL_OES_vertex_array_object
+                GL_OES_vertex_half_float
+            </d:gl-extensions>
+        </d:software>
+        <d:state name="Portrait" default="true">
+            <d:description>The phone in portrait view</d:description>
+            <d:screen-orientation>portrait</d:screen-orientation>
+            <d:keyboard-state>keyssoft</d:keyboard-state>
+            <d:nav-state>nonav</d:nav-state>
+        </d:state>
+        <d:state name="Landscape" default="true">
+            <d:description>The phone in landscape view</d:description>
+            <d:screen-orientation>landscape</d:screen-orientation>
+            <d:keyboard-state>keyssoft</d:keyboard-state>
+            <d:nav-state>nonav</d:nav-state>
+        </d:state>
+    </d:device>
+</d:devices>
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/extras/frame.jpeg b/device_validator/dvlib/tests/src/com/android/dvlib/extras/frame.jpeg
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/extras/frame.jpeg
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/extras/frame.png b/device_validator/dvlib/tests/src/com/android/dvlib/extras/frame.png
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/extras/frame.png
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/extras/sixteen.jpeg b/device_validator/dvlib/tests/src/com/android/dvlib/extras/sixteen.jpeg
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/extras/sixteen.jpeg
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/extras/sixteen.png b/device_validator/dvlib/tests/src/com/android/dvlib/extras/sixteen.png
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/extras/sixteen.png
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/extras/sixtyfour.jpeg b/device_validator/dvlib/tests/src/com/android/dvlib/extras/sixtyfour.jpeg
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/extras/sixtyfour.jpeg
diff --git a/device_validator/dvlib/tests/src/com/android/dvlib/extras/sixtyfour.png b/device_validator/dvlib/tests/src/com/android/dvlib/extras/sixtyfour.png
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/device_validator/dvlib/tests/src/com/android/dvlib/extras/sixtyfour.png