public static void ApplyStyle()

in resources/src/main/java/org/robolectric/res/android/AttributeResolution.java [226:434]


  public static void ApplyStyle(ResTableTheme theme, ResXMLParser xmlParser, int defStyleAttr, int defStyleRes,
                                int[] attrs, int attrsLength, int[] outValues, int[] outIndices) {
    if (kDebugStyles) {
      ALOGI("APPLY STYLE: theme=%s defStyleAttr=0x%x defStyleRes=0x%x xml=%s",
          theme, defStyleAttr, defStyleRes, xmlParser);
    }

    final ResTable res = theme.getResTable();
    Ref<ResTable_config> config = new Ref<>(new ResTable_config());
    Ref<Res_value> value = new Ref<>(new Res_value());

    int indices_idx = 0;

    // Load default style from attribute, if specified...
    Ref<Integer> defStyleBagTypeSetFlags = new Ref<>(0);
    if (defStyleAttr != 0) {
      if (theme.GetAttribute(defStyleAttr, value, defStyleBagTypeSetFlags) >= 0) {
        if (value.get().dataType == DataType.REFERENCE.code()) {
          defStyleRes = value.get().data;
        }
      }
    }

    // Retrieve the style class associated with the current XML tag.
    int style = 0;
    Ref<Integer> styleBagTypeSetFlags = new Ref<>(0);
    if (xmlParser != null) {
      int idx = xmlParser.indexOfStyle();
      if (idx >= 0 && xmlParser.getAttributeValue(idx, value) >= 0) {
        if (value.get().dataType == DataType.ATTRIBUTE.code()) {
          if (theme.GetAttribute(value.get().data, value, styleBagTypeSetFlags) < 0) {
            value.set(value.get().withType(DataType.NULL.code()));
          }
        }
        if (value.get().dataType == DataType.REFERENCE.code()) {
          style = value.get().data;
        }
      }
    }

    // Now lock down the resource object and start pulling stuff from it.
    res.lock();

    // Retrieve the default style bag, if requested.
    final Ref<ResTable.bag_entry[]> defStyleAttrStart = new Ref<>(null);
    Ref<Integer> defStyleTypeSetFlags = new Ref<>(0);
    int bagOff = defStyleRes != 0
        ? res.getBagLocked(defStyleRes, defStyleAttrStart, defStyleTypeSetFlags)
        : -1;
    defStyleTypeSetFlags.set(defStyleTypeSetFlags.get() | defStyleBagTypeSetFlags.get());
    // const ResTable::bag_entry* defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
    final ResTable.bag_entry defStyleAttrEnd = null;
    // BagAttributeFinder defStyleAttrFinder = new BagAttributeFinder(defStyleAttrStart, defStyleAttrEnd);
    BagAttributeFinder defStyleAttrFinder = new BagAttributeFinder(defStyleAttrStart.get(), bagOff);

    // Retrieve the style class bag, if requested.
    final Ref<ResTable.bag_entry[]> styleAttrStart = new Ref<>(null);
    Ref<Integer> styleTypeSetFlags = new Ref<>(0);
    bagOff = style != 0
        ? res.getBagLocked(style, styleAttrStart, styleTypeSetFlags)
        : -1;
    styleTypeSetFlags.set(styleTypeSetFlags.get() | styleBagTypeSetFlags.get());
    // final ResTable::bag_entry* final styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
    final ResTable.bag_entry styleAttrEnd = null;
    //BagAttributeFinder styleAttrFinder = new BagAttributeFinder(styleAttrStart, styleAttrEnd);
    BagAttributeFinder styleAttrFinder = new BagAttributeFinder(styleAttrStart.get(), bagOff);

    // Retrieve the XML attributes, if requested.
    final int kXmlBlock = 0x10000000;
    XmlAttributeFinder xmlAttrFinder = new XmlAttributeFinder(xmlParser);
    final int xmlAttrEnd = xmlParser != null ? xmlParser.getAttributeCount() : 0;

    // Now iterate through all of the attributes that the client has requested,
    // filling in each with whatever data we can find.
    for (int ii = 0; ii < attrsLength; ii++) {
      final int curIdent = attrs[ii];

      if (kDebugStyles) {
        ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
      }

      int block = kXmlBlock;
      Ref<Integer> typeSetFlags = new Ref<>(0);

      value.set(Res_value.NULL_VALUE);
      config.get().density = 0;

      // Try to find a value for this attribute...  we prioritize values
      // coming from, first XML attributes, then XML style, then default
      // style, and finally the theme.

      // Walk through the xml attributes looking for the requested attribute.
      final int xmlAttrIdx = xmlAttrFinder.find(curIdent);
      if (xmlAttrIdx != xmlAttrEnd) {
        // We found the attribute we were looking for.
        xmlParser.getAttributeValue(xmlAttrIdx, value);
        if (kDebugStyles) {
          ALOGI("-> From XML: type=0x%x, data=0x%08x", value.get().dataType, value.get().data);
        }
      }

      if (value.get().dataType == DataType.NULL.code() && value.get().data != Res_value.DATA_NULL_EMPTY) {
        // Walk through the style class values looking for the requested attribute.
        final ResTable.bag_entry styleAttrEntry = styleAttrFinder.find(curIdent);
        if (styleAttrEntry != styleAttrEnd) {
          // We found the attribute we were looking for.
          block = styleAttrEntry.stringBlock;
          typeSetFlags.set(styleTypeSetFlags.get());
          value.set(styleAttrEntry.map.value);
          if (kDebugStyles) {
            ALOGI("-> From style: type=0x%x, data=0x%08x", value.get().dataType, value.get().data);
          }
        }
      }

      if (value.get().dataType == DataType.NULL.code() && value.get().data != Res_value.DATA_NULL_EMPTY) {
        // Walk through the default style values looking for the requested attribute.
        final ResTable.bag_entry defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
        if (defStyleAttrEntry != defStyleAttrEnd) {
          // We found the attribute we were looking for.
          block = defStyleAttrEntry.stringBlock;
          typeSetFlags.set(styleTypeSetFlags.get());
          value.set(defStyleAttrEntry.map.value);
          if (kDebugStyles) {
            ALOGI("-> From def style: type=0x%x, data=0x%08x", value.get().dataType, value.get().data);
          }
        }
      }

      Ref<Integer> resid = new Ref<>(0);
      if (value.get().dataType != DataType.NULL.code()) {
        // Take care of resolving the found resource to its final value.
        int newBlock = theme.resolveAttributeReference(value, block,
            resid, typeSetFlags, config);
        if (newBlock >= 0) {
          block = newBlock;
        }

        if (kDebugStyles) {
          ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.get().dataType, value.get().data);
        }
      } else if (value.get().data != Res_value.DATA_NULL_EMPTY) {
        // If we still don't have a value for this attribute, try to find it in the theme!
        int newBlock = theme.GetAttribute(curIdent, value, typeSetFlags);
        if (newBlock >= 0) {
          if (kDebugStyles) {
            ALOGI("-> From theme: type=0x%x, data=0x%08x", value.get().dataType, value.get().data);
          }
          newBlock = res.resolveReference(value, newBlock, resid, typeSetFlags, config);
          if (newBlock >= 0) {
            block = newBlock;
          }

          if (kDebugStyles) {
            ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.get().dataType, value.get().data);
          }
        }
      }

      // Deal with the special @null value -- it turns back to TYPE_NULL.
      if (value.get().dataType == DataType.REFERENCE.code() && value.get().data == 0) {
        if (kDebugStyles) {
          ALOGI(". Setting to @null!");
        }
        value.set(Res_value.NULL_VALUE);
        block = kXmlBlock;
      }

      if (kDebugStyles) {
        ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.get().dataType, value.get().data);
      }

      // Write the final value back to Java.
      int destIndex = ii * STYLE_NUM_ENTRIES;
      Res_value res_value = value.get();
      outValues[destIndex + STYLE_TYPE] = res_value.dataType;
      outValues[destIndex + STYLE_DATA] = res_value.data;
      outValues[destIndex + STYLE_ASSET_COOKIE] =
          block != kXmlBlock ? res.getTableCookie(block) : -1;
      outValues[destIndex + STYLE_RESOURCE_ID] = resid.get();
      outValues[destIndex + STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags.get();
      outValues[destIndex + STYLE_DENSITY] = config.get().density;

      if (res_value.dataType != DataType.NULL.code() || res_value.data == Res_value.DATA_NULL_EMPTY) {
        indices_idx++;

        // out_indices must NOT be nullptr.
        outIndices[indices_idx] = ii;
      }

      if (res_value.dataType == DataType.ATTRIBUTE.code()) {
        ResTable.ResourceName attrName = new ResTable.ResourceName();
        ResTable.ResourceName attrRefName = new ResTable.ResourceName();
        boolean gotName = res.getResourceName(curIdent, true, attrName);
        boolean gotRefName = res.getResourceName(res_value.data, true, attrRefName);
        Logger.warn(
            "Failed to resolve attribute lookup: %s=\"?%s\"; theme: %s",
            gotName ? attrName : "unknown", gotRefName ? attrRefName : "unknown",
            theme);
      }

//      out_values += STYLE_NUM_ENTRIES;
    }

    res.unlock();

    // out_indices must NOT be nullptr.
    outIndices[0] = indices_idx;
  }