public AttributeSet build()

in robolectric/src/main/java/org/robolectric/android/AttributeSetBuilderImpl.java [264:386]


  public AttributeSet build() {
    Class<?> xmlBlockClass = ReflectionHelpers
        .loadClass(this.getClass().getClassLoader(), "android.content.res.XmlBlock");

    ByteBuffer buf = ByteBuffer.allocate(16 * 1024).order(ByteOrder.LITTLE_ENDIAN);
    Writer resStringPoolWriter = new Writer();

    final SparseArray<Integer> resIds = new SparseArray<>();
    final int[] maxAttrNameIndex = new int[] { 0 };

    ResXMLTree_attrExt.Writer dummyStart = new ResXMLTree_attrExt.Writer(buf, resStringPoolWriter,
        null, "dummy") {
      {
        String packageName = resourceResolver.getPackageName();

        for (Entry<Integer, String> entry : attrToValue.entrySet()) {
          Integer attrId = entry.getKey();
          String attrNs = "";
          String attrName;
          ResName attrResName = null;

          String magicAttr = MAGIC_ATTRS.get(attrId);
          if (magicAttr != null) {
            attrId = null;
            attrName = magicAttr;
          } else {
            String attrNameStr = resourceResolver.getResourceName(attrId);
            attrResName = ResName.qualifyResName(attrNameStr, packageName, "attr");
            attrNs = (attrResName.packageName.equals("android")) ? ANDROID_NS : AUTO_NS;
            attrName = attrResName.name;
          }

          String value = entry.getValue();
          DataType type;
          int valueInt;

          if (value == null || AttributeResource.isNull(value)) {
            type = DataType.NULL;
            valueInt = TypedValue.DATA_NULL_EMPTY;
          } else if (AttributeResource.isResourceReference(value)) {
            ResName resRef = AttributeResource.getResourceReference(value, packageName, null);
            Integer valueResId = resourceResolver.getIdentifier(resRef.name, resRef.type, resRef.packageName);
            if (valueResId == 0) {
              throw new IllegalArgumentException("no such resource " + value
                  + " while resolving value for "
                  + (attrResName == null ? attrName : attrResName.getFullyQualifiedName()));
            }
            type = DataType.REFERENCE;
            if (attrResName != null) {
              value = "@" +  valueResId;
            }
            valueInt = valueResId;
          } else if (AttributeResource.isStyleReference(value)) {
            ResName resRef = AttributeResource.getStyleReference(value, packageName, "attr");
            Integer valueResId = resourceResolver.getIdentifier(resRef.name, resRef.type, resRef.packageName);
            if (valueResId == 0) {
              throw new IllegalArgumentException("no such attr " + value
                  + " while resolving value for "
                  + (attrResName == null ? attrName : attrResName.getFullyQualifiedName()));
            }
            type = DataType.ATTRIBUTE;
            valueInt = valueResId;
          } else if (attrResName == null) { // class, id, or style
            type = DataType.STRING;
            valueInt = resStringPoolWriter.string(value);
          } else {
            TypedValue outValue = parse(attrId, attrResName, value, packageName);
            type = DataType.fromCode(outValue.type);
            value = (String) outValue.string;
            if (type == DataType.STRING && outValue.data == 0) {
              valueInt = resStringPoolWriter.string(value);
            } else {
              valueInt = outValue.data;
            }
          }

          Res_value resValue = new Res_value(type.code(), valueInt);

          int attrNameIndex = resStringPoolWriter.uniqueString(attrName);
          attr(resStringPoolWriter.string(attrNs), attrNameIndex,
              resStringPoolWriter.string(value), resValue, attrNs + ":" + attrName);
          if (attrId != null) {
            resIds.put(attrNameIndex, attrId);
          }
          maxAttrNameIndex[0] = Math.max(maxAttrNameIndex[0], attrNameIndex);
        }
      }
    };

    ResXMLTree_endElementExt.Writer dummyEnd =
        new ResXMLTree_endElementExt.Writer(buf, resStringPoolWriter, null, "dummy");

    int finalMaxAttrNameIndex = maxAttrNameIndex[0];
    ResXMLTree_header.write(buf, resStringPoolWriter, () -> {
      if (finalMaxAttrNameIndex > 0) {
        ResChunk_header.write(buf, (short) RES_XML_RESOURCE_MAP_TYPE, () -> {}, () -> {
          // not particularly compact, but no big deal for our purposes...
          for (int i = 0; i <= finalMaxAttrNameIndex; i++) {
            Integer value = resIds.get(i);
            buf.putInt(value == null ? 0 : value);
          }
        });
      }

      ResXMLTree_node.write(buf, RES_XML_START_ELEMENT_TYPE, dummyStart::write);
      ResXMLTree_node.write(buf, RES_XML_END_ELEMENT_TYPE, dummyEnd::write);
    });

    int size = buf.position();
    byte[] bytes = new byte[size];
    buf.position(0);
    buf.get(bytes, 0, size);

    Object xmlBlockInstance = ReflectionHelpers
        .callConstructor(xmlBlockClass, ClassParameter.from(byte[].class, bytes));

    AttributeSet parser = ReflectionHelpers.callInstanceMethod(xmlBlockClass, xmlBlockInstance,
        "newParser");
    ReflectionHelpers.callInstanceMethod(parser, "next");
    ReflectionHelpers.callInstanceMethod(parser, "next");

    return parser;
  }