Add save/load for the user-made Layout Devices.

Also added support for mcc/mnc in the schema.

Change-Id: I8a2d23797ec57eec69dc1d7218b01cd679634068
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java
index 8c37cc6..b6f9a09 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java
@@ -591,6 +591,9 @@
                 ConfigManagerDialog dialog = new ConfigManagerDialog(getShell());
                 dialog.open();
 
+                // save the user devices
+                Sdk.getCurrent().getLayoutDeviceManager().save();
+
                 // reload the combo with the new content.
                 loadDevices();
                 initUiWithDevices();
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/CountryCodeQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/CountryCodeQualifier.java
index f570bac..97028e9 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/CountryCodeQualifier.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/CountryCodeQualifier.java
@@ -33,7 +33,7 @@
 
     private final static Pattern sCountryCodePattern = Pattern.compile("^mcc(\\d{3})$");//$NON-NLS-1$
 
-    private int mCode = DEFAULT_CODE;
+    private final int mCode;
 
     public static final String NAME = "Mobile Country Code";
 
@@ -56,8 +56,7 @@
                 return null;
             }
 
-            CountryCodeQualifier qualifier = new CountryCodeQualifier();
-            qualifier.mCode = code;
+            CountryCodeQualifier qualifier = new CountryCodeQualifier(code);
             return qualifier;
         }
 
@@ -77,6 +76,14 @@
         return ""; //$NON-NLS-1$
     }
 
+    public CountryCodeQualifier() {
+        this(DEFAULT_CODE);
+    }
+
+    public CountryCodeQualifier(int code) {
+        mCode = code;
+    }
+
     public int getCode() {
         return mCode;
     }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NetworkCodeQualifier.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NetworkCodeQualifier.java
index 32bd667..655fe4e 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NetworkCodeQualifier.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/configurations/NetworkCodeQualifier.java
@@ -33,7 +33,7 @@
 
     private final static Pattern sNetworkCodePattern = Pattern.compile("^mnc(\\d{1,3})$"); //$NON-NLS-1$
 
-    private int mCode = DEFAULT_CODE;
+    private final int mCode;
 
     public final static String NAME = "Mobile Network Code";
 
@@ -56,8 +56,7 @@
                 return null;
             }
 
-            NetworkCodeQualifier qualifier = new NetworkCodeQualifier();
-            qualifier.mCode = code;
+            NetworkCodeQualifier qualifier = new NetworkCodeQualifier(code);
             return qualifier;
         }
 
@@ -77,6 +76,14 @@
         return ""; //$NON-NLS-1$
     }
 
+    public NetworkCodeQualifier() {
+        this(DEFAULT_CODE);
+    }
+
+    public NetworkCodeQualifier(int code) {
+        mCode = code;
+    }
+
     public int getCode() {
         return mCode;
     }
@@ -115,8 +122,7 @@
                 return false;
             }
 
-            NetworkCodeQualifier qualifier = new NetworkCodeQualifier();
-            qualifier.mCode = code;
+            NetworkCodeQualifier qualifier = new NetworkCodeQualifier(code);
             config.setNetworkCodeQualifier(qualifier);
             return true;
         }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDevice.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDevice.java
index 89cac5b..9e80103 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDevice.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDevice.java
@@ -16,11 +16,26 @@
 
 package com.android.ide.eclipse.adt.internal.sdk;
 
+import com.android.ide.eclipse.adt.internal.resources.configurations.CountryCodeQualifier;
 import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
+import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.NetworkCodeQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenDimensionQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenRatioQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenSizeQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMethodQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Map.Entry;
 
 /**
  * Class representing a layout device.
@@ -53,6 +68,138 @@
         mName = name;
     }
 
+    /**
+     * Saves the Layout Device into a document under a given node
+     * @param doc the document.
+     * @param parentNode the parent node.
+     */
+    void saveTo(Document doc, Element parentNode) {
+        // create the device node
+        Element deviceNode = createNode(doc, parentNode, LayoutDevicesXsd.NODE_DEVICE);
+
+        // create the name attribute (no namespace on this one).
+        deviceNode.setAttribute(LayoutDevicesXsd.ATTR_NAME, mName);
+
+        // create a default with the x/y dpi
+        Element defaultNode = createNode(doc, deviceNode, LayoutDevicesXsd.NODE_DEFAULT);
+        if (Float.isNaN(mXDpi) == false) {
+            Element xdpiNode = createNode(doc, defaultNode, LayoutDevicesXsd.NODE_XDPI);
+            xdpiNode.setTextContent(Float.toString(mXDpi));
+        }
+        if (Float.isNaN(mYDpi) == false) {
+            Element xdpiNode = createNode(doc, defaultNode, LayoutDevicesXsd.NODE_YDPI);
+            xdpiNode.setTextContent(Float.toString(mYDpi));
+        }
+
+        // then save all the configs.
+        for (Entry<String, FolderConfiguration> entry : mEditMap.entrySet()) {
+            saveConfigTo(doc, deviceNode, entry.getKey(), entry.getValue());
+        }
+    }
+
+    /**
+     * Creates and returns a new NS-enabled node.
+     * @param doc the {@link Document}
+     * @param parentNode the parent node. The new node is appended to this one as a child.
+     * @param name the name of the node.
+     * @return the newly created node.
+     */
+    private Element createNode(Document doc, Element parentNode, String name) {
+        Element newNode = doc.createElementNS(
+                LayoutDevicesXsd.NS_LAYOUT_DEVICE_XSD, name);
+        newNode.setPrefix(doc.lookupPrefix(LayoutDevicesXsd.NS_LAYOUT_DEVICE_XSD));
+        parentNode.appendChild(newNode);
+
+        return newNode;
+    }
+
+    /**
+     * Saves a {@link FolderConfiguration} in a {@link Document}.
+     * @param doc the Document in which to save
+     * @param parent the parent node
+     * @param configName the name of the config
+     * @param config the config to save
+     */
+    private void saveConfigTo(Document doc, Element parent, String configName,
+            FolderConfiguration config) {
+        Element configNode = createNode(doc, parent, LayoutDevicesXsd.NODE_CONFIG);
+
+        // create the name attribute (no namespace on this one).
+        configNode.setAttribute(LayoutDevicesXsd.ATTR_NAME, configName);
+
+        // now do the qualifiers
+        CountryCodeQualifier ccq = config.getCountryCodeQualifier();
+        if (ccq != null) {
+            Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_COUNTRY_CODE);
+            node.setTextContent(Integer.toString(ccq.getCode()));
+        }
+
+        NetworkCodeQualifier ncq = config.getNetworkCodeQualifier();
+        if (ncq != null) {
+            Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_NETWORK_CODE);
+            node.setTextContent(Integer.toString(ncq.getCode()));
+        }
+
+        ScreenSizeQualifier ssq = config.getScreenSizeQualifier();
+        if (ssq != null) {
+            Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_SCREEN_SIZE);
+            node.setTextContent(ssq.getFolderSegment(null));
+        }
+
+        ScreenRatioQualifier srq = config.getScreenRatioQualifier();
+        if (srq != null) {
+            Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_SCREEN_RATIO);
+            node.setTextContent(srq.getFolderSegment(null));
+        }
+
+        ScreenOrientationQualifier soq = config.getScreenOrientationQualifier();
+        if (soq != null) {
+            Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_SCREEN_ORIENTATION);
+            node.setTextContent(soq.getFolderSegment(null));
+        }
+
+        PixelDensityQualifier pdq = config.getPixelDensityQualifier();
+        if (pdq != null) {
+            Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_PIXEL_DENSITY);
+            node.setTextContent(pdq.getFolderSegment(null));
+        }
+
+        TouchScreenQualifier ttq = config.getTouchTypeQualifier();
+        if (ttq != null) {
+            Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_TOUCH_TYPE);
+            node.setTextContent(ttq.getFolderSegment(null));
+        }
+
+        KeyboardStateQualifier ksq = config.getKeyboardStateQualifier();
+        if (ksq != null) {
+            Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_KEYBOARD_STATE);
+            node.setTextContent(ksq.getFolderSegment(null));
+        }
+
+        TextInputMethodQualifier timq = config.getTextInputMethodQualifier();
+        if (timq != null) {
+            Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_TEXT_INPUT_METHOD);
+            node.setTextContent(timq.getFolderSegment(null));
+        }
+
+        NavigationMethodQualifier nmq = config.getNavigationMethodQualifier();
+        if (nmq != null) {
+            Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_NAV_METHOD);
+            node.setTextContent(nmq.getFolderSegment(null));
+        }
+
+        ScreenDimensionQualifier sdq = config.getScreenDimensionQualifier();
+        if (sdq != null) {
+            Element sizeNode = createNode(doc, configNode, LayoutDevicesXsd.NODE_SCREEN_DIMENSION);
+
+            Element node = createNode(doc, sizeNode, LayoutDevicesXsd.NODE_SIZE);
+            node.setTextContent(Integer.toString(sdq.getValue1()));
+
+            node = createNode(doc, sizeNode, LayoutDevicesXsd.NODE_SIZE);
+            node.setTextContent(Integer.toString(sdq.getValue2()));
+        }
+    }
+
     void addConfig(String name, FolderConfiguration config) {
         mEditMap.put(name, config);
         _seal();
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceHandler.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceHandler.java
index bb9a13d..7ad4e5d 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceHandler.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceHandler.java
@@ -16,9 +16,11 @@
 
 package com.android.ide.eclipse.adt.internal.sdk;
 
+import com.android.ide.eclipse.adt.internal.resources.configurations.CountryCodeQualifier;
 import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
 import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier;
 import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier;
+import com.android.ide.eclipse.adt.internal.resources.configurations.NetworkCodeQualifier;
 import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier;
 import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenDimensionQualifier;
 import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier;
@@ -44,7 +46,7 @@
 
 /**
  * {@link DefaultHandler} implementation to parse Layout Device XML file.
- * @see LayoutConfigsXsd
+ * @see LayoutDevicesXsd
  * @see Layout-configs.xsd
  */
 class LayoutDeviceHandler extends DefaultHandler {
@@ -74,17 +76,17 @@
     @Override
     public void startElement(String uri, String localName, String name, Attributes attributes)
             throws SAXException {
-        if (LayoutConfigsXsd.NODE_DEVICE.equals(localName)) {
+        if (LayoutDevicesXsd.NODE_DEVICE.equals(localName)) {
             // get the deviceName, will not be null since we validated the XML.
-            String deviceName = attributes.getValue("", LayoutConfigsXsd.ATTR_NAME);
+            String deviceName = attributes.getValue("", LayoutDevicesXsd.ATTR_NAME);
 
             // create a device and add it to the list
             mCurrentDevice = new LayoutDevice(deviceName);
             mDevices.add(mCurrentDevice);
-        } else if (LayoutConfigsXsd.NODE_DEFAULT.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_DEFAULT.equals(localName)) {
             // create a new default config
             mDefaultConfig = mCurrentConfig = new FolderConfiguration();
-        } else if (LayoutConfigsXsd.NODE_CONFIG.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_CONFIG.equals(localName)) {
             // create a new config
             mCurrentConfig = new FolderConfiguration();
 
@@ -94,11 +96,11 @@
             }
 
             // get the name of the config
-            String deviceName = attributes.getValue("", LayoutConfigsXsd.ATTR_NAME);
+            String deviceName = attributes.getValue("", LayoutDevicesXsd.ATTR_NAME);
 
             // give it to the current device.
             mCurrentDevice.addConfig(deviceName, mCurrentConfig);
-        } else if (LayoutConfigsXsd.NODE_SCREEN_DIMENSION.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_SCREEN_DIMENSION.equals(localName)) {
             mSize1 = mSize2 = null;
         }
 
@@ -112,53 +114,61 @@
 
     @Override
     public void endElement(String uri, String localName, String name) throws SAXException {
-        if (LayoutConfigsXsd.NODE_DEVICE.equals(localName)) {
+        if (LayoutDevicesXsd.NODE_DEVICE.equals(localName)) {
             mCurrentDevice = null;
             mDefaultConfig = null;
-        } else if (LayoutConfigsXsd.NODE_CONFIG.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_CONFIG.equals(localName)) {
             mCurrentConfig = null;
-        } else if (LayoutConfigsXsd.NODE_SCREEN_SIZE.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_COUNTRY_CODE.equals(localName)) {
+            CountryCodeQualifier ccq = new CountryCodeQualifier(
+                    Integer.parseInt(mStringAccumulator.toString()));
+            mCurrentConfig.setCountryCodeQualifier(ccq);
+        } else if (LayoutDevicesXsd.NODE_NETWORK_CODE.equals(localName)) {
+            NetworkCodeQualifier ncq = new NetworkCodeQualifier(
+                    Integer.parseInt(mStringAccumulator.toString()));
+            mCurrentConfig.setNetworkCodeQualifier(ncq);
+        } else if (LayoutDevicesXsd.NODE_SCREEN_SIZE.equals(localName)) {
             ScreenSizeQualifier ssq = new ScreenSizeQualifier(
                     ScreenSize.getEnum(mStringAccumulator.toString()));
             mCurrentConfig.setScreenSizeQualifier(ssq);
-        } else if (LayoutConfigsXsd.NODE_SCREEN_RATIO.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_SCREEN_RATIO.equals(localName)) {
             ScreenRatioQualifier srq = new ScreenRatioQualifier(
                     ScreenRatio.getEnum(mStringAccumulator.toString()));
             mCurrentConfig.setScreenRatioQualifier(srq);
-        } else if (LayoutConfigsXsd.NODE_SCREEN_ORIENTATION.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_SCREEN_ORIENTATION.equals(localName)) {
             ScreenOrientationQualifier soq = new ScreenOrientationQualifier(
                     ScreenOrientation.getEnum(mStringAccumulator.toString()));
             mCurrentConfig.setScreenOrientationQualifier(soq);
-        } else if (LayoutConfigsXsd.NODE_PIXEL_DENSITY.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_PIXEL_DENSITY.equals(localName)) {
             PixelDensityQualifier pdq = new PixelDensityQualifier(
                     Density.getEnum(mStringAccumulator.toString()));
             mCurrentConfig.setPixelDensityQualifier(pdq);
-        } else if (LayoutConfigsXsd.NODE_TOUCH_TYPE.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_TOUCH_TYPE.equals(localName)) {
             TouchScreenQualifier tsq = new TouchScreenQualifier(
                     TouchScreenType.getEnum(mStringAccumulator.toString()));
             mCurrentConfig.setTouchTypeQualifier(tsq);
-        } else if (LayoutConfigsXsd.NODE_KEYBOARD_STATE.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_KEYBOARD_STATE.equals(localName)) {
             KeyboardStateQualifier ksq = new KeyboardStateQualifier(
                     KeyboardState.getEnum(mStringAccumulator.toString()));
             mCurrentConfig.setKeyboardStateQualifier(ksq);
-        } else if (LayoutConfigsXsd.NODE_TEXT_INPUT_METHOD.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_TEXT_INPUT_METHOD.equals(localName)) {
             TextInputMethodQualifier timq = new TextInputMethodQualifier(
                     TextInputMethod.getEnum(mStringAccumulator.toString()));
             mCurrentConfig.setTextInputMethodQualifier(timq);
-        } else if (LayoutConfigsXsd.NODE_NAV_METHOD.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_NAV_METHOD.equals(localName)) {
             NavigationMethodQualifier nmq = new NavigationMethodQualifier(
                     NavigationMethod.getEnum(mStringAccumulator.toString()));
             mCurrentConfig.setNavigationMethodQualifier(nmq);
-        } else if (LayoutConfigsXsd.NODE_SCREEN_DIMENSION.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_SCREEN_DIMENSION.equals(localName)) {
             ScreenDimensionQualifier qual = ScreenDimensionQualifier.getQualifier(mSize1, mSize2);
             if (qual != null) {
                 mCurrentConfig.setScreenDimensionQualifier(qual);
             }
-        } else if (LayoutConfigsXsd.NODE_XDPI.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_XDPI.equals(localName)) {
             mCurrentDevice.setXDpi(Float.parseFloat(mStringAccumulator.toString()));
-        } else if (LayoutConfigsXsd.NODE_YDPI.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_YDPI.equals(localName)) {
             mCurrentDevice.setYDpi(Float.parseFloat(mStringAccumulator.toString()));
-        } else if (LayoutConfigsXsd.NODE_SIZE.equals(localName)) {
+        } else if (LayoutDevicesXsd.NODE_SIZE.equals(localName)) {
             if (mSize1 == null) {
                 mSize1 = mStringAccumulator.toString();
             } else if (mSize2 == null) {
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceManager.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceManager.java
index 03daf40..3b19f17 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceManager.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceManager.java
@@ -18,8 +18,12 @@
 
 import com.android.ide.eclipse.adt.AdtPlugin;
 import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
+import com.android.prefs.AndroidLocation;
+import com.android.prefs.AndroidLocation.AndroidLocationException;
 import com.android.sdklib.SdkConstants;
 
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 import org.xml.sax.ErrorHandler;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
@@ -35,10 +39,17 @@
 import java.util.List;
 import java.util.Map;
 
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.Result;
 import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
 import javax.xml.transform.stream.StreamSource;
 import javax.xml.validation.Validator;
 
@@ -232,11 +243,43 @@
         }
     }
 
-    void load(String sdkOsLocation) {
+    /**
+     * Saves the user-made {@link LayoutDevice}s to disk.
+     */
+    public void save() {
+        try {
+            String userFolder = AndroidLocation.getFolder();
+            File deviceXml = new File(userFolder, SdkConstants.FN_DEVICES_XML);
+            if (deviceXml.isDirectory() == false) {
+                write(deviceXml, mUserLayoutDevices);
+            }
+        } catch (AndroidLocationException e) {
+            // no user folder? simply don't save the user layout device.
+            // we could display the error, but it's likely something else did before, as
+            // nothing will work w/o it.
+            AdtPlugin.log(e, "Unable to find user directory");
+        }
+    }
+
+    /**
+     * Loads the default built-in and user created Layout Devices.
+     * @param sdkOsLocation location of the SDK.
+     */
+    void loadDefaultAndUserDevices(String sdkOsLocation) {
         // load the default devices
         loadDefaultLayoutDevices(sdkOsLocation);
 
         // load the user devices;
+        try {
+            String userFolder = AndroidLocation.getFolder();
+            File deviceXml = new File(userFolder, SdkConstants.FN_DEVICES_XML);
+            if (deviceXml.isFile()) {
+                parseLayoutDevices(deviceXml, mUserLayoutDevices);
+            }
+        } catch (AndroidLocationException e) {
+            // no user folder? simply don't load the user layout device
+            AdtPlugin.log(e, "Unable to find user directory");
+        }
     }
 
     void parseAddOnLayoutDevice(File deviceXml) {
@@ -251,6 +294,8 @@
 
     /**
      * Does the actual parsing of a devices.xml file.
+     * @param deviceXml the {@link File} to load/parse. This must be an existing file.
+     * @param list the list in which to write the parsed {@link LayoutDevice}.
      */
     private void parseLayoutDevices(File deviceXml, List<LayoutDevice> list) {
         // first we validate the XML
@@ -259,7 +304,7 @@
 
             CaptureErrorHandler errorHandler = new CaptureErrorHandler(deviceXml.getAbsolutePath());
 
-            Validator validator = LayoutConfigsXsd.getValidator(errorHandler);
+            Validator validator = LayoutDevicesXsd.getValidator(errorHandler);
             validator.validate(source);
 
             if (errorHandler.foundError() == false) {
@@ -307,4 +352,45 @@
         mLayoutDevices = Collections.unmodifiableList(list);
     }
 
+    /**
+     * Writes the given {@link LayoutDevice}s into the given file.
+     * @param deviceXml the file to write.
+     * @param deviceList the LayoutDevice to write into the file.
+     */
+    private void write(File deviceXml, List<LayoutDevice> deviceList) {
+        try {
+            // create a new document
+            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+            docFactory.setNamespaceAware(true);
+            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+            Document doc = docBuilder.newDocument();
+
+            // create a base node
+            Element baseNode = doc.createElementNS(
+                    LayoutDevicesXsd.NS_LAYOUT_DEVICE_XSD,
+                    LayoutDevicesXsd.NODE_LAYOUT_DEVICES);
+            // create the prefix for the namespace
+            baseNode.setPrefix("d");
+            doc.appendChild(baseNode);
+
+            // fill it with the layout devices.
+            for (LayoutDevice device : deviceList) {
+                device.saveTo(doc, baseNode);
+            }
+
+            // save the document to disk
+            // Prepare the DOM document for writing
+            Source source = new DOMSource(doc);
+
+            // Prepare the output file
+            File file = new File(deviceXml.getAbsolutePath());
+            Result result = new StreamResult(file);
+
+            // Write the DOM document to the file
+            Transformer xformer = TransformerFactory.newInstance().newTransformer();
+            xformer.transform(source, result);
+        } catch (Exception e) {
+            AdtPlugin.log(e, "Failed to write %s", deviceXml.getAbsolutePath());
+        }
+    }
 }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutConfigsXsd.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDevicesXsd.java
similarity index 88%
rename from tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutConfigsXsd.java
rename to tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDevicesXsd.java
index c75c15e..67e9718 100755
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutConfigsXsd.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDevicesXsd.java
@@ -31,14 +31,14 @@
 /**

  * Public constants for the layout device description XML Schema.

  */

-public class LayoutConfigsXsd {

+public class LayoutDevicesXsd {

 

     /** The XML namespace of the layout-configs XML. */

-    public static final String NS_LAYOUT_CONFIG_XSD =

-        "http://schemas.android.com/sdk/android/layout-configs/1";                  //$NON-NLS-1$

+    public static final String NS_LAYOUT_DEVICE_XSD =

+        "http://schemas.android.com/sdk/android/layout-devices/1";                  //$NON-NLS-1$

 

     /**

-     * The "layout-configs" element is the root element of this schema.

+     * The "layout-devices" element is the root element of this schema.

      *

      * It must contain one or more "device" elements that each define the configurations

      * available for a given device.

@@ -46,7 +46,7 @@
      * These definitions are used in the Graphical Layout Editor in the

      * Android Development Tools (ADT) plugin for Eclipse.

      */

-    public static final String NODE_LAYOUT_CONFIGS = "layout-configs";              //$NON-NLS-1$

+    public static final String NODE_LAYOUT_DEVICES = "layout-devices";              //$NON-NLS-1$

 

     /**

      * A device element must contain at most one "default" element followed

@@ -76,6 +76,10 @@
     public static final String NODE_CONFIG = "config";                              //$NON-NLS-1$

 

 

+    public static final String NODE_COUNTRY_CODE = "country-code";                  //$NON-NLS-1$

+

+    public static final String NODE_NETWORK_CODE = "network-code";                  //$NON-NLS-1$

+

     public static final String NODE_SCREEN_SIZE = "screen-size";                    //$NON-NLS-1$

 

     public static final String NODE_SCREEN_RATIO = "screen-ratio";                  //$NON-NLS-1$

@@ -111,7 +115,7 @@
      * Helper to get an input stream of the layout config XML schema.

      */

     public static InputStream getXsdStream() {

-        return LayoutConfigsXsd.class.getResourceAsStream("layout-configs.xsd");    //$NON-NLS-1$

+        return LayoutDevicesXsd.class.getResourceAsStream("layout-devices.xsd");    //$NON-NLS-1$

     }

 

     /** Helper method that returns a {@link Validator} for our XSD */

diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
index 6a8bd5b..45ff31f 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
@@ -440,7 +440,7 @@
                 SdkConstants.OS_SDK_DOCS_FOLDER);
 
         // load the built-in and user layout devices
-        mLayoutDeviceManager.load(mManager.getLocation());
+        mLayoutDeviceManager.loadDefaultAndUserDevices(mManager.getLocation());
         // and the ones from the add-on
         loadLayoutDevices();
     }
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-configs.xsd b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-devices.xsd
similarity index 89%
rename from tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-configs.xsd
rename to tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-devices.xsd
index 49131fb..8a58560 100755
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-configs.xsd
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/layout-devices.xsd
@@ -15,17 +15,17 @@
  * limitations under the License.
 -->
 <xsd:schema
-    targetNamespace="http://schemas.android.com/sdk/android/layout-configs/1"
+    targetNamespace="http://schemas.android.com/sdk/android/layout-devices/1"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
-    xmlns:c="http://schemas.android.com/sdk/android/layout-configs/1"
+    xmlns:c="http://schemas.android.com/sdk/android/layout-devices/1"
     elementFormDefault="qualified"
     attributeFormDefault="unqualified"
     version="1">
 
-    <xsd:element name="layout-configs">
+    <xsd:element name="layout-devices">
         <xsd:annotation>
             <xsd:documentation xml:lang="en">
-                The "layout-configs" element is the root element of this schema.
+                The "layout-devices" element is the root element of this schema.
 
                 It must contain one or more "device" elements that each define the configurations
                 available for a given device.
@@ -37,7 +37,7 @@
 
         <xsd:complexType>
             <xsd:sequence>
-                <!-- layout-configs defines a sequence of 1..n device elements. -->
+                <!-- layout-devices defines a sequence of 1..n device elements. -->
                 <xsd:element name="device" minOccurs="1" maxOccurs="unbounded">
 
                     <xsd:annotation>
@@ -92,6 +92,34 @@
         <xsd:all>
             <!-- parametersType says that 0..1 of each of these elements must be declared. -->
 
+            <xsd:element name="country-code" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the configuration is for a particular Mobile Country Code.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:float">
+                        <xsd:minInclusive value="100" />
+                        <xsd:maxInclusive value="999" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
+            <xsd:element name="network-code" minOccurs="0">
+                <xsd:annotation>
+                    <xsd:documentation xml:lang="en">
+                        Specifies the configuration is for a particular Mobile Network Code.
+                    </xsd:documentation>
+                </xsd:annotation>
+                <xsd:simpleType>
+                    <xsd:restriction base="xsd:float">
+                        <xsd:minExclusive value="0" />
+                        <xsd:maxExclusive value="1000" />
+                    </xsd:restriction>
+                </xsd:simpleType>
+            </xsd:element>
+
             <xsd:element name="screen-size" minOccurs="0">
                 <xsd:annotation>
                     <xsd:documentation xml:lang="en">
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutConfisXsd.java b/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutDevicesXsd.java
similarity index 83%
rename from tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutConfisXsd.java
rename to tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutDevicesXsd.java
index 43b0507..8aa8ee0 100755
--- a/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutConfisXsd.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/TestLayoutDevicesXsd.java
@@ -30,9 +30,9 @@
 import junit.framework.TestCase;

 

 /**

- * Tests local validation of a Layout-Configs sample XMLs using an XML Schema validator.

+ * Tests local validation of a Layout-Devices sample XMLs using an XML Schema validator.

  */

-public class TestLayoutConfisXsd extends TestCase {

+public class TestLayoutDevicesXsd extends TestCase {

 

     @Override

     protected void setUp() throws Exception {

@@ -117,7 +117,7 @@
         Source source = new StreamSource(new StringReader(document));

 

         // don't capture the validator errors, we want it to fail and catch the exception

-        Validator validator = LayoutConfigsXsd.getValidator(null);

+        Validator validator = LayoutDevicesXsd.getValidator(null);

         try {

             validator.validate(source);

         } catch (SAXParseException e) {

@@ -133,7 +133,7 @@
         Source source = new StreamSource(new StringReader(document));

 

         CaptureErrorHandler handler = new CaptureErrorHandler();

-        Validator validator = LayoutConfigsXsd.getValidator(null);

+        Validator validator = LayoutDevicesXsd.getValidator(null);

         validator.validate(source);

         handler.verify();

     }

@@ -144,11 +144,11 @@
     public void testValidateLocalRepositoryFile() throws Exception {

 

         InputStream xmlStream =

-            TestLayoutConfisXsd.class.getResourceAsStream("config_sample.xml");

+            TestLayoutDevicesXsd.class.getResourceAsStream("config_sample.xml");

         Source source = new StreamSource(xmlStream);

 

         CaptureErrorHandler handler = new CaptureErrorHandler();

-        Validator validator = LayoutConfigsXsd.getValidator(handler);

+        Validator validator = LayoutDevicesXsd.getValidator(handler);

         validator.validate(source);

         handler.verify();

     }

@@ -168,9 +168,9 @@
         checkFailure(

                 // document

                 "<?xml version=\"1.0\"?>" +

-                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +

+                "<d:layout-devices xmlns:d=\"http://schemas.android.com/sdk/android/layout-devices/1\" >" +

                 "<d:unknown />" +

-                "</d:layout-configs>",

+                "</d:layout-devices>",

 

                 // expected failure

                 "cvc-complex-type.2.4.a: Invalid content was found.*");

@@ -181,9 +181,9 @@
         checkFailure(

                 // document

                 "<?xml version=\"1.0\"?>" +

-                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +

+                "<d:layout-devices xmlns:d=\"http://schemas.android.com/sdk/android/layout-devices/1\" >" +

                 "<d:device />" +

-                "</d:layout-configs>",

+                "</d:layout-devices>",

 

                 // expected failure

                 "cvc-complex-type.4: Attribute 'name' must appear on element 'd:device'.");

@@ -194,10 +194,10 @@
         checkFailure(

                 // document

                 "<?xml version=\"1.0\"?>" +

-                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" />",

+                "<d:layout-devices xmlns:d=\"http://schemas.android.com/sdk/android/layout-devices/1\" />",

 

                 // expected failure

-                "cvc-complex-type.2.4.b: The content of element 'd:layout-configs' is not complete.*");

+                "cvc-complex-type.2.4.b: The content of element 'd:layout-devices' is not complete.*");

     }

 

     /** A document with an empty device element is not valid. */

@@ -205,9 +205,9 @@
         checkFailure(

                 // document

                 "<?xml version=\"1.0\"?>" +

-                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +

+                "<d:layout-devices xmlns:d=\"http://schemas.android.com/sdk/android/layout-devices/1\" >" +

                 "<d:device name=\"foo\"/>" +

-                "</d:layout-configs>",

+                "</d:layout-devices>",

 

                 // expected failure

                 "cvc-complex-type.2.4.b: The content of element 'd:device' is not complete.*");

@@ -218,12 +218,12 @@
         checkFailure(

                 // document

                 "<?xml version=\"1.0\"?>" +

-                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +

+                "<d:layout-devices xmlns:d=\"http://schemas.android.com/sdk/android/layout-devices/1\" >" +

                 "<d:device name=\"foo\">" +

                 "  <d:default />" +

                 "  <d:default />" +

                 "</d:device>" +

-                "</d:layout-configs>",

+                "</d:layout-devices>",

 

                 // expected failure

                 "cvc-complex-type.2.4.a: Invalid content was found starting with element 'd:default'.*");

@@ -234,12 +234,12 @@
         checkFailure(

                 // document

                 "<?xml version=\"1.0\"?>" +

-                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +

+                "<d:layout-devices xmlns:d=\"http://schemas.android.com/sdk/android/layout-devices/1\" >" +

                 "<d:device name=\"foo\">" +

                 "  <d:config name=\"must-be-after-default\" />" +

                 "  <d:default />" +

                 "</d:device>" +

-                "</d:layout-configs>",

+                "</d:layout-devices>",

 

                 // expected failure

                 "cvc-complex-type.2.4.a: Invalid content was found starting with element 'd:default'.*");

@@ -250,13 +250,13 @@
         checkFailure(

                 // document

                 "<?xml version=\"1.0\"?>" +

-                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +

+                "<d:layout-devices xmlns:d=\"http://schemas.android.com/sdk/android/layout-devices/1\" >" +

                 "<d:device name=\"foo\">" +

                 "  <d:default>" +

                 "    <d:screen-dimension> <d:size>0</d:size> <d:size>1</d:size> </d:screen-dimension>" +

                 "  </d:default>" +

                 "</d:device>" +

-                "</d:layout-configs>",

+                "</d:layout-devices>",

 

                 // expected failure

                 "cvc-minInclusive-valid: Value '0' is not facet-valid with respect to minInclusive '1'.*");

@@ -267,13 +267,13 @@
         checkFailure(

                 // document

                 "<?xml version=\"1.0\"?>" +

-                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +

+                "<d:layout-devices xmlns:d=\"http://schemas.android.com/sdk/android/layout-devices/1\" >" +

                 "<d:device name=\"foo\">" +

                 "  <d:default>" +

                 "    <d:screen-dimension> <d:size>-5</d:size> <d:size>1</d:size> </d:screen-dimension>" +

                 "  </d:default>" +

                 "</d:device>" +

-                "</d:layout-configs>",

+                "</d:layout-devices>",

 

                 // expected failure

                 "cvc-minInclusive-valid: Value '-5' is not facet-valid with respect to minInclusive '1'.*");

@@ -284,13 +284,13 @@
         checkFailure(

                 // document

                 "<?xml version=\"1.0\"?>" +

-                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +

+                "<d:layout-devices xmlns:d=\"http://schemas.android.com/sdk/android/layout-devices/1\" >" +

                 "<d:device name=\"foo\">" +

                 "  <d:default>" +

                 "    <d:xdpi>0</d:xdpi>" +

                 "  </d:default>" +

                 "</d:device>" +

-                "</d:layout-configs>",

+                "</d:layout-devices>",

 

                 // expected failure

                 "cvc-minExclusive-valid: Value '0' is not facet-valid with respect to minExclusive '0.0E1'.*");

@@ -302,13 +302,13 @@
         checkFailure(

                 // document

                 "<?xml version=\"1.0\"?>" +

-                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +

+                "<d:layout-devices xmlns:d=\"http://schemas.android.com/sdk/android/layout-devices/1\" >" +

                 "<d:device name=\"foo\">" +

                 "  <d:default>" +

                 "    <d:xdpi>-3.1415926538</d:xdpi>" +

                 "  </d:default>" +

                 "</d:device>" +

-                "</d:layout-configs>",

+                "</d:layout-devices>",

 

                 // expected failure

                 "cvc-minExclusive-valid: Value '-3.1415926538' is not facet-valid with respect to minExclusive '0.0E1'.*");

@@ -319,13 +319,13 @@
         checkSuccess(

                 // document

                 "<?xml version=\"1.0\"?>" +

-                "<d:layout-configs xmlns:d=\"http://schemas.android.com/sdk/android/layout-configs/1\" >" +

+                "<d:layout-devices xmlns:d=\"http://schemas.android.com/sdk/android/layout-devices/1\" >" +

                 "<d:device name=\"foo\">" +

                 "  <d:config name='foo'>" +

                 "    <d:screen-ratio>  \n long \r </d:screen-ratio>" +

                 "  </d:config>" +

                 "</d:device>" +

-                "</d:layout-configs>");

+                "</d:layout-devices>");

     }

 

 }

diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/config_sample.xml b/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/config_sample.xml
index 901dd71..56a753f 100755
--- a/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/config_sample.xml
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/sdk/config_sample.xml
@@ -14,9 +14,9 @@
  * See the License for the specific language governing permissions and

  * limitations under the License.

 -->

-<d:layout-configs

+<d:layout-devices

     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

-    xmlns:d="http://schemas.android.com/sdk/android/layout-configs/1">

+    xmlns:d="http://schemas.android.com/sdk/android/layout-devices/1">

 

     <d:device name="MyDevice">        <!-- 1..n -->

         <d:default>                   <!-- 0..1 -->

@@ -134,4 +134,4 @@
         </d:config>

     </d:device>

 

-</d:layout-configs>

+</d:layout-devices>

diff --git a/tools/scripts/devices.xml b/tools/scripts/devices.xml
index e600a19..2d10b89 100644
--- a/tools/scripts/devices.xml
+++ b/tools/scripts/devices.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
-<d:layout-configs
+<d:layout-devices
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xmlns:d="http://schemas.android.com/sdk/android/layout-configs/1">
+    xmlns:d="http://schemas.android.com/sdk/android/layout-devices/1">
 
     <d:device name="ADP1">
         <d:default>
@@ -59,4 +59,4 @@
             <d:screen-orientation>land</d:screen-orientation>
         </d:config>
     </d:device>
-</d:layout-configs>
+</d:layout-devices>