1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 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 // Copied from tools/base/layoutlib-api 18 19 package com.android.resources; 20 21 import com.android.SdkConstants; 22 import com.google.common.base.Strings; 23 import com.google.common.collect.ImmutableMap; 24 import com.google.common.collect.ImmutableSet; 25 import com.google.common.collect.Sets; 26 import org.w3c.dom.Element; 27 import org.w3c.dom.Node; 28 29 import java.util.Arrays; 30 import java.util.function.BiFunction; 31 import java.util.function.Function; 32 33 import static com.google.common.base.MoreObjects.firstNonNull; 34 35 /** 36 * Enum representing a type of compiled resource. 37 * 38 * <p>See {@code ResourceType} in aapt2/Resource.h. 39 */ 40 public enum ResourceType { 41 ANIM("anim", "Animation"), 42 ANIMATOR("animator", "Animator"), 43 ARRAY("array", "Array", "string-array", "integer-array"), 44 ATTR("attr", "Attr"), 45 BOOL("bool", "Boolean"), 46 COLOR("color", "Color"), 47 DIMEN("dimen", "Dimension"), 48 DRAWABLE("drawable", "Drawable"), 49 FONT("font", "Font"), 50 FRACTION("fraction", "Fraction"), 51 ID("id", "ID"), 52 INTEGER("integer", "Integer"), 53 INTERPOLATOR("interpolator", "Interpolator"), 54 LAYOUT("layout", "Layout"), 55 MENU("menu", "Menu"), 56 MIPMAP("mipmap", "Mip Map"), 57 NAVIGATION("navigation", "Navigation"), 58 PLURALS("plurals", "Plurals"), 59 RAW("raw", "Raw"), 60 STRING("string", "String"), 61 STYLE("style", "Style"), 62 STYLEABLE("styleable", "Styleable", Kind.STYLEABLE), 63 TRANSITION("transition", "Transition"), 64 XML("xml", "XML"), 65 66 /** 67 * This is not actually used. Only there because they get parsed and since we want to detect new 68 * resource type, we need to have this one exist. 69 */ 70 PUBLIC("public", "Public visibility modifier", Kind.SYNTHETIC), 71 72 /** 73 * This type is used for elements dynamically generated by the parsing of aapt:attr nodes. The 74 * "aapt:attr" allow to inline resources as part of a different resource, for example, a 75 * drawable as part of a layout. When the parser, encounters one of this nodes, it will generate 76 * a synthetic _aaptattr reference. 77 */ 78 AAPT("_aapt", "Aapt Attribute", Kind.SYNTHETIC), 79 80 /** 81 * Represents item tags inside a style definition. 82 */ 83 STYLE_ITEM("item", "Style Item", Kind.SYNTHETIC), 84 85 /** 86 * Not an actual resource type from AAPT. Used to provide sample data values in the tools 87 * namespace 88 */ 89 SAMPLE_DATA("sample", "Sample data", Kind.SYNTHETIC), 90 ; 91 92 private enum Kind { 93 /** 94 * These types are used both in the R and as XML tag names. 95 */ 96 REAL, 97 98 /** 99 * Styleables are handled by aapt but don't end up in the resource table. They have an R 100 * inner class (called {@code styleable}), are declared in XML (using {@code 101 * declare-styleable}) but cannot be referenced from XML. 102 */ 103 STYLEABLE, 104 105 /** 106 * Other types that are not known to aapt, but are used by tools to represent some 107 * information in the resources system. 108 */ 109 SYNTHETIC, 110 ; 111 } 112 113 private final String mName; 114 private final Kind mKind; 115 private final String mDisplayName; 116 private final String[] mAlternateXmlNames; 117 ResourceType( String name, String displayName, String... alternateXmlNames)118 ResourceType( 119 String name, 120 String displayName, 121 String... alternateXmlNames) { 122 mName = name; 123 mKind = Kind.REAL; 124 mDisplayName = displayName; 125 mAlternateXmlNames = alternateXmlNames; 126 } 127 ResourceType(String name, String displayName, Kind kind)128 ResourceType(String name, String displayName, Kind kind) { 129 mName = name; 130 mKind = kind; 131 mDisplayName = displayName; 132 mAlternateXmlNames = new String[0]; 133 } 134 135 /** 136 * The set of all types of resources that can be referenced by other resources. 137 */ 138 public static final ImmutableSet<ResourceType> REFERENCEABLE_TYPES; 139 140 private static final ImmutableMap<String, ResourceType> TAG_NAMES; 141 private static final ImmutableMap<String, ResourceType> CLASS_NAMES; 142 143 static { 144 ImmutableMap.Builder<String, ResourceType> tagNames = ImmutableMap.builder(); tagNames.put(SdkConstants.TAG_DECLARE_STYLEABLE, STYLEABLE)145 tagNames.put(SdkConstants.TAG_DECLARE_STYLEABLE, STYLEABLE); tagNames.put(SdkConstants.TAG_PUBLIC, PUBLIC)146 tagNames.put(SdkConstants.TAG_PUBLIC, PUBLIC); 147 148 ImmutableMap.Builder<String, ResourceType> classNames = ImmutableMap.builder(); classNames.put(STYLEABLE.mName, STYLEABLE)149 classNames.put(STYLEABLE.mName, STYLEABLE); classNames.put(AAPT.mName, AAPT)150 classNames.put(AAPT.mName, AAPT); 151 152 for (ResourceType type : ResourceType.values()) { 153 if (type.mKind != Kind.REAL || type == STYLEABLE) { 154 continue; 155 } type.getName()156 classNames.put(type.getName(), type); type.getName()157 tagNames.put(type.getName(), type); 158 for (String alternateName : type.mAlternateXmlNames) { tagNames.put(alternateName, type)159 tagNames.put(alternateName, type); 160 } 161 } 162 163 TAG_NAMES = tagNames.build(); 164 CLASS_NAMES = classNames.build(); 165 REFERENCEABLE_TYPES = 166 Arrays.stream(values()) 167 .filter(ResourceType::getCanBeReferenced) 168 .collect(Sets.toImmutableEnumSet()); 169 } 170 171 /** 172 * Returns the resource type name, as used by XML files. 173 */ getName()174 public String getName() { 175 return mName; 176 } 177 178 /** 179 * Returns a translated display name for the resource type. 180 */ getDisplayName()181 public String getDisplayName() { 182 return mDisplayName; 183 } 184 185 /** 186 * Returns the enum by its name as it appears in the R class. 187 * 188 * @param className name of the inner class of the R class, e.g. "string" or "styleable". 189 */ 190 fromClassName(String className)191 public static ResourceType fromClassName(String className) { 192 return CLASS_NAMES.get(className); 193 } 194 195 /** 196 * Returns the enum by its name as it appears as a folder name under {@code res/}. 197 * 198 * @param folderName name of the inner class of the R class, e.g. "drawable" or "color". 199 */ 200 fromFolderName(String folderName)201 public static ResourceType fromFolderName(String folderName) { 202 return CLASS_NAMES.get(folderName); 203 } 204 205 /** 206 * Returns the enum by its name as it appears in XML as a tag name. 207 * 208 * @param tagName name of the XML tag, e.g. "string" or "declare-styleable". 209 */ 210 fromXmlTagName(String tagName)211 public static ResourceType fromXmlTagName(String tagName) { 212 return TAG_NAMES.get(tagName); 213 } 214 215 /** 216 * Returns the enum by its name as it appears in a {@link ResourceUrl} string. 217 * 218 * @param xmlValue value of the type attribute or the prefix of a {@link ResourceUrl}, e.g. 219 * "string" or "array". 220 */ 221 fromXmlValue(String xmlValue)222 public static ResourceType fromXmlValue(String xmlValue) { 223 if (xmlValue.equals(SdkConstants.TAG_DECLARE_STYLEABLE) 224 || xmlValue.equals(STYLEABLE.mName)) { 225 return null; 226 } 227 228 if (xmlValue.equals(SAMPLE_DATA.mName)) { 229 return SAMPLE_DATA; 230 } 231 232 return CLASS_NAMES.get(xmlValue); 233 } 234 fromXmlTag( T tag, Function<T, String> nameFunction, BiFunction<T, String, String> attributeFunction)235 public static <T> ResourceType fromXmlTag( 236 T tag, 237 Function<T, String> nameFunction, 238 BiFunction<T, String, String> attributeFunction) { 239 String tagName = nameFunction.apply(tag); 240 switch (tagName) { 241 case SdkConstants.TAG_EAT_COMMENT: 242 return null; 243 case SdkConstants.TAG_ITEM: 244 String typeAttribute = attributeFunction.apply(tag, SdkConstants.ATTR_TYPE); 245 if (!Strings.isNullOrEmpty(typeAttribute)) { 246 return fromClassName(typeAttribute); 247 } else { 248 return null; 249 } 250 default: 251 return fromXmlTagName(tagName); 252 } 253 } 254 fromXmlTag(Node domNode)255 public static ResourceType fromXmlTag(Node domNode) { 256 if (!(domNode instanceof Element)) { 257 return null; 258 } 259 260 Element tag = (Element) domNode; 261 return fromXmlTag( 262 tag, 263 element -> firstNonNull(element.getLocalName(), element.getTagName()), 264 Element::getAttribute); 265 } 266 267 /** 268 * @deprecated Use other static methods in this class. Kept for layoutlib binary compatibility. 269 */ 270 @Deprecated getEnum(String className)271 public static ResourceType getEnum(String className) { 272 return fromClassName(className); 273 } 274 275 /** 276 * Returns true if the generated R class contains an inner class for this {@link ResourceType}. 277 */ getHasInnerClass()278 public boolean getHasInnerClass() { 279 return mKind != Kind.SYNTHETIC; 280 } 281 282 /** 283 * Returns true if this {@link ResourceType} can be referenced using the {@link ResourceUrl} 284 * syntax: {@code @typeName/resourceName}. 285 */ getCanBeReferenced()286 public boolean getCanBeReferenced() { 287 return mKind == Kind.REAL && this != ATTR; 288 } 289 290 @Override toString()291 public String toString() { 292 // Unfortunately we still have code that relies on toString() returning the aapt name. 293 return getName(); 294 } 295 } 296