LayoutLib: extract resource resolution into its own class.

Next step is to make it a jar that will also live in
ADT.
The version in layoutlib will be through a prebuilt jar
file, like ninepatch.

Also add ninepatch.jar inside the layoutlib.jar file.

Change-Id: I4a0cc9f2dd99709de6408386054c6d4abae7c824
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index 9b7bc5f..a0a7307 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -20,10 +20,11 @@
 
 LOCAL_JAVA_LIBRARIES := \
 	kxml2-2.3.0 \
-	layoutlib_api-prebuilt \
-	ninepatch-prebuilt
+	layoutlib_api-prebuilt
 
-LOCAL_STATIC_JAVA_LIBRARIES := temp_layoutlib
+LOCAL_STATIC_JAVA_LIBRARIES := \
+	temp_layoutlib \
+	ninepatch-prebuilt
 
 LOCAL_MODULE := layoutlib
 
diff --git a/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java b/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java
new file mode 100644
index 0000000..4c500e7
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.common.resources;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.StyleResourceValue;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ResourceResolver {
+
+    public final static String RES_ANIMATOR = "animator";
+    public final static String RES_STYLE = "style";
+    public final static String RES_ATTR = "attr";
+    public final static String RES_DIMEN = "dimen";
+    public final static String RES_DRAWABLE = "drawable";
+    public final static String RES_COLOR = "color";
+    public final static String RES_LAYOUT = "layout";
+    public final static String RES_STRING = "string";
+    public final static String RES_ID = "id";
+
+    public final static String REFERENCE_NULL = "@null";
+
+    private final static String REFERENCE_STYLE = RES_STYLE + "/";
+    private final static String PREFIX_ANDROID_RESOURCE_REF = "@android:";
+    private final static String PREFIX_RESOURCE_REF = "@";
+    private final static String PREFIX_ANDROID_THEME_REF = "?android:";
+    private final static String PREFIX_THEME_REF = "?";
+    private final static String PREFIX_ANDROID = "android:";
+
+
+    private final IFrameworkResourceIdProvider mFrameworkProvider;
+    private final Map<String, Map<String, ResourceValue>>  mProjectResources;
+    private final Map<String, Map<String, ResourceValue>>  mFrameworkResources;
+    private final LayoutLog mLogger;
+
+    private final Map<StyleResourceValue, StyleResourceValue> mStyleInheritanceMap =
+        new HashMap<StyleResourceValue, StyleResourceValue>();
+    private StyleResourceValue mTheme;
+
+    public interface IFrameworkResourceIdProvider {
+        Integer getId(String resType, String resName);
+    }
+
+    private ResourceResolver(
+            IFrameworkResourceIdProvider provider,
+            Map<String, Map<String, ResourceValue>> projectResources,
+            Map<String, Map<String, ResourceValue>> frameworkResources,
+            LayoutLog logger) {
+        mFrameworkProvider = provider;
+        mProjectResources = projectResources;
+        mFrameworkResources = frameworkResources;
+        mLogger = logger;
+    }
+
+    /**
+     * Creates a new ResourceResolver object.
+     *
+     * @param IFrameworkResourceIdProvider an optional framework resource ID provider
+     * @param projectResources the project resources.
+     * @param frameworkResources the framework resources.
+     * @param themeName the name of the current theme.
+     * @param isProjectTheme Is this a project theme?
+     * @return
+     */
+    public static ResourceResolver create(
+            IFrameworkResourceIdProvider provider,
+            Map<String, Map<String, ResourceValue>> projectResources,
+            Map<String, Map<String, ResourceValue>> frameworkResources,
+            String themeName, boolean isProjectTheme, LayoutLog logger) {
+
+        ResourceResolver resolver = new ResourceResolver(provider,
+                projectResources, frameworkResources,
+                logger);
+
+        resolver.computeStyleMaps(themeName, isProjectTheme);
+
+        return resolver;
+    }
+
+    public StyleResourceValue getTheme() {
+        return mTheme;
+    }
+
+    /**
+     * Returns a framework resource by type and name. The returned resource is resolved.
+     * @param resourceType the type of the resource
+     * @param resourceName the name of the resource
+     */
+    public ResourceValue getFrameworkResource(String resourceType, String resourceName) {
+        return getResource(resourceType, resourceName, mFrameworkResources);
+    }
+
+    /**
+     * Returns a project resource by type and name. The returned resource is resolved.
+     * @param resourceType the type of the resource
+     * @param resourceName the name of the resource
+     */
+    public ResourceValue getProjectResource(String resourceType, String resourceName) {
+        return getResource(resourceType, resourceName, mProjectResources);
+    }
+
+    /**
+     * Returns the {@link ResourceValue} matching a given name in the current theme. If the
+     * item is not directly available in the theme, the method looks in its parent theme.
+     *
+     * @param itemName the name of the item to search for.
+     * @return the {@link ResourceValue} object or <code>null</code>
+     */
+    public ResourceValue findItemInTheme(String itemName) {
+        if (mTheme != null) {
+            return findItemInStyle(mTheme, itemName);
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the {@link ResourceValue} matching a given name in a given style. If the
+     * item is not directly available in the style, the method looks in its parent style.
+     *
+     * @param style the style to search in
+     * @param itemName the name of the item to search for.
+     * @return the {@link ResourceValue} object or <code>null</code>
+     */
+    public ResourceValue findItemInStyle(StyleResourceValue style, String itemName) {
+        ResourceValue item = style.findValue(itemName);
+
+        // if we didn't find it, we look in the parent style (if applicable)
+        if (item == null && mStyleInheritanceMap != null) {
+            StyleResourceValue parentStyle = mStyleInheritanceMap.get(style);
+            if (parentStyle != null) {
+                return findItemInStyle(parentStyle, itemName);
+            }
+        }
+
+        return item;
+    }
+
+    /**
+     * Searches for, and returns a {@link ResourceValue} by its reference.
+     * <p/>
+     * The reference format can be:
+     * <pre>@resType/resName</pre>
+     * <pre>@android:resType/resName</pre>
+     * <pre>@resType/android:resName</pre>
+     * <pre>?resType/resName</pre>
+     * <pre>?android:resType/resName</pre>
+     * <pre>?resType/android:resName</pre>
+     * Any other string format will return <code>null</code>.
+     * <p/>
+     * The actual format of a reference is <pre>@[namespace:]resType/resName</pre> but this method
+     * only support the android namespace.
+     *
+     * @param reference the resource reference to search for.
+     * @param forceFrameworkOnly if true all references are considered to be toward framework
+     *      resource even if the reference does not include the android: prefix.
+     * @return a {@link ResourceValue} or <code>null</code>.
+     */
+    public ResourceValue findResValue(String reference, boolean forceFrameworkOnly) {
+        if (reference == null) {
+            return null;
+        }
+        if (reference.startsWith(PREFIX_THEME_REF)) {
+            // no theme? no need to go further!
+            if (mTheme == null) {
+                return null;
+            }
+
+            boolean frameworkOnly = false;
+
+            // eliminate the prefix from the string
+            if (reference.startsWith(PREFIX_ANDROID_THEME_REF)) {
+                frameworkOnly = true;
+                reference = reference.substring(PREFIX_ANDROID_THEME_REF.length());
+            } else {
+                reference = reference.substring(PREFIX_THEME_REF.length());
+            }
+
+            // at this point, value can contain type/name (drawable/foo for instance).
+            // split it to make sure.
+            String[] segments = reference.split("\\/");
+
+            // we look for the referenced item name.
+            String referenceName = null;
+
+            if (segments.length == 2) {
+                // there was a resType in the reference. If it's attr, we ignore it
+                // else, we assert for now.
+                if (RES_ATTR.equals(segments[0])) {
+                    referenceName = segments[1];
+                } else {
+                    // At this time, no support for ?type/name where type is not "attr"
+                    return null;
+                }
+            } else {
+                // it's just an item name.
+                referenceName = segments[0];
+            }
+
+            // now we look for android: in the referenceName in order to support format
+            // such as: ?attr/android:name
+            if (referenceName.startsWith(PREFIX_ANDROID)) {
+                frameworkOnly = true;
+                referenceName = referenceName.substring(PREFIX_ANDROID.length());
+            }
+
+            // Now look for the item in the theme, starting with the current one.
+            if (frameworkOnly) {
+                // FIXME for now we do the same as if it didn't specify android:
+                return findItemInStyle(mTheme, referenceName);
+            }
+
+            return findItemInStyle(mTheme, referenceName);
+        } else if (reference.startsWith(PREFIX_RESOURCE_REF)) {
+            boolean frameworkOnly = false;
+
+            // check for the specific null reference value.
+            if (REFERENCE_NULL.equals(reference)) {
+                return null;
+            }
+
+            // Eliminate the prefix from the string.
+            if (reference.startsWith(PREFIX_ANDROID_RESOURCE_REF)) {
+                frameworkOnly = true;
+                reference = reference.substring(
+                        PREFIX_ANDROID_RESOURCE_REF.length());
+            } else {
+                reference = reference.substring(PREFIX_RESOURCE_REF.length());
+            }
+
+            // at this point, value contains type/[android:]name (drawable/foo for instance)
+            String[] segments = reference.split("\\/");
+
+            // now we look for android: in the resource name in order to support format
+            // such as: @drawable/android:name
+            if (segments[1].startsWith(PREFIX_ANDROID)) {
+                frameworkOnly = true;
+                segments[1] = segments[1].substring(PREFIX_ANDROID.length());
+            }
+
+            return findResValue(segments[0], segments[1],
+                    forceFrameworkOnly ? true :frameworkOnly);
+        }
+
+        // Looks like the value didn't reference anything. Return null.
+        return null;
+    }
+
+    /**
+     * Resolves the value of a resource, if the value references a theme or resource value.
+     * <p/>
+     * This method ensures that it returns a {@link ResourceValue} object that does not
+     * reference another resource.
+     * If the resource cannot be resolved, it returns <code>null</code>.
+     * <p/>
+     * If a value that does not need to be resolved is given, the method will return a new
+     * instance of {@link ResourceValue} that contains the input value.
+     *
+     * @param type the type of the resource
+     * @param name the name of the attribute containing this value.
+     * @param value the resource value, or reference to resolve
+     * @param isFrameworkValue whether the value is a framework value.
+     *
+     * @return the resolved resource value or <code>null</code> if it failed to resolve it.
+     */
+    public ResourceValue resolveValue(String type, String name, String value,
+            boolean isFrameworkValue) {
+        if (value == null) {
+            return null;
+        }
+
+        // get the ResourceValue referenced by this value
+        ResourceValue resValue = findResValue(value, isFrameworkValue);
+
+        // if resValue is null, but value is not null, this means it was not a reference.
+        // we return the name/value wrapper in a ResourceValue. the isFramework flag doesn't
+        // matter.
+        if (resValue == null) {
+            return new ResourceValue(type, name, value, isFrameworkValue);
+        }
+
+        // we resolved a first reference, but we need to make sure this isn't a reference also.
+        return resolveResValue(resValue);
+    }
+
+    /**
+     * Returns the {@link ResourceValue} referenced by the value of <var>value</var>.
+     * <p/>
+     * This method ensures that it returns a {@link ResourceValue} object that does not
+     * reference another resource.
+     * If the resource cannot be resolved, it returns <code>null</code>.
+     * <p/>
+     * If a value that does not need to be resolved is given, the method will return the input
+     * value.
+     *
+     * @param value the value containing the reference to resolve.
+     * @return a {@link ResourceValue} object or <code>null</code>
+     */
+    public ResourceValue resolveResValue(ResourceValue value) {
+        if (value == null) {
+            return null;
+        }
+
+        // if the resource value is a style, we simply return it.
+        if (value instanceof StyleResourceValue) {
+            return value;
+        }
+
+        // else attempt to find another ResourceValue referenced by this one.
+        ResourceValue resolvedValue = findResValue(value.getValue(), value.isFramework());
+
+        // if the value did not reference anything, then we simply return the input value
+        if (resolvedValue == null) {
+            return value;
+        }
+
+        // otherwise, we attempt to resolve this new value as well
+        return resolveResValue(resolvedValue);
+    }
+
+
+    /**
+     * Searches for, and returns a {@link ResourceValue} by its name, and type.
+     * @param resType the type of the resource
+     * @param resName  the name of the resource
+     * @param frameworkOnly if <code>true</code>, the method does not search in the
+     * project resources
+     */
+    private ResourceValue findResValue(String resType, String resName, boolean frameworkOnly) {
+        // map of ResouceValue for the given type
+        Map<String, ResourceValue> typeMap;
+
+        // if allowed, search in the project resources first.
+        if (frameworkOnly == false) {
+            typeMap = mProjectResources.get(resType);
+            if (typeMap != null) {
+                ResourceValue item = typeMap.get(resName);
+                if (item != null) {
+                    return item;
+                }
+            }
+        }
+
+        // now search in the framework resources.
+        typeMap = mFrameworkResources.get(resType);
+        if (typeMap != null) {
+            ResourceValue item = typeMap.get(resName);
+            if (item != null) {
+                return item;
+            }
+
+            // if it was not found and the type is an id, it is possible that the ID was
+            // generated dynamically when compiling the framework resources.
+            // Look for it in the R map.
+            if (mFrameworkProvider != null && RES_ID.equals(resType)) {
+                if (mFrameworkProvider.getId(resType, resName) != null) {
+                    return new ResourceValue(resType, resName, true);
+                }
+            }
+        }
+
+        // didn't find the resource anywhere.
+        // This is normal if the resource is an ID that is generated automatically.
+        // For other resources, we output a warning
+        if ("+id".equals(resType) == false && "+android:id".equals(resType) == false) { //$NON-NLS-1$ //$NON-NLS-2$
+            mLogger.warning(LayoutLog.TAG_RESOURCES_RESOLVE,
+                    "Couldn't resolve resource @" +
+                    (frameworkOnly ? "android:" : "") + resType + "/" + resName,
+                    new ResourceValue(resType, resName, frameworkOnly));
+        }
+        return null;
+    }
+
+    ResourceValue getResource(String resourceType, String resourceName,
+            Map<String, Map<String, ResourceValue>> resourceRepository) {
+        Map<String, ResourceValue> typeMap = resourceRepository.get(resourceType);
+        if (typeMap != null) {
+            ResourceValue item = typeMap.get(resourceName);
+            if (item != null) {
+                item = resolveResValue(item);
+                return item;
+            }
+        }
+
+        // didn't find the resource anywhere.
+        return null;
+
+    }
+
+    /**
+     * Compute style information from the given list of style for the project and framework.
+     * @param themeName the name of the current theme.
+     * @param isProjectTheme Is this a project theme?
+     */
+    private void computeStyleMaps(String themeName, boolean isProjectTheme) {
+        Map<String, ResourceValue> projectStyleMap = mProjectResources.get(RES_STYLE);
+        Map<String, ResourceValue> frameworkStyleMap = mFrameworkResources.get(RES_STYLE);
+
+        if (projectStyleMap != null && frameworkStyleMap != null) {
+            // first, get the theme
+            ResourceValue theme = null;
+
+            // project theme names have been prepended with a *
+            if (isProjectTheme) {
+                theme = projectStyleMap.get(themeName);
+            } else {
+                theme = frameworkStyleMap.get(themeName);
+            }
+
+            if (theme instanceof StyleResourceValue) {
+                // compute the inheritance map for both the project and framework styles
+                computeStyleInheritance(projectStyleMap.values(), projectStyleMap,
+                        frameworkStyleMap);
+
+                // Compute the style inheritance for the framework styles/themes.
+                // Since, for those, the style parent values do not contain 'android:'
+                // we want to force looking in the framework style only to avoid using
+                // similarly named styles from the project.
+                // To do this, we pass null in lieu of the project style map.
+                computeStyleInheritance(frameworkStyleMap.values(), null /*inProjectStyleMap */,
+                        frameworkStyleMap);
+
+                mTheme = (StyleResourceValue) theme;
+            }
+        }
+    }
+
+
+
+    /**
+     * Compute the parent style for all the styles in a given list.
+     * @param styles the styles for which we compute the parent.
+     * @param inProjectStyleMap the map of project styles.
+     * @param inFrameworkStyleMap the map of framework styles.
+     * @param outInheritanceMap the map of style inheritance. This is filled by the method.
+     */
+    private void computeStyleInheritance(Collection<ResourceValue> styles,
+            Map<String, ResourceValue> inProjectStyleMap,
+            Map<String, ResourceValue> inFrameworkStyleMap) {
+        for (ResourceValue value : styles) {
+            if (value instanceof StyleResourceValue) {
+                StyleResourceValue style = (StyleResourceValue)value;
+                StyleResourceValue parentStyle = null;
+
+                // first look for a specified parent.
+                String parentName = style.getParentStyle();
+
+                // no specified parent? try to infer it from the name of the style.
+                if (parentName == null) {
+                    parentName = getParentName(value.getName());
+                }
+
+                if (parentName != null) {
+                    parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap);
+
+                    if (parentStyle != null) {
+                        mStyleInheritanceMap.put(style, parentStyle);
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Computes the name of the parent style, or <code>null</code> if the style is a root style.
+     */
+    private String getParentName(String styleName) {
+        int index = styleName.lastIndexOf('.');
+        if (index != -1) {
+            return styleName.substring(0, index);
+        }
+
+        return null;
+    }
+
+    /**
+     * Searches for and returns the {@link StyleResourceValue} from a given name.
+     * <p/>The format of the name can be:
+     * <ul>
+     * <li>[android:]&lt;name&gt;</li>
+     * <li>[android:]style/&lt;name&gt;</li>
+     * <li>@[android:]style/&lt;name&gt;</li>
+     * </ul>
+     * @param parentName the name of the style.
+     * @param inProjectStyleMap the project style map. Can be <code>null</code>
+     * @param inFrameworkStyleMap the framework style map.
+     * @return The matching {@link StyleResourceValue} object or <code>null</code> if not found.
+     */
+    private StyleResourceValue getStyle(String parentName,
+            Map<String, ResourceValue> inProjectStyleMap,
+            Map<String, ResourceValue> inFrameworkStyleMap) {
+        boolean frameworkOnly = false;
+
+        String name = parentName;
+
+        // remove the useless @ if it's there
+        if (name.startsWith(PREFIX_RESOURCE_REF)) {
+            name = name.substring(PREFIX_RESOURCE_REF.length());
+        }
+
+        // check for framework identifier.
+        if (name.startsWith(PREFIX_ANDROID)) {
+            frameworkOnly = true;
+            name = name.substring(PREFIX_ANDROID.length());
+        }
+
+        // at this point we could have the format <type>/<name>. we want only the name as long as
+        // the type is style.
+        if (name.startsWith(REFERENCE_STYLE)) {
+            name = name.substring(REFERENCE_STYLE.length());
+        } else if (name.indexOf('/') != -1) {
+            return null;
+        }
+
+        ResourceValue parent = null;
+
+        // if allowed, search in the project resources.
+        if (frameworkOnly == false && inProjectStyleMap != null) {
+            parent = inProjectStyleMap.get(name);
+        }
+
+        // if not found, then look in the framework resources.
+        if (parent == null) {
+            parent = inFrameworkStyleMap.get(name);
+        }
+
+        // make sure the result is the proper class type and return it.
+        if (parent instanceof StyleResourceValue) {
+            return (StyleResourceValue)parent;
+        }
+
+        assert false;
+        mLogger.error(LayoutLog.TAG_RESOURCES_RESOLVE,
+                String.format("Unable to resolve parent style name: %s", parentName),
+                null /*data*/);
+
+        return null;
+    }
+
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
index 194687e..112af1e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
@@ -41,25 +41,6 @@
 
     public final static String R = "com.android.internal.R";
 
-    public final static String PREFIX_ANDROID_RESOURCE_REF = "@android:";
-    public final static String PREFIX_RESOURCE_REF = "@";
-    public final static String PREFIX_ANDROID_THEME_REF = "?android:";
-    public final static String PREFIX_THEME_REF = "?";
-
-    public final static String PREFIX_ANDROID = "android:";
-
-    public final static String RES_ANIMATOR = "animator";
-    public final static String RES_STYLE = "style";
-    public final static String RES_ATTR = "attr";
-    public final static String RES_DIMEN = "dimen";
-    public final static String RES_DRAWABLE = "drawable";
-    public final static String RES_COLOR = "color";
-    public final static String RES_LAYOUT = "layout";
-    public final static String RES_STRING = "string";
-    public final static String RES_ID = "id";
-
-    public final static String REFERENCE_STYLE = RES_STYLE + "/";
-    public final static String REFERENCE_NULL = "@null";
 
     public final static String MATCH_PARENT = "match_parent";
     public final static String FILL_PARENT = "fill_parent";
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 82e217a..f633201 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -20,6 +20,7 @@
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.StyleResourceValue;
+import com.android.ide.common.resources.ResourceResolver;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
 import com.android.layoutlib.bridge.impl.Stack;
@@ -76,12 +77,9 @@
     private Resources mResources;
     private Theme mTheme;
     private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>();
-    private final StyleResourceValue mThemeValues;
     private final Object mProjectKey;
     private final DisplayMetrics mMetrics;
-    private final Map<String, Map<String, ResourceValue>> mProjectResources;
-    private final Map<String, Map<String, ResourceValue>> mFrameworkResources;
-    private final Map<StyleResourceValue, StyleResourceValue> mStyleInheritanceMap;
+    private final ResourceResolver mResourceResolver;
 
     private final Map<Object, Map<String, String>> mDefaultPropMaps =
         new IdentityHashMap<Object, Map<String,String>>();
@@ -116,19 +114,13 @@
      * @param projectCallback
      */
     public BridgeContext(Object projectKey, DisplayMetrics metrics,
-            StyleResourceValue currentTheme,
-            Map<String, Map<String, ResourceValue>> projectResources,
-            Map<String, Map<String, ResourceValue>> frameworkResources,
-            Map<StyleResourceValue, StyleResourceValue> styleInheritanceMap,
+            ResourceResolver resourceResolver,
             IProjectCallback projectCallback) {
         mProjectKey = projectKey;
         mMetrics = metrics;
         mProjectCallback = projectCallback;
 
-        mThemeValues = currentTheme;
-        mProjectResources = projectResources;
-        mFrameworkResources = frameworkResources;
-        mStyleInheritanceMap = styleInheritanceMap;
+        mResourceResolver = resourceResolver;
 
         mFragments.mCurState = Fragment.CREATED;
         mFragments.mActivity = this;
@@ -180,6 +172,10 @@
         return mProjectCallback;
     }
 
+    public ResourceResolver getResolver() {
+        return mResourceResolver;
+    }
+
     public Map<String, String> getDefaultPropMap(Object key) {
         return mDefaultPropMaps.get(key);
     }
@@ -265,7 +261,7 @@
 
     @Override
     public final TypedArray obtainStyledAttributes(int[] attrs) {
-        return createStyleBasedTypedArray(mThemeValues, attrs);
+        return createStyleBasedTypedArray(mResourceResolver.getTheme(), attrs);
     }
 
     @Override
@@ -362,7 +358,8 @@
             customStyle = set.getAttributeValue(null /* namespace*/, "style");
         }
         if (customStyle != null) {
-            ResourceValue item = findResValue(customStyle, false /*forceFrameworkOnly*/);
+            ResourceValue item = mResourceResolver.findResValue(customStyle,
+                    false /*forceFrameworkOnly*/);
 
             if (item instanceof StyleResourceValue) {
                 defStyleValues = (StyleResourceValue)item;
@@ -378,22 +375,21 @@
             }
 
             // look for the style in the current theme, and its parent:
-            if (mThemeValues != null) {
-                ResourceValue item = findItemInStyle(mThemeValues, defStyleName);
+            ResourceValue item = mResourceResolver.findItemInTheme(defStyleName);
 
-                if (item != null) {
-                    // item is a reference to a style entry. Search for it.
-                    item = findResValue(item.getValue(), false /*forceFrameworkOnly*/);
+            if (item != null) {
+                // item is a reference to a style entry. Search for it.
+                item = mResourceResolver.findResValue(item.getValue(),
+                        false /*forceFrameworkOnly*/);
 
-                    if (item instanceof StyleResourceValue) {
-                        defStyleValues = (StyleResourceValue)item;
-                    }
-                } else {
-                    Bridge.getLog().error(null,
-                            String.format(
-                                    "Failed to find style '%s' in current theme", defStyleName),
-                            null /*data*/);
+                if (item instanceof StyleResourceValue) {
+                    defStyleValues = (StyleResourceValue)item;
                 }
+            } else {
+                Bridge.getLog().error(null,
+                        String.format(
+                                "Failed to find style '%s' in current theme", defStyleName),
+                        null /*data*/);
             }
         }
 
@@ -425,13 +421,13 @@
 
                     // look for the value in the defStyle first (and its parent if needed)
                     if (defStyleValues != null) {
-                        resValue = findItemInStyle(defStyleValues, name);
+                        resValue = mResourceResolver.findItemInStyle(defStyleValues, name);
                     }
 
                     // if the item is not present in the defStyle, we look in the main theme (and
                     // its parent themes)
-                    if (resValue == null && mThemeValues != null) {
-                        resValue = findItemInStyle(mThemeValues, name);
+                    if (resValue == null) {
+                        resValue = mResourceResolver.findItemInTheme(name);
                     }
 
                     // if we found a value, we make sure this doesn't reference another value.
@@ -442,14 +438,15 @@
                             defaultPropMap.put(name, resValue.getValue());
                         }
 
-                        resValue = resolveResValue(resValue);
+                        resValue = mResourceResolver.resolveResValue(resValue);
                     }
 
                     ta.bridgeSetValue(index, name, resValue);
                 } else {
                     // there is a value in the XML, but we need to resolve it in case it's
                     // referencing another resource or a theme value.
-                    ta.bridgeSetValue(index, name, resolveValue(null, name, value, isPlatformFile));
+                    ta.bridgeSetValue(index, name,
+                            mResourceResolver.resolveValue(null, name, value, isPlatformFile));
                 }
             }
         }
@@ -487,10 +484,10 @@
             String name = styleAttribute.getValue();
 
             // get the value from the style, or its parent styles.
-            ResourceValue resValue = findItemInStyle(style, name);
+            ResourceValue resValue = mResourceResolver.findItemInStyle(style, name);
 
             // resolve it to make sure there are no references left.
-            ta.bridgeSetValue(index, name, resolveResValue(resValue));
+            ta.bridgeSetValue(index, name, mResourceResolver.resolveResValue(resValue));
         }
 
         ta.sealArray();
@@ -500,295 +497,6 @@
 
 
     /**
-     * Resolves the value of a resource, if the value references a theme or resource value.
-     * <p/>
-     * This method ensures that it returns a {@link ResourceValue} object that does not
-     * reference another resource.
-     * If the resource cannot be resolved, it returns <code>null</code>.
-     * <p/>
-     * If a value that does not need to be resolved is given, the method will return a new
-     * instance of {@link ResourceValue} that contains the input value.
-     *
-     * @param type the type of the resource
-     * @param name the name of the attribute containing this value.
-     * @param value the resource value, or reference to resolve
-     * @param isFrameworkValue whether the value is a framework value.
-     *
-     * @return the resolved resource value or <code>null</code> if it failed to resolve it.
-     */
-    private ResourceValue resolveValue(String type, String name, String value,
-            boolean isFrameworkValue) {
-        if (value == null) {
-            return null;
-        }
-
-        // get the ResourceValue referenced by this value
-        ResourceValue resValue = findResValue(value, isFrameworkValue);
-
-        // if resValue is null, but value is not null, this means it was not a reference.
-        // we return the name/value wrapper in a ResourceValue. the isFramework flag doesn't
-        // matter.
-        if (resValue == null) {
-            return new ResourceValue(type, name, value, isFrameworkValue);
-        }
-
-        // we resolved a first reference, but we need to make sure this isn't a reference also.
-        return resolveResValue(resValue);
-    }
-
-    /**
-     * Returns the {@link ResourceValue} referenced by the value of <var>value</var>.
-     * <p/>
-     * This method ensures that it returns a {@link ResourceValue} object that does not
-     * reference another resource.
-     * If the resource cannot be resolved, it returns <code>null</code>.
-     * <p/>
-     * If a value that does not need to be resolved is given, the method will return the input
-     * value.
-     *
-     * @param value the value containing the reference to resolve.
-     * @return a {@link ResourceValue} object or <code>null</code>
-     */
-    public ResourceValue resolveResValue(ResourceValue value) {
-        if (value == null) {
-            return null;
-        }
-
-        // if the resource value is a style, we simply return it.
-        if (value instanceof StyleResourceValue) {
-            return value;
-        }
-
-        // else attempt to find another ResourceValue referenced by this one.
-        ResourceValue resolvedValue = findResValue(value.getValue(), value.isFramework());
-
-        // if the value did not reference anything, then we simply return the input value
-        if (resolvedValue == null) {
-            return value;
-        }
-
-        // otherwise, we attempt to resolve this new value as well
-        return resolveResValue(resolvedValue);
-    }
-
-    /**
-     * Searches for, and returns a {@link ResourceValue} by its reference.
-     * <p/>
-     * The reference format can be:
-     * <pre>@resType/resName</pre>
-     * <pre>@android:resType/resName</pre>
-     * <pre>@resType/android:resName</pre>
-     * <pre>?resType/resName</pre>
-     * <pre>?android:resType/resName</pre>
-     * <pre>?resType/android:resName</pre>
-     * Any other string format will return <code>null</code>.
-     * <p/>
-     * The actual format of a reference is <pre>@[namespace:]resType/resName</pre> but this method
-     * only support the android namespace.
-     *
-     * @param reference the resource reference to search for.
-     * @param forceFrameworkOnly if true all references are considered to be toward framework
-     *      resource even if the reference does not include the android: prefix.
-     * @return a {@link ResourceValue} or <code>null</code>.
-     */
-    ResourceValue findResValue(String reference, boolean forceFrameworkOnly) {
-        if (reference == null) {
-            return null;
-        }
-        if (reference.startsWith(BridgeConstants.PREFIX_THEME_REF)) {
-            // no theme? no need to go further!
-            if (mThemeValues == null) {
-                return null;
-            }
-
-            boolean frameworkOnly = false;
-
-            // eliminate the prefix from the string
-            if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_THEME_REF)) {
-                frameworkOnly = true;
-                reference = reference.substring(BridgeConstants.PREFIX_ANDROID_THEME_REF.length());
-            } else {
-                reference = reference.substring(BridgeConstants.PREFIX_THEME_REF.length());
-            }
-
-            // at this point, value can contain type/name (drawable/foo for instance).
-            // split it to make sure.
-            String[] segments = reference.split("\\/");
-
-            // we look for the referenced item name.
-            String referenceName = null;
-
-            if (segments.length == 2) {
-                // there was a resType in the reference. If it's attr, we ignore it
-                // else, we assert for now.
-                if (BridgeConstants.RES_ATTR.equals(segments[0])) {
-                    referenceName = segments[1];
-                } else {
-                    // At this time, no support for ?type/name where type is not "attr"
-                    return null;
-                }
-            } else {
-                // it's just an item name.
-                referenceName = segments[0];
-            }
-
-            // now we look for android: in the referenceName in order to support format
-            // such as: ?attr/android:name
-            if (referenceName.startsWith(BridgeConstants.PREFIX_ANDROID)) {
-                frameworkOnly = true;
-                referenceName = referenceName.substring(BridgeConstants.PREFIX_ANDROID.length());
-            }
-
-            // Now look for the item in the theme, starting with the current one.
-            if (frameworkOnly) {
-                // FIXME for now we do the same as if it didn't specify android:
-                return findItemInStyle(mThemeValues, referenceName);
-            }
-
-            return findItemInStyle(mThemeValues, referenceName);
-        } else if (reference.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
-            boolean frameworkOnly = false;
-
-            // check for the specific null reference value.
-            if (BridgeConstants.REFERENCE_NULL.equals(reference)) {
-                return null;
-            }
-
-            // Eliminate the prefix from the string.
-            if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_RESOURCE_REF)) {
-                frameworkOnly = true;
-                reference = reference.substring(
-                        BridgeConstants.PREFIX_ANDROID_RESOURCE_REF.length());
-            } else {
-                reference = reference.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
-            }
-
-            // at this point, value contains type/[android:]name (drawable/foo for instance)
-            String[] segments = reference.split("\\/");
-
-            // now we look for android: in the resource name in order to support format
-            // such as: @drawable/android:name
-            if (segments[1].startsWith(BridgeConstants.PREFIX_ANDROID)) {
-                frameworkOnly = true;
-                segments[1] = segments[1].substring(BridgeConstants.PREFIX_ANDROID.length());
-            }
-
-            return findResValue(segments[0], segments[1],
-                    forceFrameworkOnly ? true :frameworkOnly);
-        }
-
-        // Looks like the value didn't reference anything. Return null.
-        return null;
-    }
-
-    /**
-     * Searches for, and returns a {@link ResourceValue} by its name, and type.
-     * @param resType the type of the resource
-     * @param resName  the name of the resource
-     * @param frameworkOnly if <code>true</code>, the method does not search in the
-     * project resources
-     */
-    private ResourceValue findResValue(String resType, String resName, boolean frameworkOnly) {
-        // map of ResouceValue for the given type
-        Map<String, ResourceValue> typeMap;
-
-        // if allowed, search in the project resources first.
-        if (frameworkOnly == false) {
-            typeMap = mProjectResources.get(resType);
-            if (typeMap != null) {
-                ResourceValue item = typeMap.get(resName);
-                if (item != null) {
-                    return item;
-                }
-            }
-        }
-
-        // now search in the framework resources.
-        typeMap = mFrameworkResources.get(resType);
-        if (typeMap != null) {
-            ResourceValue item = typeMap.get(resName);
-            if (item != null) {
-                return item;
-            }
-
-            // if it was not found and the type is an id, it is possible that the ID was
-            // generated dynamically when compiling the framework resources.
-            // Look for it in the R map.
-            if (BridgeConstants.RES_ID.equals(resType)) {
-                if (Bridge.getResourceValue(resType, resName) != null) {
-                    return new ResourceValue(resType, resName, true);
-                }
-            }
-        }
-
-        // didn't find the resource anywhere.
-        // This is normal if the resource is an ID that is generated automatically.
-        // For other resources, we output a warning
-        if ("+id".equals(resType) == false && "+android:id".equals(resType) == false) { //$NON-NLS-1$ //$NON-NLS-2$
-            Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE,
-                    "Couldn't resolve resource @" +
-                    (frameworkOnly ? "android:" : "") + resType + "/" + resName,
-                    new ResourceValue(resType, resName, frameworkOnly));
-        }
-        return null;
-    }
-
-    /**
-     * Returns a framework resource by type and name. The returned resource is resolved.
-     * @param resourceType the type of the resource
-     * @param resourceName the name of the resource
-     */
-    public ResourceValue getFrameworkResource(String resourceType, String resourceName) {
-        return getResource(resourceType, resourceName, mFrameworkResources);
-    }
-
-    /**
-     * Returns a project resource by type and name. The returned resource is resolved.
-     * @param resourceType the type of the resource
-     * @param resourceName the name of the resource
-     */
-    public ResourceValue getProjectResource(String resourceType, String resourceName) {
-        return getResource(resourceType, resourceName, mProjectResources);
-    }
-
-    ResourceValue getResource(String resourceType, String resourceName,
-            Map<String, Map<String, ResourceValue>> resourceRepository) {
-        Map<String, ResourceValue> typeMap = resourceRepository.get(resourceType);
-        if (typeMap != null) {
-            ResourceValue item = typeMap.get(resourceName);
-            if (item != null) {
-                item = resolveResValue(item);
-                return item;
-            }
-        }
-
-        // didn't find the resource anywhere.
-        return null;
-
-    }
-
-    /**
-     * Returns the {@link ResourceValue} matching a given name in a given style. If the
-     * item is not directly available in the style, the method looks in its parent style.
-     * @param style the style to search in
-     * @param itemName the name of the item to search for.
-     * @return the {@link ResourceValue} object or <code>null</code>
-     */
-    public ResourceValue findItemInStyle(StyleResourceValue style, String itemName) {
-        ResourceValue item = style.findValue(itemName);
-
-        // if we didn't find it, we look in the parent style (if applicable)
-        if (item == null && mStyleInheritanceMap != null) {
-            StyleResourceValue parentStyle = mStyleInheritanceMap.get(style);
-            if (parentStyle != null) {
-                return findItemInStyle(parentStyle, itemName);
-            }
-        }
-
-        return item;
-    }
-
-    /**
      * The input int[] attrs is one of com.android.internal.R.styleable fields where the name
      * of the field is the style being referenced and the array contains one index per attribute.
      * <p/>
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
index e95d295..61f47ba 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
@@ -19,8 +19,8 @@
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.resources.ResourceResolver;
 import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.BridgeConstants;
 
 import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
@@ -155,14 +155,14 @@
 
             String[] layoutInfo = Bridge.resolveResourceValue(resource);
             if (layoutInfo != null) {
-                value = bridgeContext.getFrameworkResource(BridgeConstants.RES_LAYOUT,
-                        layoutInfo[0]);
+                value = bridgeContext.getResolver().getFrameworkResource(
+                        ResourceResolver.RES_LAYOUT, layoutInfo[0]);
             } else {
                 layoutInfo = mProjectCallback.resolveResourceValue(resource);
 
                 if (layoutInfo != null) {
-                    value = bridgeContext.getProjectResource(BridgeConstants.RES_LAYOUT,
-                            layoutInfo[0]);
+                    value = bridgeContext.getResolver().getProjectResource(
+                            ResourceResolver.RES_LAYOUT, layoutInfo[0]);
                 }
             }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
index 23d81a2..3af6a1b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
@@ -104,7 +104,7 @@
 
         if (resourceInfo != null) {
             platformResFlag_out[0] = true;
-            return mContext.getFrameworkResource(resourceInfo[1], resourceInfo[0]);
+            return mContext.getResolver().getFrameworkResource(resourceInfo[1], resourceInfo[0]);
         }
 
         // didn't find a match in the framework? look in the project.
@@ -113,7 +113,7 @@
 
             if (resourceInfo != null) {
                 platformResFlag_out[0] = false;
-                return mContext.getProjectResource(resourceInfo[1], resourceInfo[0]);
+                return mContext.getResolver().getProjectResource(resourceInfo[1], resourceInfo[0]);
             }
         }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index 84bb4d1..b166da5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -19,6 +19,7 @@
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.StyleResourceValue;
+import com.android.ide.common.resources.ResourceResolver;
 import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
@@ -633,11 +634,11 @@
             // if this is a framework id
             if (mPlatformFile || value.startsWith("@android") || value.startsWith("@+android")) {
                 // look for idName in the android R classes
-                return mContext.getFrameworkResourceValue(BridgeConstants.RES_ID, idName, defValue);
+                return mContext.getFrameworkResourceValue(ResourceResolver.RES_ID, idName, defValue);
             }
 
             // look for idName in the project R class.
-            return mContext.getProjectResourceValue(BridgeConstants.RES_ID, idName, defValue);
+            return mContext.getProjectResourceValue(ResourceResolver.RES_ID, idName, defValue);
         }
 
         // not a direct id valid reference? resolve it
@@ -682,7 +683,7 @@
 
         ResourceValue value = mResourceData[index];
         String stringValue = value.getValue();
-        if (stringValue == null || BridgeConstants.REFERENCE_NULL.equals(stringValue)) {
+        if (stringValue == null || ResourceResolver.REFERENCE_NULL.equals(stringValue)) {
             return null;
         }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
index ba45217..45d8e26 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
@@ -17,6 +17,7 @@
 package com.android.layoutlib.bridge.android;
 
 import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.resources.ResourceResolver;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
 
@@ -57,7 +58,7 @@
         String ns = mParser.getAttributeNamespace(index);
 
         if (BridgeConstants.NS_RESOURCES.equals(ns)) {
-            Integer v = Bridge.getResourceValue(BridgeConstants.RES_ATTR, name);
+            Integer v = Bridge.getResourceValue(ResourceResolver.RES_ATTR, name);
             if (v != null) {
                 return v.intValue();
             }
@@ -68,7 +69,7 @@
         // this is not an attribute in the android namespace, we query the customviewloader, if
         // the namespaces match.
         if (mContext.getProjectCallback().getNamespace().equals(ns)) {
-            Integer v = mContext.getProjectCallback().getResourceValue(BridgeConstants.RES_ATTR,
+            Integer v = mContext.getProjectCallback().getResourceValue(ResourceResolver.RES_ATTR,
                     name);
             if (v != null) {
                 return v.intValue();
@@ -102,8 +103,9 @@
 
     private int resolveResourceValue(String value, int defaultValue) {
         // now look for this particular value
-        ResourceValue resource = mContext.resolveResValue(
-                mContext.findResValue(value, mPlatformFile));
+        ResourceResolver resolver = mContext.getResolver();
+        ResourceValue resource = resolver.resolveResValue(
+                resolver.findResValue(value, mPlatformFile));
 
         if (resource != null) {
             Integer id = null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 2439791..a227d0c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -38,9 +38,10 @@
 import com.android.ide.common.rendering.api.ViewInfo;
 import com.android.ide.common.rendering.api.Params.RenderingMode;
 import com.android.ide.common.rendering.api.Result.Status;
+import com.android.ide.common.resources.ResourceResolver;
+import com.android.ide.common.resources.ResourceResolver.IFrameworkResourceIdProvider;
 import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.BridgeConstants;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.BridgeInflater;
 import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
@@ -73,8 +74,6 @@
 import java.awt.Graphics2D;
 import java.awt.image.BufferedImage;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
@@ -106,7 +105,6 @@
     private BridgeContext mContext;
     private BridgeXmlBlockParser mBlockParser;
     private BridgeInflater mInflater;
-    private StyleResourceValue mCurrentTheme;
     private int mScreenOffset;
     private ResourceValue mWindowBackground;
     private FrameLayout mViewRoot;
@@ -170,18 +168,23 @@
         metrics.xdpi = mParams.getXdpi();
         metrics.ydpi = mParams.getYdpi();
 
-        // find the current theme and compute the style inheritance map
-        Map<StyleResourceValue, StyleResourceValue> styleParentMap =
-            new HashMap<StyleResourceValue, StyleResourceValue>();
+        // create the resource resolver
+        ResourceResolver resolver = ResourceResolver.create(
+                new IFrameworkResourceIdProvider() {
+                    public Integer getId(String resType, String resName) {
+                        return Bridge.getResourceValue(resType, resName);
+                    }
+                },
+                mParams.getProjectResources(),
+                mParams.getFrameworkResources(),
+                mParams.getThemeName(),
+                mParams.isProjectTheme(),
+                mParams.getLog());
 
-        mCurrentTheme = computeStyleMaps(mParams.getThemeName(), mParams.isProjectTheme(),
-                mParams.getProjectResources().get(BridgeConstants.RES_STYLE),
-                mParams.getFrameworkResources().get(BridgeConstants.RES_STYLE), styleParentMap);
 
         // build the context
-        mContext = new BridgeContext(mParams.getProjectKey(), metrics, mCurrentTheme,
-                mParams.getProjectResources(), mParams.getFrameworkResources(),
-                styleParentMap, mParams.getProjectCallback());
+        mContext = new BridgeContext(mParams.getProjectKey(), metrics, resolver,
+                mParams.getProjectCallback());
 
         // set the current rendering context
         sCurrentContext = mContext;
@@ -193,12 +196,12 @@
         // get the screen offset and window-background resource
         mWindowBackground = null;
         mScreenOffset = 0;
-        if (mCurrentTheme != null && mParams.isBgColorOverridden() == false) {
-            mWindowBackground = mContext.findItemInStyle(mCurrentTheme, "windowBackground");
-            mWindowBackground = mContext.resolveResValue(mWindowBackground);
+        StyleResourceValue theme = resolver.getTheme();
+        if (theme != null && mParams.isBgColorOverridden() == false) {
+            mWindowBackground = resolver.findItemInTheme("windowBackground");
+            mWindowBackground = resolver.resolveResValue(mWindowBackground);
 
-            mScreenOffset = getScreenOffset(mParams.getFrameworkResources(), mCurrentTheme,
-                    mContext);
+            mScreenOffset = getScreenOffset(resolver, metrics);
         }
 
         // build the inflater and parser.
@@ -499,18 +502,18 @@
         ResourceValue animationResource = null;
         int animationId = 0;
         if (isFrameworkAnimation) {
-            animationResource = mContext.getFrameworkResource(BridgeConstants.RES_ANIMATOR,
-                    animationName);
+            animationResource = mContext.getResolver().getFrameworkResource(
+                    ResourceResolver.RES_ANIMATOR, animationName);
             if (animationResource != null) {
-                animationId = Bridge.getResourceValue(BridgeConstants.RES_ANIMATOR,
+                animationId = Bridge.getResourceValue(ResourceResolver.RES_ANIMATOR,
                         animationName);
             }
         } else {
-            animationResource = mContext.getProjectResource(BridgeConstants.RES_ANIMATOR,
-                    animationName);
+            animationResource = mContext.getResolver().getProjectResource(
+                    ResourceResolver.RES_ANIMATOR, animationName);
             if (animationResource != null) {
                 animationId = mContext.getProjectCallback().getResourceValue(
-                        BridgeConstants.RES_ANIMATOR, animationName);
+                        ResourceResolver.RES_ANIMATOR, animationName);
             }
         }
 
@@ -905,182 +908,21 @@
         }
     }
 
-
-    /**
-     * Compute style information from the given list of style for the project and framework.
-     * @param themeName the name of the current theme.  In order to differentiate project and
-     * platform themes sharing the same name, all project themes must be prepended with
-     * a '*' character.
-     * @param isProjectTheme Is this a project theme
-     * @param inProjectStyleMap the project style map
-     * @param inFrameworkStyleMap the framework style map
-     * @param outInheritanceMap the map of style inheritance. This is filled by the method
-     * @return the {@link StyleResourceValue} matching <var>themeName</var>
-     */
-    private StyleResourceValue computeStyleMaps(
-            String themeName, boolean isProjectTheme, Map<String,
-            ResourceValue> inProjectStyleMap, Map<String, ResourceValue> inFrameworkStyleMap,
-            Map<StyleResourceValue, StyleResourceValue> outInheritanceMap) {
-
-        if (inProjectStyleMap != null && inFrameworkStyleMap != null) {
-            // first, get the theme
-            ResourceValue theme = null;
-
-            // project theme names have been prepended with a *
-            if (isProjectTheme) {
-                theme = inProjectStyleMap.get(themeName);
-            } else {
-                theme = inFrameworkStyleMap.get(themeName);
-            }
-
-            if (theme instanceof StyleResourceValue) {
-                // compute the inheritance map for both the project and framework styles
-                computeStyleInheritance(inProjectStyleMap.values(), inProjectStyleMap,
-                        inFrameworkStyleMap, outInheritanceMap);
-
-                // Compute the style inheritance for the framework styles/themes.
-                // Since, for those, the style parent values do not contain 'android:'
-                // we want to force looking in the framework style only to avoid using
-                // similarly named styles from the project.
-                // To do this, we pass null in lieu of the project style map.
-                computeStyleInheritance(inFrameworkStyleMap.values(), null /*inProjectStyleMap */,
-                        inFrameworkStyleMap, outInheritanceMap);
-
-                return (StyleResourceValue)theme;
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Compute the parent style for all the styles in a given list.
-     * @param styles the styles for which we compute the parent.
-     * @param inProjectStyleMap the map of project styles.
-     * @param inFrameworkStyleMap the map of framework styles.
-     * @param outInheritanceMap the map of style inheritance. This is filled by the method.
-     */
-    private void computeStyleInheritance(Collection<ResourceValue> styles,
-            Map<String, ResourceValue> inProjectStyleMap,
-            Map<String, ResourceValue> inFrameworkStyleMap,
-            Map<StyleResourceValue, StyleResourceValue> outInheritanceMap) {
-        for (ResourceValue value : styles) {
-            if (value instanceof StyleResourceValue) {
-                StyleResourceValue style = (StyleResourceValue)value;
-                StyleResourceValue parentStyle = null;
-
-                // first look for a specified parent.
-                String parentName = style.getParentStyle();
-
-                // no specified parent? try to infer it from the name of the style.
-                if (parentName == null) {
-                    parentName = getParentName(value.getName());
-                }
-
-                if (parentName != null) {
-                    parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap);
-
-                    if (parentStyle != null) {
-                        outInheritanceMap.put(style, parentStyle);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Searches for and returns the {@link StyleResourceValue} from a given name.
-     * <p/>The format of the name can be:
-     * <ul>
-     * <li>[android:]&lt;name&gt;</li>
-     * <li>[android:]style/&lt;name&gt;</li>
-     * <li>@[android:]style/&lt;name&gt;</li>
-     * </ul>
-     * @param parentName the name of the style.
-     * @param inProjectStyleMap the project style map. Can be <code>null</code>
-     * @param inFrameworkStyleMap the framework style map.
-     * @return The matching {@link StyleResourceValue} object or <code>null</code> if not found.
-     */
-    private StyleResourceValue getStyle(String parentName,
-            Map<String, ResourceValue> inProjectStyleMap,
-            Map<String, ResourceValue> inFrameworkStyleMap) {
-        boolean frameworkOnly = false;
-
-        String name = parentName;
-
-        // remove the useless @ if it's there
-        if (name.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
-            name = name.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
-        }
-
-        // check for framework identifier.
-        if (name.startsWith(BridgeConstants.PREFIX_ANDROID)) {
-            frameworkOnly = true;
-            name = name.substring(BridgeConstants.PREFIX_ANDROID.length());
-        }
-
-        // at this point we could have the format <type>/<name>. we want only the name as long as
-        // the type is style.
-        if (name.startsWith(BridgeConstants.REFERENCE_STYLE)) {
-            name = name.substring(BridgeConstants.REFERENCE_STYLE.length());
-        } else if (name.indexOf('/') != -1) {
-            return null;
-        }
-
-        ResourceValue parent = null;
-
-        // if allowed, search in the project resources.
-        if (frameworkOnly == false && inProjectStyleMap != null) {
-            parent = inProjectStyleMap.get(name);
-        }
-
-        // if not found, then look in the framework resources.
-        if (parent == null) {
-            parent = inFrameworkStyleMap.get(name);
-        }
-
-        // make sure the result is the proper class type and return it.
-        if (parent instanceof StyleResourceValue) {
-            return (StyleResourceValue)parent;
-        }
-
-        assert false;
-        mParams.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
-                String.format("Unable to resolve parent style name: %s", parentName),
-                null /*data*/);
-
-        return null;
-    }
-
-    /**
-     * Computes the name of the parent style, or <code>null</code> if the style is a root style.
-     */
-    private String getParentName(String styleName) {
-        int index = styleName.lastIndexOf('.');
-        if (index != -1) {
-            return styleName.substring(0, index);
-        }
-
-        return null;
-    }
-
     /**
      * Returns the top screen offset. This depends on whether the current theme defines the user
      * of the title and status bars.
-     * @param frameworkResources The framework resources
-     * @param currentTheme The current theme
-     * @param context The context
+     * @param resolver The {@link ResourceResolver}
+     * @param metrics The display metrics
      * @return the pixel height offset
      */
-    private int getScreenOffset(Map<String, Map<String, ResourceValue>> frameworkResources,
-            StyleResourceValue currentTheme, BridgeContext context) {
+    private int getScreenOffset(ResourceResolver resolver, DisplayMetrics metrics) {
         int offset = 0;
 
         // get the title bar flag from the current theme.
-        ResourceValue value = context.findItemInStyle(currentTheme, "windowNoTitle");
+        ResourceValue value = resolver.findItemInTheme("windowNoTitle");
 
         // because it may reference something else, we resolve it.
-        value = context.resolveResValue(value);
+        value = resolver.resolveResValue(value);
 
         // if there's a value and it's true (default is false)
         if (value == null || value.getValue() == null ||
@@ -1089,17 +931,17 @@
             int defaultOffset = DEFAULT_TITLE_BAR_HEIGHT;
 
             // get value from the theme.
-            value = context.findItemInStyle(currentTheme, "windowTitleSize");
+            value = resolver.findItemInTheme("windowTitleSize");
 
             // resolve it
-            value = context.resolveResValue(value);
+            value = resolver.resolveResValue(value);
 
             if (value != null) {
                 // get the numerical value, if available
                 TypedValue typedValue = ResourceHelper.getValue(value.getValue());
                 if (typedValue != null) {
                     // compute the pixel value based on the display metrics
-                    defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
+                    defaultOffset = (int)typedValue.getDimension(metrics);
                 }
             }
 
@@ -1107,10 +949,10 @@
         }
 
         // get the fullscreen flag from the current theme.
-        value = context.findItemInStyle(currentTheme, "windowFullscreen");
+        value = resolver.findItemInTheme("windowFullscreen");
 
         // because it may reference something else, we resolve it.
-        value = context.resolveResValue(value);
+        value = resolver.resolveResValue(value);
 
         if (value == null || value.getValue() == null ||
                 XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
@@ -1118,16 +960,13 @@
             // default value
             int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT;
 
-            // get the real value, first the list of Dimensions from the framework map
-            Map<String, ResourceValue> dimens = frameworkResources.get(BridgeConstants.RES_DIMEN);
-
-            // now get the value
-            value = dimens.get("status_bar_height");
+            // get the real value
+            value = resolver.getFrameworkResource(ResourceResolver.RES_DIMEN, "status_bar_height");
             if (value != null) {
                 TypedValue typedValue = ResourceHelper.getValue(value.getValue());
                 if (typedValue != null) {
                     // compute the pixel value based on the display metrics
-                    defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
+                    defaultOffset = (int)typedValue.getDimension(metrics);
                 }
             }
 
@@ -1136,7 +975,6 @@
         }
 
         return offset;
-
     }
 
     /**