All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.robolectric.res.Attribute Maven / Gradle / Ivy

There is a newer version: 3.4-rc2
Show newest version
package org.robolectric.res;

import org.jetbrains.annotations.NotNull;
import org.w3c.dom.Node;

import java.net.URLEncoder;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Attribute {
  public static final String ANDROID_RES_NS_PREFIX = "http://schemas.android.com/apk/res/";
  private static final int ANDROID_RES_NS_PREFIX_LENGTH = ANDROID_RES_NS_PREFIX.length();
  private static final Logger LOGGER = Logger.getLogger(Attribute.class.getName());
  public static final String RES_AUTO_NS_URI = "http://schemas.android.com/apk/res-auto";

  public final @NotNull ResName resName;
  public final @NotNull String value;
  public final @NotNull String contextPackageName;


  public static Attribute find(List attributes, String fullyQualifiedName) {
    return find(attributes, new ResName(fullyQualifiedName));
  }

  public static Attribute find(List attributes, ResName resName) {
    for (Attribute attribute : attributes) {
      if (resName.equals(attribute.resName)) {
        return attribute;
      }
    }
    return null;
  }

  public static Attribute find(List attributes, int attrId, ResourceIndex resourceIndex) {
    for (Attribute attribute : attributes) {
      Integer resourceId = resourceIndex.getResourceId(attribute.resName);
      if (resourceId != null && resourceId == attrId) {
        return attribute;
      }
    }
    return null;
  }

  public static String findValue(List attributes, String fullyQualifiedName) {
    return findValue(attributes, fullyQualifiedName, null);
  }

  public static String findValue(List attributes, String fullyQualifiedName, String defaultValue) {
    Attribute attribute = find(attributes, fullyQualifiedName);
    return (attribute != null) ? attribute.value : defaultValue;
  }

  public static void put(List attributes, Attribute attribute) {
    remove(attributes, attribute.resName);
    attributes.add(attribute);
  }

  public static Attribute remove(List attributes, String fullyQualifiedName) {
    return remove(attributes, new ResName(fullyQualifiedName));
  }

  public static Attribute remove(List attributes, ResName resName) {
    for (int i = 0; i < attributes.size(); i++) {
      Attribute attribute = attributes.get(i);
      if (resName.equals(attribute.resName)) {
        attributes.remove(i);
        return attribute;
      }
    }
    return null;
  }

  public static String addType(String possiblyPartiallyQualifiedAttrName, String typeName) {
    return possiblyPartiallyQualifiedAttrName.contains(":") ? possiblyPartiallyQualifiedAttrName.replaceFirst(":", ":" + typeName + "/") : ":" + typeName + "/" + possiblyPartiallyQualifiedAttrName;
  }

  public static String qualifyName(String possiblyQualifiedAttrName, String defaultPackage) {
    if (possiblyQualifiedAttrName.indexOf(':') == -1) {
      return defaultPackage + ":" + possiblyQualifiedAttrName;
    }
    return possiblyQualifiedAttrName;
  }

  public Attribute(@NotNull String fullyQualifiedName, @NotNull String value, @NotNull String contextPackageName) {
    this(new ResName(fullyQualifiedName), value, contextPackageName);
  }

  public Attribute(@NotNull ResName resName, @NotNull String value, @NotNull String contextPackageName) {
    if (!resName.type.equals("attr")) throw new IllegalStateException("\"" + resName.getFullyQualifiedName() + "\" unexpected");

    this.resName = resName;
    this.value = value;
    this.contextPackageName = contextPackageName;
  }

  public Attribute(Node attr, XmlLoader.XmlContext xmlContext) {
    this(extractPackageName(attr.getNamespaceURI(), xmlContext) + ":attr/" + attr.getLocalName(),
        attr.getNodeValue(),
        xmlContext.packageName);
  }

  private static String extractPackageName(String namespaceUri, XmlLoader.XmlContext xmlContext) {
    if (namespaceUri == null) {
      return "";
    }

    if (RES_AUTO_NS_URI.equals(namespaceUri)) {
      return xmlContext.packageName;
    }

    return extractPackageName(namespaceUri);
  }

  public static String extractPackageName(@NotNull String namespaceUri) {
    if (namespaceUri.startsWith(ANDROID_RES_NS_PREFIX)) {
      return namespaceUri.substring(ANDROID_RES_NS_PREFIX_LENGTH);
    } else {
      if (!namespaceUri.equals("http://schemas.android.com/apk/prv/res/android")) {
        LOGGER.log(Level.WARNING, "unexpected ns uri \"" + namespaceUri + "\"");
      }
      return URLEncoder.encode(namespaceUri);
    }
  }

  public String qualifiedValue() {
    if (isResourceReference()) return "@" + getResourceReference().getFullyQualifiedName();
    if (isStyleReference()) return "?" + getStyleReference().getFullyQualifiedName();
    else return value;
  }

  public boolean isResourceReference() {
    return value.startsWith("@") && !isNull();
  }

  public @NotNull ResName getResourceReference() {
    if (!isResourceReference()) throw new RuntimeException("not a resource reference: " + this);
    return ResName.qualifyResName(value.substring(1).replace("+", ""), contextPackageName, "attr");
  }

  public boolean isStyleReference() {
    return value.startsWith("?");
  }

  public ResName getStyleReference() {
    if (!isStyleReference()) throw new RuntimeException("not a style reference: " + this);
    return ResName.qualifyResName(value.substring(1), contextPackageName, "attr");
  }

  public boolean isNull() {
    return "@null".equals(value);
  }

  public boolean isEmpty() {
    return "@empty".equals(value);
  }

  @Override
  public String toString() {
    return "Attribute{" +
        "name='" + resName + '\'' +
        ", value='" + value + '\'' +
        ", contextPackageName='" + contextPackageName + '\'' +
        '}';
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy