Fix theme/style resolution in Layoutlib [DO NOT MERGE]

Cherry picked from klp-dev from
Change-Id: If1e7187645f0b0388f7b97d742395efd228b347a which was
cherrypicked from master with the following

Change-Id: Icfb91e566666408802dadc0e2070991151b16b9d
(cherry picked from commit f1e7187645)
This commit is contained in:
Deepanshu Gupta
2014-03-11 18:02:44 -07:00
parent b85d30a2c8
commit 3c00b28bf6
5 changed files with 155 additions and 14 deletions

View File

@@ -1456,6 +1456,11 @@ public class Resources {
private final AssetManager mAssets;
private final int mTheme;
// Needed by layoutlib.
/*package*/ int getNativeTheme() {
return mTheme;
}
}
/**

View File

@@ -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;
}
}

View File

@@ -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.AttributeSet;
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 @@ import android.util.TypedValue;
*/
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 @@ public class Resources_Theme_Delegate {
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 @@ public class Resources_Theme_Delegate {
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());
}
}
}

View File

@@ -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 @@ public final class BridgeContext extends Context {
// 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;
@@ -315,6 +316,11 @@ public final class BridgeContext extends Context {
}
}
// 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;
}
@@ -455,7 +461,10 @@ public final class BridgeContext extends Context {
@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
@@ -723,11 +732,13 @@ public final class BridgeContext extends Context {
/**
* 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);
@@ -740,8 +751,14 @@ public final class BridgeContext extends Context {
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.
@@ -756,7 +773,6 @@ public final class BridgeContext extends Context {
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)

View File

@@ -125,6 +125,9 @@ public final class CreateInfo implements ICreateInfo {
"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",