in resources/src/main/java/org/robolectric/res/android/AttributeResolution.java [64:224]
public static boolean ResolveAttrs(ResTableTheme theme, int defStyleAttr,
int defStyleRes, int[] srcValues,
int srcValuesLength, int[] attrs,
int attrsLength, int[] outValues, int[] outIndices) {
if (kDebugStyles) {
ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme,
defStyleAttr, defStyleRes);
}
final ResTable res = theme.getResTable();
ResTable_config config = new ResTable_config();
Res_value value;
int indicesIdx = 0;
// Load default style from attribute, if specified...
Ref<Integer> defStyleBagTypeSetFlags = new Ref<>(0);
if (defStyleAttr != 0) {
Ref<Res_value> valueRef = new Ref<>(null);
if (theme.GetAttribute(defStyleAttr, valueRef, defStyleBagTypeSetFlags) >= 0) {
value = valueRef.get();
if (value.dataType == Res_value.TYPE_REFERENCE) {
defStyleRes = value.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[]> defStyleStart = new Ref<>(null);
Ref<Integer> defStyleTypeSetFlags = new Ref<>(0);
int bagOff = defStyleRes != 0
? res.getBagLocked(defStyleRes, defStyleStart, defStyleTypeSetFlags) : -1;
defStyleTypeSetFlags.set(defStyleTypeSetFlags.get() | defStyleBagTypeSetFlags.get());
// const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
final int defStyleEnd = (bagOff >= 0 ? bagOff : 0);
BagAttributeFinder defStyleAttrFinder = new BagAttributeFinder(defStyleStart.get(), defStyleEnd);
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
int destOffset = 0;
for (int ii=0; ii<attrsLength; ii++) {
final int curIdent = attrs[ii];
if (kDebugStyles) {
ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
}
int block = -1;
int typeSetFlags = 0;
value = Res_value.NULL_VALUE;
config.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.
// Retrieve the current input value if available.
if (srcValuesLength > 0 && srcValues[ii] != 0) {
value = new Res_value((byte) Res_value.TYPE_ATTRIBUTE, srcValues[ii]);
if (kDebugStyles) {
ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
}
} else {
final ResTable.bag_entry defStyleEntry = defStyleAttrFinder.find(curIdent);
if (defStyleEntry != null) {
block = defStyleEntry.stringBlock;
typeSetFlags = defStyleTypeSetFlags.get();
value = defStyleEntry.map.value;
if (kDebugStyles) {
ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
}
}
}
int resid = 0;
Ref<Res_value> valueRef = new Ref<>(value);
Ref<Integer> residRef = new Ref<>(resid);
Ref<Integer> typeSetFlagsRef = new Ref<>(typeSetFlags);
Ref<ResTable_config> configRef = new Ref<>(config);
if (value.dataType != Res_value.TYPE_NULL) {
// Take care of resolving the found resource to its final value.
int newBlock = theme.resolveAttributeReference(valueRef, block,
residRef, typeSetFlagsRef, configRef);
value = valueRef.get();
resid = residRef.get();
typeSetFlags = typeSetFlagsRef.get();
config = configRef.get();
if (newBlock >= 0) block = newBlock;
if (kDebugStyles) {
ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
}
} else {
// If we still don't have a value for this attribute, try to find
// it in the theme!
int newBlock = theme.GetAttribute(curIdent, valueRef, typeSetFlagsRef);
value = valueRef.get();
typeSetFlags = typeSetFlagsRef.get();
if (newBlock >= 0) {
if (kDebugStyles) {
ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
newBlock = res.resolveReference(valueRef, newBlock, residRef, typeSetFlagsRef, configRef);
value = valueRef.get();
resid = residRef.get();
typeSetFlags = typeSetFlagsRef.get();
config = configRef.get();
if (kThrowOnBadId) {
if (newBlock == BAD_INDEX) {
throw new IllegalStateException("Bad resource!");
}
}
if (newBlock >= 0) block = newBlock;
if (kDebugStyles) {
ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
}
}
}
// Deal with the special @null value -- it turns back to TYPE_NULL.
if (value.dataType == Res_value.TYPE_REFERENCE && value.data == 0) {
if (kDebugStyles) {
ALOGI("-> Setting to @null!");
}
value = Res_value.NULL_VALUE;
block = -1;
}
if (kDebugStyles) {
ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType,
value.data);
}
// Write the final value back to Java.
outValues[destOffset + STYLE_TYPE] = value.dataType;
outValues[destOffset + STYLE_DATA] = value.data;
outValues[destOffset + STYLE_ASSET_COOKIE] =
block != -1 ? res.getTableCookie(block) : -1;
outValues[destOffset + STYLE_RESOURCE_ID] = resid;
outValues[destOffset + STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
outValues[destOffset + STYLE_DENSITY] = config.density;
if (outIndices != null && value.dataType != Res_value.TYPE_NULL) {
indicesIdx++;
outIndices[indicesIdx] = ii;
}
destOffset += STYLE_NUM_ENTRIES;
}
res.unlock();
if (outIndices != null) {
outIndices[0] = indicesIdx;
}
return true;
}