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 17 package com.android.ide.eclipse.adt.internal.sdk; 18 19 import com.android.ide.eclipse.adt.internal.resources.configurations.CountryCodeQualifier; 20 import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration; 21 import com.android.ide.eclipse.adt.internal.resources.configurations.KeyboardStateQualifier; 22 import com.android.ide.eclipse.adt.internal.resources.configurations.NavigationMethodQualifier; 23 import com.android.ide.eclipse.adt.internal.resources.configurations.NetworkCodeQualifier; 24 import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier; 25 import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenDimensionQualifier; 26 import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier; 27 import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenRatioQualifier; 28 import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenSizeQualifier; 29 import com.android.ide.eclipse.adt.internal.resources.configurations.TextInputMethodQualifier; 30 import com.android.ide.eclipse.adt.internal.resources.configurations.TouchScreenQualifier; 31 32 import org.w3c.dom.Document; 33 import org.w3c.dom.Element; 34 35 import java.util.Collections; 36 import java.util.HashMap; 37 import java.util.Map; 38 import java.util.Map.Entry; 39 40 /** 41 * Class representing a layout device. 42 * 43 * A Layout device is a collection of {@link FolderConfiguration} that can be used to render Android 44 * layout files. 45 * 46 * It also contains a single xdpi/ydpi that is independent of the {@link FolderConfiguration}. 47 * 48 * If the device is meant to represent a true device, then most of the FolderConfigurations' content 49 * should be identical, with only a few qualifiers (orientation, keyboard state) that would differ. 50 * However it is simpler to reuse the FolderConfiguration class (with the non changing qualifiers 51 * duplicated in each configuration) as it's what's being used by the rendering library. 52 * 53 * To create, edit and delete LayoutDevice objects, see {@link LayoutDeviceManager}. 54 * The class is not technically immutable but behaves as such outside of its package. 55 */ 56 public class LayoutDevice { 57 58 private final String mName; 59 60 /** editable map of the config */ 61 private Map<String, FolderConfiguration> mEditMap = new HashMap<String, FolderConfiguration>(); 62 /** unmodifiable map returned by {@link #getConfigs()}. */ 63 private Map<String, FolderConfiguration> mMap; 64 private float mXDpi = Float.NaN; 65 private float mYDpi = Float.NaN; 66 LayoutDevice(String name)67 LayoutDevice(String name) { 68 mName = name; 69 } 70 71 /** 72 * Saves the Layout Device into a document under a given node 73 * @param doc the document. 74 * @param parentNode the parent node. 75 */ saveTo(Document doc, Element parentNode)76 void saveTo(Document doc, Element parentNode) { 77 // create the device node 78 Element deviceNode = createNode(doc, parentNode, LayoutDevicesXsd.NODE_DEVICE); 79 80 // create the name attribute (no namespace on this one). 81 deviceNode.setAttribute(LayoutDevicesXsd.ATTR_NAME, mName); 82 83 // create a default with the x/y dpi 84 Element defaultNode = createNode(doc, deviceNode, LayoutDevicesXsd.NODE_DEFAULT); 85 if (Float.isNaN(mXDpi) == false) { 86 Element xdpiNode = createNode(doc, defaultNode, LayoutDevicesXsd.NODE_XDPI); 87 xdpiNode.setTextContent(Float.toString(mXDpi)); 88 } 89 if (Float.isNaN(mYDpi) == false) { 90 Element xdpiNode = createNode(doc, defaultNode, LayoutDevicesXsd.NODE_YDPI); 91 xdpiNode.setTextContent(Float.toString(mYDpi)); 92 } 93 94 // then save all the configs. 95 for (Entry<String, FolderConfiguration> entry : mEditMap.entrySet()) { 96 saveConfigTo(doc, deviceNode, entry.getKey(), entry.getValue()); 97 } 98 } 99 100 /** 101 * Creates and returns a new NS-enabled node. 102 * @param doc the {@link Document} 103 * @param parentNode the parent node. The new node is appended to this one as a child. 104 * @param name the name of the node. 105 * @return the newly created node. 106 */ createNode(Document doc, Element parentNode, String name)107 private Element createNode(Document doc, Element parentNode, String name) { 108 Element newNode = doc.createElementNS( 109 LayoutDevicesXsd.NS_LAYOUT_DEVICE_XSD, name); 110 newNode.setPrefix(doc.lookupPrefix(LayoutDevicesXsd.NS_LAYOUT_DEVICE_XSD)); 111 parentNode.appendChild(newNode); 112 113 return newNode; 114 } 115 116 /** 117 * Saves a {@link FolderConfiguration} in a {@link Document}. 118 * @param doc the Document in which to save 119 * @param parent the parent node 120 * @param configName the name of the config 121 * @param config the config to save 122 */ saveConfigTo(Document doc, Element parent, String configName, FolderConfiguration config)123 private void saveConfigTo(Document doc, Element parent, String configName, 124 FolderConfiguration config) { 125 Element configNode = createNode(doc, parent, LayoutDevicesXsd.NODE_CONFIG); 126 127 // create the name attribute (no namespace on this one). 128 configNode.setAttribute(LayoutDevicesXsd.ATTR_NAME, configName); 129 130 // now do the qualifiers 131 CountryCodeQualifier ccq = config.getCountryCodeQualifier(); 132 if (ccq != null) { 133 Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_COUNTRY_CODE); 134 node.setTextContent(Integer.toString(ccq.getCode())); 135 } 136 137 NetworkCodeQualifier ncq = config.getNetworkCodeQualifier(); 138 if (ncq != null) { 139 Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_NETWORK_CODE); 140 node.setTextContent(Integer.toString(ncq.getCode())); 141 } 142 143 ScreenSizeQualifier ssq = config.getScreenSizeQualifier(); 144 if (ssq != null) { 145 Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_SCREEN_SIZE); 146 node.setTextContent(ssq.getFolderSegment(null)); 147 } 148 149 ScreenRatioQualifier srq = config.getScreenRatioQualifier(); 150 if (srq != null) { 151 Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_SCREEN_RATIO); 152 node.setTextContent(srq.getFolderSegment(null)); 153 } 154 155 ScreenOrientationQualifier soq = config.getScreenOrientationQualifier(); 156 if (soq != null) { 157 Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_SCREEN_ORIENTATION); 158 node.setTextContent(soq.getFolderSegment(null)); 159 } 160 161 PixelDensityQualifier pdq = config.getPixelDensityQualifier(); 162 if (pdq != null) { 163 Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_PIXEL_DENSITY); 164 node.setTextContent(pdq.getFolderSegment(null)); 165 } 166 167 TouchScreenQualifier ttq = config.getTouchTypeQualifier(); 168 if (ttq != null) { 169 Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_TOUCH_TYPE); 170 node.setTextContent(ttq.getFolderSegment(null)); 171 } 172 173 KeyboardStateQualifier ksq = config.getKeyboardStateQualifier(); 174 if (ksq != null) { 175 Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_KEYBOARD_STATE); 176 node.setTextContent(ksq.getFolderSegment(null)); 177 } 178 179 TextInputMethodQualifier timq = config.getTextInputMethodQualifier(); 180 if (timq != null) { 181 Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_TEXT_INPUT_METHOD); 182 node.setTextContent(timq.getFolderSegment(null)); 183 } 184 185 NavigationMethodQualifier nmq = config.getNavigationMethodQualifier(); 186 if (nmq != null) { 187 Element node = createNode(doc, configNode, LayoutDevicesXsd.NODE_NAV_METHOD); 188 node.setTextContent(nmq.getFolderSegment(null)); 189 } 190 191 ScreenDimensionQualifier sdq = config.getScreenDimensionQualifier(); 192 if (sdq != null) { 193 Element sizeNode = createNode(doc, configNode, LayoutDevicesXsd.NODE_SCREEN_DIMENSION); 194 195 Element node = createNode(doc, sizeNode, LayoutDevicesXsd.NODE_SIZE); 196 node.setTextContent(Integer.toString(sdq.getValue1())); 197 198 node = createNode(doc, sizeNode, LayoutDevicesXsd.NODE_SIZE); 199 node.setTextContent(Integer.toString(sdq.getValue2())); 200 } 201 } 202 addConfig(String name, FolderConfiguration config)203 void addConfig(String name, FolderConfiguration config) { 204 mEditMap.put(name, config); 205 _seal(); 206 } 207 addConfigs(Map<String, FolderConfiguration> configs)208 void addConfigs(Map<String, FolderConfiguration> configs) { 209 mEditMap.putAll(configs); 210 _seal(); 211 } 212 removeConfig(String name)213 void removeConfig(String name) { 214 mEditMap.remove(name); 215 _seal(); 216 } 217 218 /** 219 * Adds config to the LayoutDevice. This is to be used to add plenty of configurations. 220 * It must be followed by {@link #_seal()}. 221 * @param name the name of the config 222 * @param config the config. 223 */ _addConfig(String name, FolderConfiguration config)224 void _addConfig(String name, FolderConfiguration config) { 225 mEditMap.put(name, config); 226 } 227 _seal()228 void _seal() { 229 mMap = Collections.unmodifiableMap(mEditMap); 230 } 231 setXDpi(float xdpi)232 void setXDpi(float xdpi) { 233 mXDpi = xdpi; 234 } 235 setYDpi(float ydpi)236 void setYDpi(float ydpi) { 237 mYDpi = ydpi; 238 } 239 getName()240 public String getName() { 241 return mName; 242 } 243 getConfigs()244 public Map<String, FolderConfiguration> getConfigs() { 245 return mMap; 246 } 247 248 /** 249 * Returns the dpi of the Device screen in X. 250 * @return the dpi of screen or {@link Float#NaN} if it's not set. 251 */ getXDpi()252 public float getXDpi() { 253 return mXDpi; 254 } 255 256 /** 257 * Returns the dpi of the Device screen in Y. 258 * @return the dpi of screen or {@link Float#NaN} if it's not set. 259 */ getYDpi()260 public float getYDpi() { 261 return mYDpi; 262 } 263 } 264