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