From 02d2b5a4031c80bfe1012ce2f4f7b3695762abd9 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet Date: Sun, 13 Feb 2011 20:15:50 -0800 Subject: [PATCH] LayoutLib: When possible ensure parsers are popped from the stack. Some parser consumers (seems to be mostly resource inflation) don't use the pull parser up to the END_DOCUMENT tag, making the parser not pop itself from the parser stack automatically. This is likely due to the XML resources being very shallow (1-2 levels max), and the inflater just reading the content that it expects instead of parsing till the document is done. This ensures that *some* parsers are pop'ed from the stack when used. Some other parsers we don't really control and hope the user will parse till END_DOCUMENT. Change-Id: Ie1f5762983fed2b2ae97b896218ae12b493e7ad9 --- .../layoutlib/bridge/android/BridgeTypedArray.java | 15 +++++++++------ .../bridge/android/BridgeXmlBlockParser.java | 14 ++++++++++++-- .../android/layoutlib/bridge/bars/CustomBar.java | 8 ++++++-- .../layoutlib/bridge/impl/RenderSessionImpl.java | 9 +++++---- .../layoutlib/bridge/impl/ResourceHelper.java | 21 ++++++++++++++------- 5 files changed, 46 insertions(+), 21 deletions(-) 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 15c4f4422a3c..734f5addccb1 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 @@ -294,7 +294,8 @@ public final class BridgeTypedArray extends TypedArray { return null; } - String value = mResourceData[index].getValue(); + ResourceValue resValue = mResourceData[index]; + String value = resValue.getValue(); if (value == null) { return null; @@ -308,11 +309,13 @@ public final class BridgeTypedArray extends TypedArray { parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); parser.setInput(new FileReader(f)); - ColorStateList colorStateList = ColorStateList.createFromXml( - mContext.getResources(), - // FIXME: we need to know if this resource is platform or not - new BridgeXmlBlockParser(parser, mContext, false)); - return colorStateList; + BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser( + parser, mContext, resValue.isFramework()); + try { + return ColorStateList.createFromXml(mContext.getResources(), blockParser); + } finally { + blockParser.ensurePopped(); + } } catch (XmlPullParserException e) { Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Failed to configure parser for " + value, e, null /*data*/); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java index 38800da132e9..2f54ae6eb03c 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java @@ -45,6 +45,8 @@ public class BridgeXmlBlockParser implements XmlResourceParser { private boolean mStarted = false; private int mEventType = START_DOCUMENT; + private boolean mPopped = true; // default to true in case it's not pushed. + /** * Builds a {@link BridgeXmlBlockParser}. * @param parser The XmlPullParser to get the content from. @@ -59,6 +61,7 @@ public class BridgeXmlBlockParser implements XmlResourceParser { if (mContext != null) { mContext.pushParser(this); + mPopped = false; } } @@ -82,6 +85,13 @@ public class BridgeXmlBlockParser implements XmlResourceParser { return null; } + public void ensurePopped() { + if (mContext != null && mPopped == false) { + mContext.popParser(); + mPopped = true; + } + } + // ------- XmlResourceParser implementation public void setFeature(String name, boolean state) @@ -249,9 +259,9 @@ public class BridgeXmlBlockParser implements XmlResourceParser { } int ev = mParser.next(); - if (ev == END_TAG && mParser.getDepth() == 1 && mContext != null) { + if (ev == END_TAG && mParser.getDepth() == 1) { // done with parser remove it from the context stack. - mContext.popParser(); + ensurePopped(); } mEventType = ev; return ev; diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java index 771d89add260..0c4b0d3bbda7 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java @@ -76,9 +76,13 @@ abstract class CustomBar extends LinearLayout { "UTF8"); BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser( - parser, (BridgeContext) context, false); + parser, (BridgeContext) context, false /*platformFile*/); - inflater.inflate(bridgeParser, this, true); + try { + inflater.inflate(bridgeParser, this, true); + } finally { + bridgeParser.ensurePopped(); + } } private InputStream getIcon(String iconName, Density[] densityInOut, String[] pathOut, 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 136b20566c7f..fedd789fe258 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 @@ -182,8 +182,8 @@ public class RenderSessionImpl extends RenderAction { context.setBridgeInflater(mInflater); mInflater.setFactory2(context); - mBlockParser = new BridgeXmlBlockParser(params.getLayoutDescription(), - context, false /* platformResourceFlag */); + mBlockParser = new BridgeXmlBlockParser( + params.getLayoutDescription(), context, false /* platformResourceFlag */); return SUCCESS.createResult(); } @@ -562,13 +562,14 @@ public class RenderSessionImpl extends RenderAction { BridgeContext context = getContext(); // create a block parser for the XML - BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, context, - false /* platformResourceFlag */); + BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser( + childXml, context, false /* platformResourceFlag */); // inflate the child without adding it to the root since we want to control where it'll // get added. We do pass the parentView however to ensure that the layoutParams will // be created correctly. final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/); + blockParser.ensurePopped(); invalidateRenderingSize(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java index 19392a7d3634..69f46e6e335e 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java @@ -126,8 +126,13 @@ public final class ResourceHelper { parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); parser.setInput(new FileReader(f)); - return ColorStateList.createFromXml(context.getResources(), - new BridgeXmlBlockParser(parser, context, resValue.isFramework())); + BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser( + parser, context, resValue.isFramework()); + try { + return ColorStateList.createFromXml(context.getResources(), blockParser); + } finally { + blockParser.ensurePopped(); + } } catch (XmlPullParserException e) { Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Failed to configure parser for " + value, e, null /*data*/); @@ -164,8 +169,6 @@ public final class ResourceHelper { * @param context the current context */ public static Drawable getDrawable(ResourceValue value, BridgeContext context) { - Drawable d = null; - String stringValue = value.getValue(); if (RenderResources.REFERENCE_NULL.equals(stringValue)) { return null; @@ -205,9 +208,13 @@ public final class ResourceHelper { parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); parser.setInput(new FileReader(f)); - d = Drawable.createFromXml(context.getResources(), - new BridgeXmlBlockParser(parser, context, value.isFramework())); - return d; + BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser( + parser, context, value.isFramework()); + try { + return Drawable.createFromXml(context.getResources(), blockParser); + } finally { + blockParser.ensurePopped(); + } } catch (Exception e) { // this is an error and not warning since the file existence is checked before // attempting to parse it. -- 2.11.0