PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/LayoutDeviceManager.java

https://gitlab.com/Codeaurora/platform_sdk
Java | 395 lines | 229 code | 56 blank | 110 comment | 22 complexity | 76f5de80465f13acb810bdd42b41246b MD5 | raw file
  1. /*
  2. * Copyright (C) 2009 The Android Open Source Project
  3. *
  4. * Licensed under the Eclipse Public License, Version 1.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.eclipse.org/org/documents/epl-v10.php
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.android.ide.eclipse.adt.internal.sdk;
  17. import com.android.ide.common.resources.configuration.FolderConfiguration;
  18. import com.android.ide.eclipse.adt.AdtPlugin;
  19. import com.android.ide.eclipse.adt.internal.sdk.LayoutDevice.DeviceConfig;
  20. import com.android.prefs.AndroidLocation;
  21. import com.android.prefs.AndroidLocation.AndroidLocationException;
  22. import com.android.sdklib.SdkConstants;
  23. import org.w3c.dom.Document;
  24. import org.w3c.dom.Element;
  25. import org.xml.sax.ErrorHandler;
  26. import org.xml.sax.InputSource;
  27. import org.xml.sax.SAXException;
  28. import org.xml.sax.SAXParseException;
  29. import java.io.File;
  30. import java.io.FileInputStream;
  31. import java.io.FileNotFoundException;
  32. import java.io.FileReader;
  33. import java.io.IOException;
  34. import java.util.ArrayList;
  35. import java.util.Collections;
  36. import java.util.List;
  37. import javax.xml.parsers.DocumentBuilder;
  38. import javax.xml.parsers.DocumentBuilderFactory;
  39. import javax.xml.parsers.ParserConfigurationException;
  40. import javax.xml.parsers.SAXParser;
  41. import javax.xml.parsers.SAXParserFactory;
  42. import javax.xml.transform.Result;
  43. import javax.xml.transform.Source;
  44. import javax.xml.transform.Transformer;
  45. import javax.xml.transform.TransformerFactory;
  46. import javax.xml.transform.dom.DOMSource;
  47. import javax.xml.transform.stream.StreamResult;
  48. import javax.xml.transform.stream.StreamSource;
  49. import javax.xml.validation.Validator;
  50. /**
  51. * Manages the layout devices.
  52. * They can come from 3 sources: built-in, add-ons, user.
  53. */
  54. public class LayoutDeviceManager {
  55. /**
  56. * A SAX error handler that captures the errors and warnings.
  57. * This allows us to capture *all* errors and just not get an exception on the first one.
  58. */
  59. private static class CaptureErrorHandler implements ErrorHandler {
  60. private final String mSourceLocation;
  61. private boolean mFoundError = false;
  62. CaptureErrorHandler(String sourceLocation) {
  63. mSourceLocation = sourceLocation;
  64. }
  65. public boolean foundError() {
  66. return mFoundError;
  67. }
  68. /**
  69. * @throws SAXException
  70. */
  71. public void error(SAXParseException ex) throws SAXException {
  72. mFoundError = true;
  73. AdtPlugin.log(ex, "Error validating %1$s", mSourceLocation);
  74. }
  75. /**
  76. * @throws SAXException
  77. */
  78. public void fatalError(SAXParseException ex) throws SAXException {
  79. mFoundError = true;
  80. AdtPlugin.log(ex, "Error validating %1$s", mSourceLocation);
  81. }
  82. /**
  83. * @throws SAXException
  84. */
  85. public void warning(SAXParseException ex) throws SAXException {
  86. // ignore those for now.
  87. }
  88. }
  89. private final SAXParserFactory mParserFactory;
  90. private List<LayoutDevice> mDefaultLayoutDevices =
  91. new ArrayList<LayoutDevice>();
  92. private List<LayoutDevice> mAddOnLayoutDevices =
  93. new ArrayList<LayoutDevice>();
  94. private final List<LayoutDevice> mUserLayoutDevices =
  95. new ArrayList<LayoutDevice>();
  96. private List<LayoutDevice> mLayoutDevices;
  97. LayoutDeviceManager() {
  98. mParserFactory = SAXParserFactory.newInstance();
  99. mParserFactory.setNamespaceAware(true);
  100. }
  101. public List<LayoutDevice> getCombinedList() {
  102. return mLayoutDevices;
  103. }
  104. public List<LayoutDevice> getDefaultLayoutDevices() {
  105. return mDefaultLayoutDevices;
  106. }
  107. public List<LayoutDevice> getAddOnLayoutDevice() {
  108. return mAddOnLayoutDevices;
  109. }
  110. public List<LayoutDevice> getUserLayoutDevices() {
  111. return mUserLayoutDevices;
  112. }
  113. public LayoutDevice getUserLayoutDevice(String name) {
  114. for (LayoutDevice d : mUserLayoutDevices) {
  115. if (d.getName().equals(name)) {
  116. return d;
  117. }
  118. }
  119. return null;
  120. }
  121. public LayoutDevice addUserDevice(String name, float xdpi, float ydpi) {
  122. LayoutDevice d = new LayoutDevice(name);
  123. d.setXDpi(xdpi);
  124. d.setYDpi(ydpi);
  125. mUserLayoutDevices.add(d);
  126. combineLayoutDevices();
  127. return d;
  128. }
  129. public void removeUserDevice(LayoutDevice device) {
  130. if (mUserLayoutDevices.remove(device)) {
  131. combineLayoutDevices();
  132. }
  133. }
  134. /**
  135. * Replaces a device with a new one with new name and/or x/y dpi, and return the new device.
  136. * If the name and dpi values are identical the given device is returned an nothing is done
  137. * @param device the {@link LayoutDevice} to replace
  138. * @param newName the new name.
  139. * @param newXDpi the new X dpi value
  140. * @param newYDpi the new Y dpi value.
  141. * @return the new LayoutDevice
  142. */
  143. public LayoutDevice replaceUserDevice(LayoutDevice device, String newName,
  144. float newXDpi, float newYDpi) {
  145. if (device.getName().equals(newName) && device.getXDpi() == newXDpi &&
  146. device.getYDpi() == newYDpi) {
  147. return device;
  148. }
  149. // else create a new device
  150. LayoutDevice newDevice = new LayoutDevice(newName);
  151. newDevice.setXDpi(newXDpi);
  152. newDevice.setYDpi(newYDpi);
  153. // and get the Folderconfiguration
  154. List<DeviceConfig> configs = device.getConfigs();
  155. newDevice.addConfigs(configs);
  156. // replace the old device with the new
  157. mUserLayoutDevices.remove(device);
  158. mUserLayoutDevices.add(newDevice);
  159. combineLayoutDevices();
  160. return newDevice;
  161. }
  162. /**
  163. * Adds or replaces a configuration in a given {@link LayoutDevice}.
  164. * @param device the device to modify
  165. * @param configName the configuration name to add or replace
  166. * @param config the configuration to set
  167. */
  168. public void addUserConfiguration(LayoutDevice device, String configName,
  169. FolderConfiguration config) {
  170. // check that the device does belong to the user list.
  171. // the main goal is to make sure that this does not belong to the default/addon list.
  172. if (mUserLayoutDevices.contains(device)) {
  173. device.addConfig(configName, config);
  174. }
  175. }
  176. /**
  177. * Replaces a configuration in a given {@link LayoutDevice}.
  178. * @param device the device to modify
  179. * @param oldConfigName the name of the config to replace. If null, the new config is simply
  180. * added.
  181. * @param newConfigName the configuration name to add or replace
  182. * @param config the configuration to set
  183. */
  184. public void replaceUserConfiguration(LayoutDevice device, String oldConfigName,
  185. String newConfigName, FolderConfiguration config) {
  186. // check that the device does belong to the user list.
  187. // the main goal is to make sure that this does not belong to the default/addon list.
  188. if (mUserLayoutDevices.contains(device)) {
  189. // if the old and new config name are different, remove the old one
  190. if (oldConfigName != null && oldConfigName.equals(newConfigName) == false) {
  191. device.removeConfig(oldConfigName);
  192. }
  193. // and then add the new one
  194. device.addConfig(newConfigName, config);
  195. }
  196. }
  197. /**
  198. * Removes a configuration from a given user {@link LayoutDevice}
  199. * @param device the device to modify
  200. * @param configName the name of the config to remove
  201. */
  202. public void removeUserConfiguration(LayoutDevice device, String configName) {
  203. // check that the device does belong to the user list.
  204. // the main goal is to make sure that this does not belong to the default/addon list.
  205. if (mUserLayoutDevices.contains(device)) {
  206. device.removeConfig(configName);
  207. }
  208. }
  209. /**
  210. * Saves the user-made {@link LayoutDevice}s to disk.
  211. */
  212. public void save() {
  213. try {
  214. String userFolder = AndroidLocation.getFolder();
  215. File deviceXml = new File(userFolder, SdkConstants.FN_DEVICES_XML);
  216. if (deviceXml.isDirectory() == false) {
  217. write(deviceXml, mUserLayoutDevices);
  218. }
  219. } catch (AndroidLocationException e) {
  220. // no user folder? simply don't save the user layout device.
  221. // we could display the error, but it's likely something else did before, as
  222. // nothing will work w/o it.
  223. AdtPlugin.log(e, "Unable to find user directory");
  224. }
  225. }
  226. /**
  227. * Loads the default built-in and user created Layout Devices.
  228. * @param sdkOsLocation location of the SDK.
  229. */
  230. void loadDefaultAndUserDevices(String sdkOsLocation) {
  231. // load the default devices
  232. loadDefaultLayoutDevices(sdkOsLocation);
  233. // load the user devices;
  234. try {
  235. String userFolder = AndroidLocation.getFolder();
  236. File deviceXml = new File(userFolder, SdkConstants.FN_DEVICES_XML);
  237. if (deviceXml.isFile()) {
  238. parseLayoutDevices(deviceXml, mUserLayoutDevices);
  239. }
  240. } catch (AndroidLocationException e) {
  241. // no user folder? simply don't load the user layout device
  242. AdtPlugin.log(e, "Unable to find user directory");
  243. }
  244. }
  245. void parseAddOnLayoutDevice(File deviceXml) {
  246. parseLayoutDevices(deviceXml, mAddOnLayoutDevices);
  247. }
  248. void sealAddonLayoutDevices() {
  249. mAddOnLayoutDevices = Collections.unmodifiableList(mAddOnLayoutDevices);
  250. combineLayoutDevices();
  251. }
  252. /**
  253. * Does the actual parsing of a devices.xml file.
  254. * @param deviceXml the {@link File} to load/parse. This must be an existing file.
  255. * @param list the list in which to write the parsed {@link LayoutDevice}.
  256. */
  257. private void parseLayoutDevices(File deviceXml, List<LayoutDevice> list) {
  258. // first we validate the XML
  259. try {
  260. Source source = new StreamSource(new FileReader(deviceXml));
  261. CaptureErrorHandler errorHandler = new CaptureErrorHandler(deviceXml.getAbsolutePath());
  262. Validator validator = LayoutDevicesXsd.getValidator(errorHandler);
  263. validator.validate(source);
  264. if (errorHandler.foundError() == false) {
  265. // do the actual parsing
  266. LayoutDeviceHandler handler = new LayoutDeviceHandler();
  267. SAXParser parser = mParserFactory.newSAXParser();
  268. parser.parse(new InputSource(new FileInputStream(deviceXml)), handler);
  269. // get the parsed devices
  270. list.addAll(handler.getDevices());
  271. }
  272. } catch (SAXException e) {
  273. AdtPlugin.log(e, "Error parsing %1$s", deviceXml.getAbsoluteFile());
  274. } catch (FileNotFoundException e) {
  275. // this shouldn't happen as we check above.
  276. } catch (IOException e) {
  277. AdtPlugin.log(e, "Error reading %1$s", deviceXml.getAbsoluteFile());
  278. } catch (ParserConfigurationException e) {
  279. AdtPlugin.log(e, "Error parsing %1$s", deviceXml.getAbsoluteFile());
  280. }
  281. }
  282. /**
  283. * Creates some built-it layout devices.
  284. */
  285. private void loadDefaultLayoutDevices(String sdkOsLocation) {
  286. ArrayList<LayoutDevice> list = new ArrayList<LayoutDevice>();
  287. File toolsFolder = new File(sdkOsLocation, SdkConstants.OS_SDK_TOOLS_LIB_FOLDER);
  288. if (toolsFolder.isDirectory()) {
  289. File deviceXml = new File(toolsFolder, SdkConstants.FN_DEVICES_XML);
  290. if (deviceXml.isFile()) {
  291. parseLayoutDevices(deviceXml, list);
  292. }
  293. }
  294. mDefaultLayoutDevices = Collections.unmodifiableList(list);
  295. }
  296. private void combineLayoutDevices() {
  297. ArrayList<LayoutDevice> list = new ArrayList<LayoutDevice>();
  298. list.addAll(mDefaultLayoutDevices);
  299. list.addAll(mAddOnLayoutDevices);
  300. list.addAll(mUserLayoutDevices);
  301. mLayoutDevices = Collections.unmodifiableList(list);
  302. }
  303. /**
  304. * Writes the given {@link LayoutDevice}s into the given file.
  305. * @param deviceXml the file to write.
  306. * @param deviceList the LayoutDevice to write into the file.
  307. */
  308. private void write(File deviceXml, List<LayoutDevice> deviceList) {
  309. try {
  310. // create a new document
  311. DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
  312. docFactory.setNamespaceAware(true);
  313. DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
  314. Document doc = docBuilder.newDocument();
  315. // create a base node
  316. Element baseNode = doc.createElementNS(
  317. LayoutDevicesXsd.NS_LAYOUT_DEVICE_XSD,
  318. LayoutDevicesXsd.NODE_LAYOUT_DEVICES);
  319. // create the prefix for the namespace
  320. baseNode.setPrefix("d");
  321. doc.appendChild(baseNode);
  322. // fill it with the layout devices.
  323. for (LayoutDevice device : deviceList) {
  324. device.saveTo(doc, baseNode);
  325. }
  326. // save the document to disk
  327. // Prepare the DOM document for writing
  328. Source source = new DOMSource(doc);
  329. // Prepare the output file
  330. File file = new File(deviceXml.getAbsolutePath());
  331. Result result = new StreamResult(file);
  332. // Write the DOM document to the file
  333. Transformer xformer = TransformerFactory.newInstance().newTransformer();
  334. xformer.transform(source, result);
  335. } catch (Exception e) {
  336. AdtPlugin.log(e, "Failed to write %s", deviceXml.getAbsolutePath());
  337. }
  338. }
  339. }