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