com.android.resources.base.BasicAttrResourceItem Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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 com.android.resources.base;
import static com.android.SdkConstants.URI_DOMAIN_PREFIX;
import com.android.ide.common.rendering.api.AttrResourceValue;
import com.android.ide.common.rendering.api.AttributeFormat;
import com.android.ide.common.rendering.api.ResourceNamespace;
import com.android.resources.ResourceType;
import com.android.resources.ResourceVisibility;
import com.android.utils.Base128InputStream;
import com.android.utils.Base128InputStream.StreamFormatException;
import com.android.utils.Base128OutputStream;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import java.io.IOException;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Resource item representing an attr resource.
*/
public class BasicAttrResourceItem extends BasicValueResourceItemBase implements AttrResourceValue {
@NotNull private Set myFormats;
/** The keys are enum or flag names, the values are corresponding numeric values. */
@NotNull private final Map myValueMap;
/** The keys are enum or flag names, the values are the value descriptions. */
@NotNull private final Map myValueDescriptionMap;
@Nullable private final String myDescription;
@Nullable private final String myGroupName;
/**
* Initializes the resource.
*
* @param name the name of the resource
* @param sourceFile the source file containing definition of the resource
* @param visibility the visibility of the resource
* @param description the description of the attr resource, if available
* @param groupName the name of the attr group, if available
* @param formats the allowed attribute formats
* @param valueMap the enum or flag integer values keyed by the value names. Some of the values in the
* map may be null. The map must contain the names of all declared values, even the ones that don't
* have corresponding numeric values.
* @param valueDescriptionMap the enum or flag value descriptions keyed by the value names
*/
public BasicAttrResourceItem(@NotNull String name,
@NotNull ResourceSourceFile sourceFile,
@NotNull ResourceVisibility visibility,
@Nullable String description,
@Nullable String groupName,
@NotNull Set formats,
@NotNull Map valueMap,
@NotNull Map valueDescriptionMap) {
super(ResourceType.ATTR, name, sourceFile, visibility);
myDescription = description;
myGroupName = groupName;
myFormats = ImmutableSet.copyOf(formats);
// Cannot use ImmutableMap.copyOf() since valueMap may contain null values.
myValueMap = valueMap.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(valueMap);
myValueDescriptionMap = valueDescriptionMap.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(valueDescriptionMap);
}
@Override
@NotNull
public final Set getFormats() {
return myFormats;
}
/**
* Replaces the set of the allowed attribute formats. Intended to be called only by the resource repository code.
*
* @param formats the new set of the allowed attribute formats
*/
public final void setFormats(@NotNull Set formats) {
myFormats = ImmutableSet.copyOf(formats);
}
@Override
@NotNull
public final Map getAttributeValues() {
return myValueMap;
}
@Override
@Nullable
public final String getValueDescription(@NotNull String valueName) {
return myValueDescriptionMap.get(valueName);
}
@Override
@Nullable
public final String getDescription() {
return myDescription;
}
@Override
@Nullable
public final String getGroupName() {
return myGroupName;
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) return true;
if (!super.equals(obj)) return false;
BasicAttrResourceItem other = (BasicAttrResourceItem) obj;
return Objects.equals(myDescription, other.myDescription) &&
Objects.equals(myGroupName, other.myGroupName) &&
myFormats.equals(other.myFormats) &&
myValueMap.equals(other.myValueMap) &&
myValueDescriptionMap.equals(other.myValueDescriptionMap);
}
/**
* Creates and returns an {@link BasicAttrReference} pointing to this attribute.
*/
@NotNull
public BasicAttrReference createReference() {
BasicAttrReference attrReference =
new BasicAttrReference(getNamespace(), getName(), getSourceFile(), getVisibility(), myDescription, myGroupName);
attrReference.setNamespaceResolver(getNamespaceResolver());
return attrReference;
}
@Override
public void serialize(@NotNull Base128OutputStream stream,
@NotNull Object2IntMap configIndexes,
@NotNull Object2IntMap sourceFileIndexes,
@NotNull Object2IntMap namespaceResolverIndexes) throws IOException {
super.serialize(stream, configIndexes, sourceFileIndexes, namespaceResolverIndexes);
serializeAttrValue(this, getRepository().getNamespace(), stream);
}
static void serializeAttrValue(@NotNull AttrResourceValue attr, @NotNull ResourceNamespace defaultNamespace,
@NotNull Base128OutputStream stream) throws IOException {
ResourceNamespace namespace = attr.getNamespace();
String namespaceSuffix = namespace.equals(defaultNamespace) ?
null : namespace.getXmlNamespaceUri().substring(URI_DOMAIN_PREFIX.length());
stream.writeString(namespaceSuffix);
stream.writeString(attr.getDescription());
stream.writeString(attr.getGroupName());
int formatMask = 0;
for (AttributeFormat format : attr.getFormats()) {
formatMask |= 1 << format.ordinal();
}
stream.writeInt(formatMask);
Map attributeValues = attr.getAttributeValues();
stream.writeInt(attributeValues.size());
for (Map.Entry entry : attributeValues.entrySet()) {
String name = entry.getKey();
stream.writeString(name);
Integer value = entry.getValue();
int v = value == null ? Integer.MIN_VALUE : value + 1; // Use value + 1 to reduce length of encoded -1 value.
stream.writeInt(v);
String description = attr.getValueDescription(name);
stream.writeString(description);
}
}
/**
* Creates a BasicAttrResourceItem by reading its contents from the given stream.
*/
@NotNull
static BasicValueResourceItemBase deserialize(@NotNull Base128InputStream stream,
@NotNull String name,
@NotNull ResourceVisibility visibility,
@NotNull ResourceSourceFile sourceFile,
@NotNull ResourceNamespace.Resolver resolver) throws IOException {
String namespaceSuffix = stream.readString();
String description = stream.readString();
String groupName = stream.readString();
int formatMask = stream.readInt();
Set formats = EnumSet.noneOf(AttributeFormat.class);
AttributeFormat[] attributeFormatValues = AttributeFormat.values();
for (int ordinal = 0; ordinal < attributeFormatValues.length && formatMask != 0; ordinal++, formatMask >>>= 1) {
if ((formatMask & 0x1) != 0) {
formats.add(attributeFormatValues[ordinal]);
}
}
int n = stream.readInt();
Map valueMap = n == 0 ? Collections.emptyMap() : Maps.newHashMapWithExpectedSize(n);
Map descriptionMap = n == 0 ? Collections.emptyMap() : Maps.newHashMapWithExpectedSize(n);
for (int i = 0; i < n; i++) {
String valueName = stream.readString();
int value = stream.readInt();
if (value != Integer.MIN_VALUE) {
valueMap.put(valueName, value - 1);
}
String valueDescription = stream.readString();
if (valueDescription != null) {
descriptionMap.put(valueName, valueDescription);
}
}
BasicValueResourceItemBase item;
if (formats.isEmpty() && valueMap.isEmpty()) {
ResourceNamespace namespace = namespaceSuffix == null ?
sourceFile.getRepository().getNamespace() :
ResourceNamespace.fromNamespaceUri(URI_DOMAIN_PREFIX + namespaceSuffix);
if (namespace == null) {
throw StreamFormatException.invalidFormat();
}
item = new BasicAttrReference(namespace, name, sourceFile, visibility, description, groupName);
}
else if (namespaceSuffix == null) {
item = new BasicAttrResourceItem(name, sourceFile, visibility, description, groupName, formats, valueMap, descriptionMap);
}
else {
ResourceNamespace namespace = ResourceNamespace.fromNamespaceUri(URI_DOMAIN_PREFIX + namespaceSuffix);
if (namespace == null) {
throw StreamFormatException.invalidFormat();
}
item = new BasicForeignAttrResourceItem(namespace, name, sourceFile, description, groupName, formats, valueMap, descriptionMap);
}
item.setNamespaceResolver(resolver);
return item;
}
}