summaryrefslogtreecommitdiffstats
path: root/tools/layoutlib/bridge
diff options
context:
space:
mode:
authorXavier Ducrohet <xav@android.com>2011-01-16 19:38:33 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-01-16 19:38:33 -0800
commit87ab45c0fe4db814a7364fce3b88be3a49507e90 (patch)
tree04460db0ef24ecdbdb7d45d171a3100dea0aa6fd /tools/layoutlib/bridge
parentbdac9e0fbe874cf7414228624bd0d3af4f715ccc (diff)
parentd1d6fafc7fc63543b10552dadf202dd6fa40fe6b (diff)
downloadframeworks_base-87ab45c0fe4db814a7364fce3b88be3a49507e90.zip
frameworks_base-87ab45c0fe4db814a7364fce3b88be3a49507e90.tar.gz
frameworks_base-87ab45c0fe4db814a7364fce3b88be3a49507e90.tar.bz2
Merge "LayoutLib: extract resource resolution into its own class." into honeycomb
Diffstat (limited to 'tools/layoutlib/bridge')
-rw-r--r--tools/layoutlib/bridge/Android.mk7
-rw-r--r--tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java560
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java19
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java354
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java10
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java4
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java7
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java10
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java242
9 files changed, 652 insertions, 561 deletions
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_SRC_FILES := $(call all-java-files-under,src)
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 class BridgeConstants {
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.IProjectCallback;
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 @@ public final class BridgeContext extends Activity {
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 @@ public final class BridgeContext extends Activity {
* @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 @@ public final class BridgeContext extends Activity {
return mProjectCallback;
}
+ public ResourceResolver getResolver() {
+ return mResourceResolver;
+ }
+
public Map<String, String> getDefaultPropMap(Object key) {
return mDefaultPropMaps.get(key);
}
@@ -265,7 +261,7 @@ public final class BridgeContext extends Activity {
@Override
public final TypedArray obtainStyledAttributes(int[] attrs) {
- return createStyleBasedTypedArray(mThemeValues, attrs);
+ return createStyleBasedTypedArray(mResourceResolver.getTheme(), attrs);
}
@Override
@@ -362,7 +358,8 @@ public final class BridgeContext extends Activity {
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 @@ public final class BridgeContext extends Activity {
}
// 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 @@ public final class BridgeContext extends Activity {
// 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 @@ public final class BridgeContext extends Activity {
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 @@ public final class BridgeContext extends Activity {
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 @@ public final class BridgeContext extends Activity {
/**
- * 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 @@ package com.android.layoutlib.bridge.android;
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 @@ public final class BridgeInflater extends LayoutInflater {
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 @@ public final class BridgeResources extends Resources {
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 @@ public final class BridgeResources extends Resources {
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 @@ package com.android.layoutlib.bridge.android;
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 @@ public final class BridgeTypedArray extends TypedArray {
// 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 @@ public final class BridgeTypedArray extends TypedArray {
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 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
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 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
// 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 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
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.StyleResourceValue;
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.Color;
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 @@ public class RenderSessionImpl {
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 @@ public class RenderSessionImpl {
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 @@ public class RenderSessionImpl {
// 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 @@ public class RenderSessionImpl {
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 @@ public class RenderSessionImpl {
}
}
-
- /**
- * 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 @@ public class RenderSessionImpl {
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 @@ public class RenderSessionImpl {
}
// 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 @@ public class RenderSessionImpl {
// 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 @@ public class RenderSessionImpl {
}
return offset;
-
}
/**