am 9053261a: am 052e0c58: am 770e40f8: Fix theme/style resolution in Layoutlib [DO NOT MERGE]
* commit '9053261a5413f401168d25fa4a9749723b232949':
Fix theme/style resolution in Layoutlib [DO NOT MERGE]
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index b316f23..60dddea 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1352,6 +1352,11 @@
private final AssetManager mAssets;
private final int mTheme;
+
+ // Needed by layoutlib.
+ /*package*/ int getNativeTheme() {
+ return mTheme;
+ }
}
/**
diff --git a/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java
new file mode 100644
index 0000000..f3d6ba3
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 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 android.content.res;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate used to provide implementation of a select few native methods of {@link AssetManager}
+ * <p/>
+ * Through the layoutlib_create tool, the original native methods of AssetManager have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class AssetManager_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static int newTheme(AssetManager manager) {
+ return Resources_Theme_Delegate.getDelegateManager()
+ .addNewDelegate(new Resources_Theme_Delegate());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void deleteTheme(AssetManager manager, int theme) {
+ Resources_Theme_Delegate.getDelegateManager().removeJavaReferenceFor(theme);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void applyThemeStyle(int theme, int styleRes, boolean force) {
+ Resources_Theme_Delegate delegate = Resources_Theme_Delegate.getDelegateManager()
+ .getDelegate(theme);
+ delegate.mThemeResId = styleRes;
+ delegate.force = force;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
index c9d615c..b89d15f 100644
--- a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
@@ -16,7 +16,13 @@
package android.content.res;
+import com.android.annotations.Nullable;
+import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.ide.common.rendering.api.StyleResourceValue;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.layoutlib.bridge.impl.RenderSessionImpl;
+import com.android.resources.ResourceType;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.content.res.Resources.NotFoundException;
@@ -25,7 +31,7 @@
import android.util.TypedValue;
/**
- * Delegate used to provide new implementation of a select few methods of {@link Resources$Theme}
+ * Delegate used to provide new implementation of a select few methods of {@link Resources.Theme}
*
* Through the layoutlib_create tool, the original methods of Theme have been replaced
* by calls to methods of the same name in this delegate class.
@@ -33,11 +39,30 @@
*/
public class Resources_Theme_Delegate {
+ // Resource identifier for the theme.
+ int mThemeResId;
+ // Whether to use the Theme.mThemeResId as primary theme.
+ boolean force;
+
+ // ---- delegate manager ----
+
+ private static final DelegateManager<Resources_Theme_Delegate> sManager =
+ new DelegateManager<Resources_Theme_Delegate>(Resources_Theme_Delegate.class);
+
+ public static DelegateManager<Resources_Theme_Delegate> getDelegateManager() {
+ return sManager;
+ }
+
+ // ---- delegate methods. ----
+
@LayoutlibDelegate
/*package*/ static TypedArray obtainStyledAttributes(
Resources thisResources, Theme thisTheme,
int[] attrs) {
- return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(attrs);
+ boolean changed = setupResources(thisTheme);
+ TypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(attrs);
+ restoreResources(changed);
+ return ta;
}
@LayoutlibDelegate
@@ -45,15 +70,21 @@
Resources thisResources, Theme thisTheme,
int resid, int[] attrs)
throws NotFoundException {
- return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(resid, attrs);
+ boolean changed = setupResources(thisTheme);
+ TypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(resid, attrs);
+ restoreResources(changed);
+ return ta;
}
@LayoutlibDelegate
/*package*/ static TypedArray obtainStyledAttributes(
Resources thisResources, Theme thisTheme,
AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
- return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(
- set, attrs, defStyleAttr, defStyleRes);
+ boolean changed = setupResources(thisTheme);
+ TypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(set, attrs,
+ defStyleAttr, defStyleRes);
+ restoreResources(changed);
+ return ta;
}
@LayoutlibDelegate
@@ -61,7 +92,45 @@
Resources thisResources, Theme thisTheme,
int resid, TypedValue outValue,
boolean resolveRefs) {
- return RenderSessionImpl.getCurrentContext().resolveThemeAttribute(
+ boolean changed = setupResources(thisTheme);
+ boolean found = RenderSessionImpl.getCurrentContext().resolveThemeAttribute(
resid, outValue, resolveRefs);
+ restoreResources(changed);
+ return found;
+ }
+
+ // ---- private helper methods ----
+
+ private static boolean setupResources(Theme thisTheme) {
+ Resources_Theme_Delegate themeDelegate = sManager.getDelegate(thisTheme.getNativeTheme());
+ StyleResourceValue style = resolveStyle(themeDelegate.mThemeResId);
+ if (style != null) {
+ RenderSessionImpl.getCurrentContext().getRenderResources()
+ .applyStyle(style, themeDelegate.force);
+ return true;
+ }
+ return false;
+ }
+
+ private static void restoreResources(boolean changed) {
+ if (changed) {
+ RenderSessionImpl.getCurrentContext().getRenderResources().clearStyles();
+ }
+ }
+
+ @Nullable
+ private static StyleResourceValue resolveStyle(int nativeResid) {
+ if (nativeResid == 0) {
+ return null;
+ }
+ BridgeContext context = RenderSessionImpl.getCurrentContext();
+ ResourceReference theme = context.resolveId(nativeResid);
+ if (theme.isFramework()) {
+ return (StyleResourceValue) context.getRenderResources()
+ .getFrameworkResource(ResourceType.STYLE, theme.getName());
+ } else {
+ return (StyleResourceValue) context.getRenderResources()
+ .getProjectResource(ResourceType.STYLE, theme.getName());
+ }
}
}
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 e2fced6..a1c5be4 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
@@ -16,6 +16,7 @@
package com.android.layoutlib.bridge.android;
+import com.android.annotations.Nullable;
import com.android.ide.common.rendering.api.ILayoutPullParser;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.LayoutLog;
@@ -109,7 +110,7 @@
// maps for dynamically generated id representing style objects (StyleResourceValue)
private Map<Integer, StyleResourceValue> mDynamicIdToStyleMap;
private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap;
- private int mDynamicIdGenerator = 0x01030000; // Base id for framework R.style
+ private int mDynamicIdGenerator = 0x02030000; // Base id for R.style in custom namespace
// cache for TypedArray generated from IStyleResourceValue object
private Map<int[], Map<Integer, TypedArray>> mTypedArrayCache;
@@ -311,6 +312,11 @@
}
}
+ // The base value for R.style is 0x01030000 and the custom style is 0x02030000.
+ // So, if the second byte is 03, it's probably a style.
+ if ((id >> 16 & 0xFF) == 0x03) {
+ return getStyleByDynamicId(id);
+ }
return null;
}
@@ -451,7 +457,10 @@
@Override
public final TypedArray obtainStyledAttributes(int[] attrs) {
- return createStyleBasedTypedArray(mRenderResources.getCurrentTheme(), attrs);
+ // No style is specified here, so create the typed array based on the default theme
+ // and the styles already applied to it. A null value of style indicates that the default
+ // theme should be used.
+ return createStyleBasedTypedArray(null, attrs);
}
@Override
@@ -719,11 +728,13 @@
/**
* Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the
- * values found in the given style.
+ * values found in the given style. If no style is specified, the default theme, along with the
+ * styles applied to it are used.
+ *
* @see #obtainStyledAttributes(int, int[])
*/
- private BridgeTypedArray createStyleBasedTypedArray(StyleResourceValue style, int[] attrs)
- throws Resources.NotFoundException {
+ private BridgeTypedArray createStyleBasedTypedArray(@Nullable StyleResourceValue style,
+ int[] attrs) throws Resources.NotFoundException {
List<Pair<String, Boolean>> attributes = searchAttrs(attrs);
@@ -736,8 +747,14 @@
if (attribute != null) {
// look for the value in the given style
- ResourceValue resValue = mRenderResources.findItemInStyle(style,
- attribute.getFirst(), attribute.getSecond());
+ ResourceValue resValue;
+ if (style != null) {
+ resValue = mRenderResources.findItemInStyle(style, attribute.getFirst(),
+ attribute.getSecond());
+ } else {
+ resValue = mRenderResources.findItemInTheme(attribute.getFirst(),
+ attribute.getSecond());
+ }
if (resValue != null) {
// resolve it to make sure there are no references left.
@@ -752,7 +769,6 @@
return ta;
}
-
/**
* The input int[] attrs is a list of attributes. The returns a list of information about
* each attributes. The information is (name, isFramework)
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index bc7e164..3d13269 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -125,6 +125,9 @@
"android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;",
"android.content.res.Resources$Theme#obtainStyledAttributes",
"android.content.res.Resources$Theme#resolveAttribute",
+ "android.content.res.AssetManager#newTheme",
+ "android.content.res.AssetManager#deleteTheme",
+ "android.content.res.AssetManager#applyThemeStyle",
"android.content.res.TypedArray#getValueAt",
"android.graphics.BitmapFactory#finishDecode",
"android.os.Handler#sendMessageAtTime",