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