OSDN Git Service

LayoutLib: When possible ensure parsers are popped from the stack.
authorXavier Ducrohet <xav@android.com>
Mon, 14 Feb 2011 04:15:50 +0000 (20:15 -0800)
committerXavier Ducrohet <xav@android.com>
Mon, 14 Feb 2011 17:42:19 +0000 (09:42 -0800)
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

tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java

index 15c4f44..734f5ad 100644 (file)
@@ -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*/);
index 38800da..2f54ae6 100644 (file)
@@ -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;
index 771d89a..0c4b0d3 100644 (file)
@@ -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,
index 136b205..fedd789 100644 (file)
@@ -182,8 +182,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
         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<SessionParams> {
         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();
 
index 19392a7..69f46e6 100644 (file)
@@ -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.