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:
@@ -1456,6 +1456,11 @@ public class Resources {
|
||||
|
||||
private final AssetManager mAssets;
|
||||
private final int mTheme;
|
||||
|
||||
// Needed by layoutlib.
|
||||
/*package*/ int getNativeTheme() {
|
||||
return mTheme;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user