blob: b58e8545a5d76a5396e28a84c2a71091ca427c22 [file] [log] [blame]
// Copyright 2018 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package res handles understanding and representing information about Android resources.
package res
import (
"errors"
"fmt"
"strconv"
"strings"
rdpb "src/tools/ak/res/proto/res_data_go_proto"
)
var (
// ErrWrongType occurs when a type is used in an operation that it does not support.
ErrWrongType = errors.New("this type cannot be used in this operation")
)
// Type of resource (eg: string, layout, drawable)
type Type rdpb.Resource_Type
// Enum converts a Type into a enum proto value
func (t Type) Enum() (rdpb.Resource_Type, error) {
if !t.IsSerializable() {
return rdpb.Resource_Type(ValueType), ErrWrongType
}
return rdpb.Resource_Type(t), nil
}
// IsSerializable indicates that the Type can be converted to a proto (some types are only for in memory operations).
func (t Type) IsSerializable() bool {
for _, a := range nonProtoTypes {
if t == a {
return false
}
}
return true
}
// NestedClassName is the R.java nested class name for this type (if the type is understood by android).
func (t Type) NestedClassName() (string, error) {
if !t.IsReal() {
return "", ErrWrongType
}
return typeToString[t], nil
}
// IsReal indicates that the type is known to the android framework.
func (t Type) IsReal() bool {
for _, a := range nonProtoTypes {
if a == t {
return false
}
}
return true
}
// From frameworks/base/tools/aapt2/Resource.h, except UnknownType and ValueType
// TODO(mauriciogg): use proto definitions and remove ValueType and UnknownType.
const (
// UnknownType needs to be zero value
UnknownType Type = -2
ValueType = -1
// Anim represents Android Anim resource types.
Anim = Type(rdpb.Resource_ANIM)
// Animator represents Android Animator resource types.
Animator = Type(rdpb.Resource_ANIMATOR)
// Array represents Android Array resource types.
Array = Type(rdpb.Resource_ARRAY)
// Attr represents Android Attr resource types.
Attr = Type(rdpb.Resource_ATTR)
// AttrPrivate represents Android AttrPrivate resource types.
AttrPrivate = Type(rdpb.Resource_ATTR_PRIVATE)
// Bool represents Android Bool resource types.
Bool = Type(rdpb.Resource_BOOL)
// Color represents Android Color resource types.
Color = Type(rdpb.Resource_COLOR)
// ConfigVarying represents Android ConfigVarying resource types, not really a type, but it shows up in some CTS tests
ConfigVarying = Type(rdpb.Resource_CONFIG_VARYING)
// Dimen represents Android Dimen resource types.
Dimen = Type(rdpb.Resource_DIMEN)
// Drawable represents Android Drawable resource types.
Drawable = Type(rdpb.Resource_DRAWABLE)
// Font represents Android Font resource types.
Font = Type(rdpb.Resource_FONT)
// Fraction represents Android Fraction resource types.
Fraction = Type(rdpb.Resource_FRACTION)
// ID represents Android Id resource types.
ID = Type(rdpb.Resource_ID)
// Integer represents Android Integer resource types.
Integer = Type(rdpb.Resource_INTEGER)
// Interpolator represents Android Interpolator resource types.
Interpolator = Type(rdpb.Resource_INTERPOLATOR)
// Layout represents Android Layout resource types.
Layout = Type(rdpb.Resource_LAYOUT)
// Menu represents Android Menu resource types.
Menu = Type(rdpb.Resource_MENU)
// Mipmap represents Android Mipmap resource types.
Mipmap = Type(rdpb.Resource_MIPMAP)
// Navigation represents Android Navigation resource types.
Navigation = Type(rdpb.Resource_NAVIGATION)
// Plurals represents Android Plurals resource types.
Plurals = Type(rdpb.Resource_PLURALS)
// Raw represents Android Raw resource types.
Raw = Type(rdpb.Resource_RAW)
// String represents Android String resource types.
String = Type(rdpb.Resource_STRING)
// Style represents Android Style resource types.
Style = Type(rdpb.Resource_STYLE)
// Styleable represents Android Styleable resource types.
Styleable = Type(rdpb.Resource_STYLEABLE)
// Transition represents Android Transition resource types.
Transition = Type(rdpb.Resource_TRANSITION)
// XML represents Android Xml resource types.
XML = Type(rdpb.Resource_XML)
)
var (
// A fixed mapping between the string representation of a type and its Type.
typeToString = map[Type]string{
Anim: "anim",
Animator: "animator",
Array: "array",
Attr: "attr",
AttrPrivate: "^attr-private",
Bool: "bool",
Color: "color",
ConfigVarying: "configVarying",
Dimen: "dimen",
Drawable: "drawable",
Fraction: "fraction",
Font: "font",
ID: "id",
Integer: "integer",
Interpolator: "interpolator",
Layout: "layout",
Menu: "menu",
Mipmap: "mipmap",
Navigation: "navigation",
Plurals: "plurals",
Raw: "raw",
String: "string",
Style: "style",
Styleable: "styleable",
Transition: "transition",
XML: "xml",
}
stringToType = make(map[string]Type)
// AllTypes is a list of all known resource types.
AllTypes = make([]Type, 0, len(typeToString))
// These types are not allowed to be serialized into proto format.
nonProtoTypes = []Type{ValueType, UnknownType}
)
// Kind indicates what type of resource file emits this resource. A resource can be found in
// res/values folder (and therefore is a Value - which can be represented as a ResourceValue in
// Android) or in folders outside of res/values (such as res/layout) and thus are not ResourceValues
// but rather some external resource (such as an image or parsed xml file).
type Kind uint8
const (
// Unknown should not be encountered.
Unknown Kind = iota
// Value can only be encountered in res/values folders.
Value
// NonValue can not be encountered in res/values folders.
NonValue
// Both is a Kind of Type which may be inside a res/values folder or in another res/ folder.
Both
)
var (
kindToString = map[Kind]string{
Unknown: "Unknown",
Value: "Value",
NonValue: "NonValue",
Both: "Both",
}
// A fixed mapping between Type and Kind.
TypesToKind = map[Type]Kind{
Anim: NonValue,
Animator: NonValue,
Array: Value,
Attr: Value,
AttrPrivate: Value,
Bool: Value,
Color: Both,
ConfigVarying: Value,
Dimen: Value,
Drawable: NonValue,
Font: NonValue,
Fraction: Value,
ID: Value,
Integer: Value,
Interpolator: NonValue,
Layout: NonValue,
Menu: NonValue,
Mipmap: NonValue,
Navigation: NonValue,
Plurals: Value,
Raw: NonValue,
String: Value,
Style: Value,
Styleable: Value,
Transition: NonValue,
XML: NonValue,
}
)
// Density represents the dpi value of a resource.
type Density uint16
// From frameworks/base/core/java/Android/content/res/Configuration.java
const (
// UnspecifiedDensity is a default value indicating no dpi has been specified
UnspecifiedDensity Density = 0
// LDPI has a dpi of 120
LDPI Density = 120
// MDPI has a dpi of 160
MDPI Density = 160
// TVDPI has a dpi of 213
TVDPI Density = 213
// HDPI has a dpi of 240
HDPI Density = 240
// XhDPI has a dpi of 320
XhDPI Density = 320
// XxhDPI has a dpi of 480
XxhDPI Density = 480
// XxxhDPI has a dpi of 640
XxxhDPI Density = 640
// AnyDPI indicates a resource which can be any dpi.
AnyDPI Density = 0xfffe
// NoDPI indicates the resources have no dpi constraints
NoDPI Density = 0xffff
dpiSuffix = "dpi"
)
var (
densityToStr = map[Density]string{
LDPI: "ldpi",
MDPI: "mdpi",
TVDPI: "tvdpi",
HDPI: "hdpi",
XhDPI: "xhdpi",
XxhDPI: "xxhdpi",
XxxhDPI: "xxxhdpi",
AnyDPI: "anydpi",
NoDPI: "nodpi",
}
strToDensity = make(map[string]Density)
)
// ParseValueOrType converts a string into a value type or well known type
func ParseValueOrType(s string) (Type, error) {
if s == "values" {
return ValueType, nil
}
return ParseType(s)
}
// ParseType converts a string into a well known type
func ParseType(s string) (Type, error) {
if t, ok := stringToType[s]; ok {
return t, nil
}
return UnknownType, fmt.Errorf("%s: unknown type", s)
}
// String for Type structs corresponds to the string format known to Android.
func (t Type) String() string {
if s, ok := typeToString[t]; ok {
return s
}
return fmt.Sprintf("Type(%d)", t)
}
// Kind indicates the resource kind of this type.
func (t Type) Kind() Kind {
if t == ValueType {
return Value
}
if t, ok := TypesToKind[t]; ok {
return t
}
return Unknown
}
// ParseDensity converts a string representation of a density into a Density.
func ParseDensity(s string) (Density, error) {
if d, ok := strToDensity[s]; ok {
return d, nil
}
if strings.HasSuffix(s, dpiSuffix) {
parsed, err := strconv.ParseUint(s[0:len(s)-len(dpiSuffix)], 10, 16)
if err != nil {
return 0, fmt.Errorf("%s: unparsable: %v", s, err)
}
return Density(parsed), nil
}
return UnspecifiedDensity, nil
}
func init() {
for k, v := range typeToString {
AllTypes = append(AllTypes, k)
stringToType[v] = k
}
for k, v := range densityToStr {
strToDensity[v] = k
}
}