/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceManager.java
Java | 395 lines | 229 code | 56 blank | 110 comment | 22 complexity | 76f5de80465f13acb810bdd42b41246b MD5 | raw file
- /*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Eclipse Public License, Version 1.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.eclipse.org/org/documents/epl-v10.php
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.android.ide.eclipse.adt.internal.sdk;
- import com.android.ide.common.resources.configuration.FolderConfiguration;
- import com.android.ide.eclipse.adt.AdtPlugin;
- import com.android.ide.eclipse.adt.internal.sdk.LayoutDevice.DeviceConfig;
- 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;
- import org.xml.sax.SAXParseException;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileReader;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
- 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;
- /**
- * Manages the layout devices.
- * They can come from 3 sources: built-in, add-ons, user.
- */
- public class LayoutDeviceManager {
- /**
- * A SAX error handler that captures the errors and warnings.
- * This allows us to capture *all* errors and just not get an exception on the first one.
- */
- private static class CaptureErrorHandler implements ErrorHandler {
- private final String mSourceLocation;
- private boolean mFoundError = false;
- CaptureErrorHandler(String sourceLocation) {
- mSourceLocation = sourceLocation;
- }
- public boolean foundError() {
- return mFoundError;
- }
- /**
- * @throws SAXException
- */
- public void error(SAXParseException ex) throws SAXException {
- mFoundError = true;
- AdtPlugin.log(ex, "Error validating %1$s", mSourceLocation);
- }
- /**
- * @throws SAXException
- */
- public void fatalError(SAXParseException ex) throws SAXException {
- mFoundError = true;
- AdtPlugin.log(ex, "Error validating %1$s", mSourceLocation);
- }
- /**
- * @throws SAXException
- */
- public void warning(SAXParseException ex) throws SAXException {
- // ignore those for now.
- }
- }
- private final SAXParserFactory mParserFactory;
- private List<LayoutDevice> mDefaultLayoutDevices =
- new ArrayList<LayoutDevice>();
- private List<LayoutDevice> mAddOnLayoutDevices =
- new ArrayList<LayoutDevice>();
- private final List<LayoutDevice> mUserLayoutDevices =
- new ArrayList<LayoutDevice>();
- private List<LayoutDevice> mLayoutDevices;
- LayoutDeviceManager() {
- mParserFactory = SAXParserFactory.newInstance();
- mParserFactory.setNamespaceAware(true);
- }
- public List<LayoutDevice> getCombinedList() {
- return mLayoutDevices;
- }
- public List<LayoutDevice> getDefaultLayoutDevices() {
- return mDefaultLayoutDevices;
- }
- public List<LayoutDevice> getAddOnLayoutDevice() {
- return mAddOnLayoutDevices;
- }
- public List<LayoutDevice> getUserLayoutDevices() {
- return mUserLayoutDevices;
- }
- public LayoutDevice getUserLayoutDevice(String name) {
- for (LayoutDevice d : mUserLayoutDevices) {
- if (d.getName().equals(name)) {
- return d;
- }
- }
- return null;
- }
- public LayoutDevice addUserDevice(String name, float xdpi, float ydpi) {
- LayoutDevice d = new LayoutDevice(name);
- d.setXDpi(xdpi);
- d.setYDpi(ydpi);
- mUserLayoutDevices.add(d);
- combineLayoutDevices();
- return d;
- }
- public void removeUserDevice(LayoutDevice device) {
- if (mUserLayoutDevices.remove(device)) {
- combineLayoutDevices();
- }
- }
- /**
- * Replaces a device with a new one with new name and/or x/y dpi, and return the new device.
- * If the name and dpi values are identical the given device is returned an nothing is done
- * @param device the {@link LayoutDevice} to replace
- * @param newName the new name.
- * @param newXDpi the new X dpi value
- * @param newYDpi the new Y dpi value.
- * @return the new LayoutDevice
- */
- public LayoutDevice replaceUserDevice(LayoutDevice device, String newName,
- float newXDpi, float newYDpi) {
- if (device.getName().equals(newName) && device.getXDpi() == newXDpi &&
- device.getYDpi() == newYDpi) {
- return device;
- }
- // else create a new device
- LayoutDevice newDevice = new LayoutDevice(newName);
- newDevice.setXDpi(newXDpi);
- newDevice.setYDpi(newYDpi);
- // and get the Folderconfiguration
- List<DeviceConfig> configs = device.getConfigs();
- newDevice.addConfigs(configs);
- // replace the old device with the new
- mUserLayoutDevices.remove(device);
- mUserLayoutDevices.add(newDevice);
- combineLayoutDevices();
- return newDevice;
- }
- /**
- * Adds or replaces a configuration in a given {@link LayoutDevice}.
- * @param device the device to modify
- * @param configName the configuration name to add or replace
- * @param config the configuration to set
- */
- public void addUserConfiguration(LayoutDevice device, String configName,
- FolderConfiguration config) {
- // check that the device does belong to the user list.
- // the main goal is to make sure that this does not belong to the default/addon list.
- if (mUserLayoutDevices.contains(device)) {
- device.addConfig(configName, config);
- }
- }
- /**
- * Replaces a configuration in a given {@link LayoutDevice}.
- * @param device the device to modify
- * @param oldConfigName the name of the config to replace. If null, the new config is simply
- * added.
- * @param newConfigName the configuration name to add or replace
- * @param config the configuration to set
- */
- public void replaceUserConfiguration(LayoutDevice device, String oldConfigName,
- String newConfigName, FolderConfiguration config) {
- // check that the device does belong to the user list.
- // the main goal is to make sure that this does not belong to the default/addon list.
- if (mUserLayoutDevices.contains(device)) {
- // if the old and new config name are different, remove the old one
- if (oldConfigName != null && oldConfigName.equals(newConfigName) == false) {
- device.removeConfig(oldConfigName);
- }
- // and then add the new one
- device.addConfig(newConfigName, config);
- }
- }
- /**
- * Removes a configuration from a given user {@link LayoutDevice}
- * @param device the device to modify
- * @param configName the name of the config to remove
- */
- public void removeUserConfiguration(LayoutDevice device, String configName) {
- // check that the device does belong to the user list.
- // the main goal is to make sure that this does not belong to the default/addon list.
- if (mUserLayoutDevices.contains(device)) {
- device.removeConfig(configName);
- }
- }
- /**
- * 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) {
- parseLayoutDevices(deviceXml, mAddOnLayoutDevices);
- }
- void sealAddonLayoutDevices() {
- mAddOnLayoutDevices = Collections.unmodifiableList(mAddOnLayoutDevices);
- combineLayoutDevices();
- }
- /**
- * 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
- try {
- Source source = new StreamSource(new FileReader(deviceXml));
- CaptureErrorHandler errorHandler = new CaptureErrorHandler(deviceXml.getAbsolutePath());
- Validator validator = LayoutDevicesXsd.getValidator(errorHandler);
- validator.validate(source);
- if (errorHandler.foundError() == false) {
- // do the actual parsing
- LayoutDeviceHandler handler = new LayoutDeviceHandler();
- SAXParser parser = mParserFactory.newSAXParser();
- parser.parse(new InputSource(new FileInputStream(deviceXml)), handler);
- // get the parsed devices
- list.addAll(handler.getDevices());
- }
- } catch (SAXException e) {
- AdtPlugin.log(e, "Error parsing %1$s", deviceXml.getAbsoluteFile());
- } catch (FileNotFoundException e) {
- // this shouldn't happen as we check above.
- } catch (IOException e) {
- AdtPlugin.log(e, "Error reading %1$s", deviceXml.getAbsoluteFile());
- } catch (ParserConfigurationException e) {
- AdtPlugin.log(e, "Error parsing %1$s", deviceXml.getAbsoluteFile());
- }
- }
- /**
- * Creates some built-it layout devices.
- */
- private void loadDefaultLayoutDevices(String sdkOsLocation) {
- ArrayList<LayoutDevice> list = new ArrayList<LayoutDevice>();
- File toolsFolder = new File(sdkOsLocation, SdkConstants.OS_SDK_TOOLS_LIB_FOLDER);
- if (toolsFolder.isDirectory()) {
- File deviceXml = new File(toolsFolder, SdkConstants.FN_DEVICES_XML);
- if (deviceXml.isFile()) {
- parseLayoutDevices(deviceXml, list);
- }
- }
- mDefaultLayoutDevices = Collections.unmodifiableList(list);
- }
- private void combineLayoutDevices() {
- ArrayList<LayoutDevice> list = new ArrayList<LayoutDevice>();
- list.addAll(mDefaultLayoutDevices);
- list.addAll(mAddOnLayoutDevices);
- list.addAll(mUserLayoutDevices);
- 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());
- }
- }
- }