xref: /aosp_15_r20/external/bazelbuild-rules_android/src/tools/ak/res/struct.go (revision 9e965d6fece27a77de5377433c2f7e6999b8cc0b)
1// Copyright 2018 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package res handles understanding and representing information about Android resources.
16package res
17
18import (
19	"errors"
20	"fmt"
21	"strconv"
22	"strings"
23
24	rdpb "src/tools/ak/res/proto/res_data_go_proto"
25)
26
27var (
28	// ErrWrongType occurs when a type is used in an operation that it does not support.
29	ErrWrongType = errors.New("this type cannot be used in this operation")
30)
31
32// Type of resource (eg: string, layout, drawable)
33type Type rdpb.Resource_Type
34
35// Enum converts a Type into a enum proto value
36func (t Type) Enum() (rdpb.Resource_Type, error) {
37	if !t.IsSerializable() {
38		return rdpb.Resource_Type(ValueType), ErrWrongType
39	}
40	return rdpb.Resource_Type(t), nil
41}
42
43// IsSerializable indicates that the Type can be converted to a proto (some types are only for in memory operations).
44func (t Type) IsSerializable() bool {
45	for _, a := range nonProtoTypes {
46		if t == a {
47			return false
48		}
49	}
50	return true
51}
52
53// NestedClassName is the R.java nested class name for this type (if the type is understood by android).
54func (t Type) NestedClassName() (string, error) {
55	if !t.IsReal() {
56		return "", ErrWrongType
57	}
58	return typeToString[t], nil
59}
60
61// IsReal indicates that the type is known to the android framework.
62func (t Type) IsReal() bool {
63	for _, a := range nonProtoTypes {
64		if a == t {
65			return false
66		}
67	}
68	return true
69}
70
71// From frameworks/base/tools/aapt2/Resource.h, except UnknownType and ValueType
72// TODO(mauriciogg): use proto definitions and remove ValueType and UnknownType.
73const (
74	// UnknownType needs to be zero value
75	UnknownType Type = -2
76	ValueType        = -1
77
78	// Anim represents Android Anim resource types.
79	Anim = Type(rdpb.Resource_ANIM)
80	// Animator represents Android Animator resource types.
81	Animator = Type(rdpb.Resource_ANIMATOR)
82	// Array represents Android Array resource types.
83	Array = Type(rdpb.Resource_ARRAY)
84	// Attr represents Android Attr resource types.
85	Attr = Type(rdpb.Resource_ATTR)
86	// AttrPrivate represents Android AttrPrivate resource types.
87	AttrPrivate = Type(rdpb.Resource_ATTR_PRIVATE)
88	// Bool represents Android Bool resource types.
89	Bool = Type(rdpb.Resource_BOOL)
90	// Color represents Android Color resource types.
91	Color = Type(rdpb.Resource_COLOR)
92	// ConfigVarying represents Android ConfigVarying resource types, not really a type, but it shows up in some CTS tests
93	ConfigVarying = Type(rdpb.Resource_CONFIG_VARYING)
94	// Dimen represents Android Dimen resource types.
95	Dimen = Type(rdpb.Resource_DIMEN)
96	// Drawable represents Android Drawable resource types.
97	Drawable = Type(rdpb.Resource_DRAWABLE)
98	// Font represents Android Font resource types.
99	Font = Type(rdpb.Resource_FONT)
100	// Fraction represents Android Fraction resource types.
101	Fraction = Type(rdpb.Resource_FRACTION)
102	// ID represents Android Id resource types.
103	ID = Type(rdpb.Resource_ID)
104	// Integer represents Android Integer resource types.
105	Integer = Type(rdpb.Resource_INTEGER)
106	// Interpolator represents Android Interpolator resource types.
107	Interpolator = Type(rdpb.Resource_INTERPOLATOR)
108	// Layout represents Android Layout resource types.
109	Layout = Type(rdpb.Resource_LAYOUT)
110	// Menu represents Android Menu resource types.
111	Menu = Type(rdpb.Resource_MENU)
112	// Mipmap represents Android Mipmap resource types.
113	Mipmap = Type(rdpb.Resource_MIPMAP)
114	// Navigation represents Android Navigation resource types.
115	Navigation = Type(rdpb.Resource_NAVIGATION)
116	// Plurals represents Android Plurals resource types.
117	Plurals = Type(rdpb.Resource_PLURALS)
118	// Raw represents Android Raw resource types.
119	Raw = Type(rdpb.Resource_RAW)
120	// String represents Android String resource types.
121	String = Type(rdpb.Resource_STRING)
122	// Style represents Android Style resource types.
123	Style = Type(rdpb.Resource_STYLE)
124	// Styleable represents Android Styleable resource types.
125	Styleable = Type(rdpb.Resource_STYLEABLE)
126	// Transition represents Android Transition resource types.
127	Transition = Type(rdpb.Resource_TRANSITION)
128	// XML represents Android Xml resource types.
129	XML = Type(rdpb.Resource_XML)
130)
131
132var (
133	// A fixed mapping between the string representation of a type and its Type.
134	typeToString = map[Type]string{
135		Anim:          "anim",
136		Animator:      "animator",
137		Array:         "array",
138		Attr:          "attr",
139		AttrPrivate:   "^attr-private",
140		Bool:          "bool",
141		Color:         "color",
142		ConfigVarying: "configVarying",
143		Dimen:         "dimen",
144		Drawable:      "drawable",
145		Fraction:      "fraction",
146		Font:          "font",
147		ID:            "id",
148		Integer:       "integer",
149		Interpolator:  "interpolator",
150		Layout:        "layout",
151		Menu:          "menu",
152		Mipmap:        "mipmap",
153		Navigation:    "navigation",
154		Plurals:       "plurals",
155		Raw:           "raw",
156		String:        "string",
157		Style:         "style",
158		Styleable:     "styleable",
159		Transition:    "transition",
160		XML:           "xml",
161	}
162	stringToType = make(map[string]Type)
163	// AllTypes is a list of all known resource types.
164	AllTypes = make([]Type, 0, len(typeToString))
165
166	// These types are not allowed to be serialized into proto format.
167	nonProtoTypes = []Type{ValueType, UnknownType}
168)
169
170// Kind indicates what type of resource file emits this resource. A resource can be found in
171// res/values folder (and therefore is a Value - which can be represented as a ResourceValue in
172// Android) or in folders outside of res/values (such as res/layout) and thus are not ResourceValues
173// but rather some external resource (such as an image or parsed xml file).
174type Kind uint8
175
176const (
177	// Unknown should not be encountered.
178	Unknown Kind = iota
179	// Value can only be encountered in res/values folders.
180	Value
181	// NonValue can not be encountered in res/values folders.
182	NonValue
183	// Both  is a Kind of Type which may be inside a res/values folder or in another res/ folder.
184	Both
185)
186
187var (
188	kindToString = map[Kind]string{
189		Unknown:  "Unknown",
190		Value:    "Value",
191		NonValue: "NonValue",
192		Both:     "Both",
193	}
194
195	// A fixed mapping between Type and Kind.
196	TypesToKind = map[Type]Kind{
197		Anim:          NonValue,
198		Animator:      NonValue,
199		Array:         Value,
200		Attr:          Value,
201		AttrPrivate:   Value,
202		Bool:          Value,
203		Color:         Both,
204		ConfigVarying: Value,
205		Dimen:         Value,
206		Drawable:      NonValue,
207		Font:          NonValue,
208		Fraction:      Value,
209		ID:            Value,
210		Integer:       Value,
211		Interpolator:  NonValue,
212		Layout:        NonValue,
213		Menu:          NonValue,
214		Mipmap:        NonValue,
215		Navigation:    NonValue,
216		Plurals:       Value,
217		Raw:           NonValue,
218		String:        Value,
219		Style:         Value,
220		Styleable:     Value,
221		Transition:    NonValue,
222		XML:           NonValue,
223	}
224)
225
226// Density represents the dpi value of a resource.
227type Density uint16
228
229// From frameworks/base/core/java/Android/content/res/Configuration.java
230const (
231	// UnspecifiedDensity is a default value indicating no dpi has been specified
232	UnspecifiedDensity Density = 0
233
234	// LDPI has a dpi of 120
235	LDPI Density = 120
236	// MDPI has a dpi of 160
237	MDPI Density = 160
238	// TVDPI has a dpi of 213
239	TVDPI Density = 213
240	// HDPI has a dpi of 240
241	HDPI Density = 240
242	// XhDPI has a dpi of 320
243	XhDPI Density = 320
244	// XxhDPI has a dpi of 480
245	XxhDPI Density = 480
246	// XxxhDPI has a dpi of 640
247	XxxhDPI Density = 640
248	// AnyDPI indicates a resource which can be any dpi.
249	AnyDPI Density = 0xfffe
250	// NoDPI indicates the resources have no dpi constraints
251	NoDPI     Density = 0xffff
252	dpiSuffix         = "dpi"
253)
254
255var (
256	densityToStr = map[Density]string{
257		LDPI:    "ldpi",
258		MDPI:    "mdpi",
259		TVDPI:   "tvdpi",
260		HDPI:    "hdpi",
261		XhDPI:   "xhdpi",
262		XxhDPI:  "xxhdpi",
263		XxxhDPI: "xxxhdpi",
264		AnyDPI:  "anydpi",
265		NoDPI:   "nodpi",
266	}
267	strToDensity = make(map[string]Density)
268)
269
270// ParseValueOrType converts a string into a value type or well known type
271func ParseValueOrType(s string) (Type, error) {
272	if s == "values" {
273		return ValueType, nil
274	}
275	return ParseType(s)
276}
277
278// ParseType converts a string into a well known type
279func ParseType(s string) (Type, error) {
280	if t, ok := stringToType[s]; ok {
281		return t, nil
282	}
283	return UnknownType, fmt.Errorf("%s: unknown type", s)
284}
285
286// String for Type structs corresponds to the string format known to Android.
287func (t Type) String() string {
288	if s, ok := typeToString[t]; ok {
289		return s
290	}
291	return fmt.Sprintf("Type(%d)", t)
292}
293
294// Kind indicates the resource kind of this type.
295func (t Type) Kind() Kind {
296	if t == ValueType {
297		return Value
298	}
299	if t, ok := TypesToKind[t]; ok {
300		return t
301	}
302	return Unknown
303}
304
305// ParseDensity converts a string representation of a density into a Density.
306func ParseDensity(s string) (Density, error) {
307	if d, ok := strToDensity[s]; ok {
308		return d, nil
309	}
310	if strings.HasSuffix(s, dpiSuffix) {
311		parsed, err := strconv.ParseUint(s[0:len(s)-len(dpiSuffix)], 10, 16)
312		if err != nil {
313			return 0, fmt.Errorf("%s: unparsable: %v", s, err)
314		}
315		return Density(parsed), nil
316	}
317	return UnspecifiedDensity, nil
318}
319
320func init() {
321	for k, v := range typeToString {
322		AllTypes = append(AllTypes, k)
323		stringToType[v] = k
324	}
325	for k, v := range densityToStr {
326		strToDensity[v] = k
327	}
328}
329