Move attribute resolution from core/jni to libandroidfw

Without the entire JNI environment, testing the attribute
resolution code will be much easier and enable safer
refactoring.

Change-Id: I2815cc1e10a694a3b01bc37e191a0d5e9d0e6735
Test: Existing CTS tests pass
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index ef32afee..5a4348e 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -31,7 +31,7 @@
 
 #include "androidfw/Asset.h"
 #include "androidfw/AssetManager.h"
-#include "androidfw/AttributeFinder.h"
+#include "androidfw/AttributeResolution.h"
 #include "androidfw/ResourceTypes.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "android_util_Binder.h"
@@ -51,7 +51,6 @@
 namespace android {
 
 static const bool kThrowOnBadId = false;
-static const bool kDebugStyles = false;
 
 // ----------------------------------------------------------------------------
 
@@ -1121,30 +1120,6 @@
     theme->dumpToLog();
 }
 
-class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
-public:
-    explicit XmlAttributeFinder(const ResXMLParser* parser)
-        : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0)
-        , mParser(parser) {}
-
-    inline uint32_t getAttribute(jsize index) const {
-        return mParser->getAttributeNameResID(index);
-    }
-
-private:
-    const ResXMLParser* mParser;
-};
-
-class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
-public:
-    BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
-        : BackTrackingAttributeFinder(start, end) {}
-
-    inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
-        return entry->map.name.ident;
-    }
-};
-
 static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
                                                           jlong themeToken,
                                                           jint defStyleAttr,
@@ -1167,16 +1142,6 @@
         return JNI_FALSE;
     }
 
-    if (kDebugStyles) {
-        ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x "
-              "defStyleRes=0x%x", themeToken, defStyleAttr, defStyleRes);
-    }
-
-    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
-    const ResTable& res = theme->getResTable();
-    ResTable_config config;
-    Res_value value;
-
     const jsize NI = env->GetArrayLength(attrs);
     const jsize NV = env->GetArrayLength(outValues);
     if (NV < (NI*STYLE_NUM_ENTRIES)) {
@@ -1193,159 +1158,32 @@
     const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
 
     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
-    jint* dest = baseDest;
-    if (dest == NULL) {
+    if (baseDest == NULL) {
         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
         return JNI_FALSE;
     }
 
     jint* indices = NULL;
-    int indicesIdx = 0;
     if (outIndices != NULL) {
         if (env->GetArrayLength(outIndices) > NI) {
             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
         }
     }
 
-    // Load default style from attribute, if specified...
-    uint32_t defStyleBagTypeSetFlags = 0;
-    if (defStyleAttr != 0) {
-        Res_value value;
-        if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
-            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.
-    const ResTable::bag_entry* defStyleStart = NULL;
-    uint32_t defStyleTypeSetFlags = 0;
-    ssize_t bagOff = defStyleRes != 0
-            ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
-    defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
-    const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
-    BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
-
-    // Now iterate through all of the attributes that the client has requested,
-    // filling in each with whatever data we can find.
-    ssize_t block = 0;
-    uint32_t typeSetFlags;
-    for (jsize ii=0; ii<NI; ii++) {
-        const uint32_t curIdent = (uint32_t)src[ii];
-
-        if (kDebugStyles) {
-            ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
-        }
-
-        // 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.
-        value.dataType = Res_value::TYPE_NULL;
-        value.data = Res_value::DATA_NULL_UNDEFINED;
-        typeSetFlags = 0;
-        config.density = 0;
-
-        // Retrieve the current input value if available.
-        if (NSV > 0 && srcValues[ii] != 0) {
-            block = -1;
-            value.dataType = Res_value::TYPE_ATTRIBUTE;
-            value.data = srcValues[ii];
-            if (kDebugStyles) {
-                ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
-            }
-        }
-
-        if (value.dataType == Res_value::TYPE_NULL) {
-            const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent);
-            if (defStyleEntry != defStyleEnd) {
-                block = defStyleEntry->stringBlock;
-                typeSetFlags = defStyleTypeSetFlags;
-                value = defStyleEntry->map.value;
-                if (kDebugStyles) {
-                    ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
-                }
-            }
-        }
-
-        uint32_t resid = 0;
-        if (value.dataType != Res_value::TYPE_NULL) {
-            // Take care of resolving the found resource to its final value.
-            ssize_t 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.dataType, value.data);
-            }
-        } else {
-            // If we still don't have a value for this attribute, try to find
-            // it in the theme!
-            ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
-            if (newBlock >= 0) {
-                if (kDebugStyles) {
-                    ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
-                }
-                newBlock = res.resolveReference(&value, block, &resid,
-                        &typeSetFlags, &config);
-                if (kThrowOnBadId) {
-                    if (newBlock == BAD_INDEX) {
-                        jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-                        return JNI_FALSE;
-                    }
-                }
-                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.dataType = Res_value::TYPE_NULL;
-            value.data = Res_value::DATA_NULL_UNDEFINED;
-            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.
-        dest[STYLE_TYPE] = value.dataType;
-        dest[STYLE_DATA] = value.data;
-        dest[STYLE_ASSET_COOKIE] =
-            block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
-        dest[STYLE_RESOURCE_ID] = resid;
-        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
-        dest[STYLE_DENSITY] = config.density;
-
-        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
-            indicesIdx++;
-            indices[indicesIdx] = ii;
-        }
-
-        dest += STYLE_NUM_ENTRIES;
-    }
-
-    res.unlock();
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+    bool result = resolveAttrs(theme, defStyleAttr, defStyleRes,
+                               (uint32_t*) srcValues, NSV,
+                               (uint32_t*) src, NI,
+                               (uint32_t*) baseDest,
+                               (uint32_t*) indices);
 
     if (indices != NULL) {
-        indices[0] = indicesIdx;
         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
     }
     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
     env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-
-    return JNI_TRUE;
+    return result ? JNI_TRUE : JNI_FALSE;
 }
 
 static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
@@ -1370,18 +1208,6 @@
         return JNI_FALSE;
     }
 
-    if (kDebugStyles) {
-    ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x defStyleRes=0x%x "
-          "xml=0x%" PRIx64, themeToken, defStyleAttr, defStyleRes,
-          xmlParserToken);
-    }
-
-    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
-    const ResTable& res = theme->getResTable();
-    ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
-    ResTable_config config;
-    Res_value value;
-
     const jsize NI = env->GetArrayLength(attrs);
     const jsize NV = env->GetArrayLength(outValues);
     if (NV < (NI*STYLE_NUM_ENTRIES)) {
@@ -1395,211 +1221,32 @@
     }
 
     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
-    jint* dest = baseDest;
-    if (dest == NULL) {
+    if (baseDest == NULL) {
         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
         return JNI_FALSE;
     }
 
     jint* indices = NULL;
-    int indicesIdx = 0;
     if (outIndices != NULL) {
         if (env->GetArrayLength(outIndices) > NI) {
             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
         }
     }
 
-    // Load default style from attribute, if specified...
-    uint32_t defStyleBagTypeSetFlags = 0;
-    if (defStyleAttr != 0) {
-        Res_value value;
-        if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
-            if (value.dataType == Res_value::TYPE_REFERENCE) {
-                defStyleRes = value.data;
-            }
-        }
-    }
-
-    // Retrieve the style class associated with the current XML tag.
-    int style = 0;
-    uint32_t styleBagTypeSetFlags = 0;
-    if (xmlParser != NULL) {
-        ssize_t idx = xmlParser->indexOfStyle();
-        if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
-            if (value.dataType == value.TYPE_ATTRIBUTE) {
-                if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
-                    value.dataType = Res_value::TYPE_NULL;
-                }
-            }
-            if (value.dataType == value.TYPE_REFERENCE) {
-                style = value.data;
-            }
-        }
-    }
-
-    // Now lock down the resource object and start pulling stuff from it.
-    res.lock();
-
-    // Retrieve the default style bag, if requested.
-    const ResTable::bag_entry* defStyleAttrStart = NULL;
-    uint32_t defStyleTypeSetFlags = 0;
-    ssize_t bagOff = defStyleRes != 0
-            ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
-    defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
-    const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
-    BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
-
-    // Retrieve the style class bag, if requested.
-    const ResTable::bag_entry* styleAttrStart = NULL;
-    uint32_t styleTypeSetFlags = 0;
-    bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
-    styleTypeSetFlags |= styleBagTypeSetFlags;
-    const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
-    BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
-
-    // Retrieve the XML attributes, if requested.
-    static const ssize_t kXmlBlock = 0x10000000;
-    XmlAttributeFinder xmlAttrFinder(xmlParser);
-    const jsize 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.
-    ssize_t block = 0;
-    uint32_t typeSetFlags;
-    for (jsize ii = 0; ii < NI; ii++) {
-        const uint32_t curIdent = (uint32_t)src[ii];
-
-        if (kDebugStyles) {
-            ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
-        }
-
-        // 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.
-        value.dataType = Res_value::TYPE_NULL;
-        value.data = Res_value::DATA_NULL_UNDEFINED;
-        typeSetFlags = 0;
-        config.density = 0;
-
-        // Walk through the xml attributes looking for the requested attribute.
-        const jsize xmlAttrIdx = xmlAttrFinder.find(curIdent);
-        if (xmlAttrIdx != xmlAttrEnd) {
-            // We found the attribute we were looking for.
-            block = kXmlBlock;
-            xmlParser->getAttributeValue(xmlAttrIdx, &value);
-            if (kDebugStyles) {
-                ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
-            }
-        }
-
-        if (value.dataType == Res_value::TYPE_NULL) {
-            // Walk through the style class values looking for the requested attribute.
-            const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent);
-            if (styleAttrEntry != styleAttrEnd) {
-                // We found the attribute we were looking for.
-                block = styleAttrEntry->stringBlock;
-                typeSetFlags = styleTypeSetFlags;
-                value = styleAttrEntry->map.value;
-                if (kDebugStyles) {
-                    ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
-                }
-            }
-        }
-
-        if (value.dataType == Res_value::TYPE_NULL) {
-            // Walk through the default style values looking for the requested attribute.
-            const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
-            if (defStyleAttrEntry != defStyleAttrEnd) {
-                // We found the attribute we were looking for.
-                block = defStyleAttrEntry->stringBlock;
-                typeSetFlags = styleTypeSetFlags;
-                value = defStyleAttrEntry->map.value;
-                if (kDebugStyles) {
-                    ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
-                }
-            }
-        }
-
-        uint32_t resid = 0;
-        if (value.dataType != Res_value::TYPE_NULL) {
-            // Take care of resolving the found resource to its final value.
-            ssize_t 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.dataType, value.data);
-            }
-        } else {
-            // If we still don't have a value for this attribute, try to find
-            // it in the theme!
-            ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
-            if (newBlock >= 0) {
-                if (kDebugStyles) {
-                    ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
-                }
-                newBlock = res.resolveReference(&value, block, &resid,
-                        &typeSetFlags, &config);
-                if (kThrowOnBadId) {
-                    if (newBlock == BAD_INDEX) {
-                        jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-                        return JNI_FALSE;
-                    }
-                }
-
-                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.dataType = Res_value::TYPE_NULL;
-            value.data = Res_value::DATA_NULL_UNDEFINED;
-            block = kXmlBlock;
-        }
-
-        if (kDebugStyles) {
-            ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data);
-        }
-
-        // Write the final value back to Java.
-        dest[STYLE_TYPE] = value.dataType;
-        dest[STYLE_DATA] = value.data;
-        dest[STYLE_ASSET_COOKIE] = block != kXmlBlock ?
-            static_cast<jint>(res.getTableCookie(block)) : -1;
-        dest[STYLE_RESOURCE_ID] = resid;
-        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
-        dest[STYLE_DENSITY] = config.density;
-
-        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
-            indicesIdx++;
-            indices[indicesIdx] = ii;
-        }
-
-        dest += STYLE_NUM_ENTRIES;
-    }
-
-    res.unlock();
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+    ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
+    bool result = applyStyle(theme, xmlParser,
+                             defStyleAttr, defStyleRes,
+                             (uint32_t*) src, NI,
+                             (uint32_t*) baseDest,
+                             (uint32_t*) indices);
 
     if (indices != NULL) {
-        indices[0] = indicesIdx;
         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
     }
     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-
-    return JNI_TRUE;
+    return result ? JNI_TRUE : JNI_FALSE;
 }
 
 static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
@@ -1627,8 +1274,6 @@
     }
     const ResTable& res(am->getResources());
     ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
-    ResTable_config config;
-    Res_value value;
 
     const jsize NI = env->GetArrayLength(attrs);
     const jsize NV = env->GetArrayLength(outValues);
@@ -1643,108 +1288,29 @@
     }
 
     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
-    jint* dest = baseDest;
-    if (dest == NULL) {
+    if (baseDest == NULL) {
         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
         return JNI_FALSE;
     }
 
     jint* indices = NULL;
-    int indicesIdx = 0;
     if (outIndices != NULL) {
         if (env->GetArrayLength(outIndices) > NI) {
             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
         }
     }
 
-    // Now lock down the resource object and start pulling stuff from it.
-    res.lock();
-
-    // Retrieve the XML attributes, if requested.
-    const jsize NX = xmlParser->getAttributeCount();
-    jsize ix=0;
-    uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
-
-    static const ssize_t kXmlBlock = 0x10000000;
-
-    // Now iterate through all of the attributes that the client has requested,
-    // filling in each with whatever data we can find.
-    ssize_t block = 0;
-    uint32_t typeSetFlags;
-    for (jsize ii=0; ii<NI; ii++) {
-        const uint32_t curIdent = (uint32_t)src[ii];
-
-        // Try to find a value for this attribute...
-        value.dataType = Res_value::TYPE_NULL;
-        value.data = Res_value::DATA_NULL_UNDEFINED;
-        typeSetFlags = 0;
-        config.density = 0;
-
-        // Skip through XML attributes until the end or the next possible match.
-        while (ix < NX && curIdent > curXmlAttr) {
-            ix++;
-            curXmlAttr = xmlParser->getAttributeNameResID(ix);
-        }
-        // Retrieve the current XML attribute if it matches, and step to next.
-        if (ix < NX && curIdent == curXmlAttr) {
-            block = kXmlBlock;
-            xmlParser->getAttributeValue(ix, &value);
-            ix++;
-            curXmlAttr = xmlParser->getAttributeNameResID(ix);
-        }
-
-        //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
-        uint32_t resid = 0;
-        if (value.dataType != Res_value::TYPE_NULL) {
-            // Take care of resolving the found resource to its final value.
-            //printf("Resolving attribute reference\n");
-            ssize_t newBlock = res.resolveReference(&value, block, &resid,
-                    &typeSetFlags, &config);
-            if (kThrowOnBadId) {
-                if (newBlock == BAD_INDEX) {
-                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
-                    return JNI_FALSE;
-                }
-            }
-            if (newBlock >= 0) block = newBlock;
-        }
-
-        // Deal with the special @null value -- it turns back to TYPE_NULL.
-        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
-            value.dataType = Res_value::TYPE_NULL;
-            value.data = Res_value::DATA_NULL_UNDEFINED;
-        }
-
-        //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
-
-        // Write the final value back to Java.
-        dest[STYLE_TYPE] = value.dataType;
-        dest[STYLE_DATA] = value.data;
-        dest[STYLE_ASSET_COOKIE] =
-            block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
-        dest[STYLE_RESOURCE_ID] = resid;
-        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
-        dest[STYLE_DENSITY] = config.density;
-
-        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
-            indicesIdx++;
-            indices[indicesIdx] = ii;
-        }
-
-        dest += STYLE_NUM_ENTRIES;
-    }
-
-    res.unlock();
+    bool result = retrieveAttributes(&res, xmlParser,
+                                     (uint32_t*) src, NI,
+                                     (uint32_t*) baseDest,
+                                     (uint32_t*) indices);
 
     if (indices != NULL) {
-        indices[0] = indicesIdx;
         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
     }
-
     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-
-    return JNI_TRUE;
+    return result ? JNI_TRUE : JNI_FALSE;
 }
 
 static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,