am 5b9936f6: Merge "LayoutLib: Use special view cookie for include-merge case." into honeycomb

* commit '5b9936f651a06b4b3c988ee330d12355041eeb00':
  LayoutLib: Use special view cookie for include-merge case.
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
new file mode 100644
index 0000000..3946a2f
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2011 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.view;
+
+import com.android.layoutlib.bridge.android.BridgeInflater;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.util.AttributeSet;
+
+import java.io.IOException;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link LayoutInflater}
+ *
+ * Through the layoutlib_create tool, the original  methods of LayoutInflater have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class LayoutInflater_Delegate {
+
+    /**
+     * Recursive method used to descend down the xml hierarchy and instantiate
+     * views, instantiate their children, and then call onFinishInflate().
+     */
+    /*package*/ static void rInflate(LayoutInflater thisInflater,
+            XmlPullParser parser, View parent, final AttributeSet attrs,
+            boolean finishInflate) throws XmlPullParserException, IOException {
+
+        if (finishInflate == false) {
+            // this is a merge rInflate!
+            if (thisInflater instanceof BridgeInflater) {
+                ((BridgeInflater) thisInflater).setIsInMerge(true);
+            }
+        }
+
+        // ---- START DEFAULT IMPLEMENTATION.
+
+        final int depth = parser.getDepth();
+        int type;
+
+        while (((type = parser.next()) != XmlPullParser.END_TAG ||
+                parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            final String name = parser.getName();
+
+            if (LayoutInflater.TAG_REQUEST_FOCUS.equals(name)) {
+                thisInflater.parseRequestFocus(parser, parent);
+            } else if (LayoutInflater.TAG_INCLUDE.equals(name)) {
+                if (parser.getDepth() == 0) {
+                    throw new InflateException("<include /> cannot be the root element");
+                }
+                thisInflater.parseInclude(parser, parent, attrs);
+            } else if (LayoutInflater.TAG_MERGE.equals(name)) {
+                throw new InflateException("<merge /> must be the root element");
+            } else {
+                final View view = thisInflater.createViewFromTag(parent, name, attrs);
+                final ViewGroup viewGroup = (ViewGroup) parent;
+                final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
+                thisInflater.rInflate(parser, view, attrs, true);
+                viewGroup.addView(view, params);
+            }
+        }
+
+        if (finishInflate) parent.onFinishInflate();
+
+        // ---- END DEFAULT IMPLEMENTATION.
+
+        if (finishInflate == false) {
+            // this is a merge rInflate!
+            if (thisInflater instanceof BridgeInflater) {
+                ((BridgeInflater) thisInflater).setIsInMerge(false);
+            }
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
index 7fa6fdf..465bf1d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
@@ -18,6 +18,7 @@
 
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.MergeCookie;
 import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.layoutlib.bridge.Bridge;
@@ -41,6 +42,7 @@
 public final class BridgeInflater extends LayoutInflater {
 
     private final IProjectCallback mProjectCallback;
+    private boolean mIsInMerge = false;
 
     /**
      * List of class prefixes which are tried first by default.
@@ -211,8 +213,6 @@
         return null;
     }
 
-
-
     private void setupViewInContext(View view, AttributeSet attrs) {
         if (getContext() instanceof BridgeContext) {
             BridgeContext bc = (BridgeContext) getContext();
@@ -222,9 +222,11 @@
                 // get the view key
                 Object viewKey = parser.getViewCookie();
 
-                // if there's no view key and the depth is 1 (ie this is the first tag),
+                // if there's no view key and the depth is 1 (ie this is the first tag), or 2
+                // (this is first item in included merge layout)
                 // look for a previous parser in the context, and check if this one has a viewkey.
-                if (viewKey == null && parser.getDepth() == 1) {
+                int testDepth = mIsInMerge ? 2 : 1;
+                if (viewKey == null && parser.getDepth() == testDepth) {
                     BridgeXmlBlockParser previousParser = bc.getPreviousParser();
                     if (previousParser != null) {
                         viewKey = previousParser.getViewCookie();
@@ -232,12 +234,21 @@
                 }
 
                 if (viewKey != null) {
+                    if (testDepth == 2) {
+                        // include-merge case
+                        viewKey = new MergeCookie(viewKey);
+                    }
+
                     bc.addViewKey(view, viewKey);
                 }
             }
         }
     }
 
+    public void setIsInMerge(boolean isInMerge) {
+        mIsInMerge = isInMerge;
+    }
+
     @Override
     public LayoutInflater cloneInContext(Context newContext) {
         return new BridgeInflater(this, newContext);
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestDelegates.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestDelegates.java
index 23b7e94..0ff1925 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestDelegates.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestDelegates.java
@@ -104,7 +104,12 @@
                         parameters);
 
                 // check that the method is static
-                assertTrue((delegateMethod.getModifiers() & Modifier.STATIC) == Modifier.STATIC);
+                assertTrue(
+                        String.format(
+                                "Delegate method %1$s for class %2$s is not static",
+                                delegateMethod.getName(),
+                                originalClass.getName()),
+                        (delegateMethod.getModifiers() & Modifier.STATIC) == Modifier.STATIC);
             } catch (NoSuchMethodException e) {
                 // compute a full class name that's long but not too long.
                 StringBuilder sb = new StringBuilder(originalMethod.getName() + "(");
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 4198006..e3c5b4b 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
@@ -96,8 +96,9 @@
     private final static String[] DELEGATE_METHODS = new String[] {
         "android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;",
         "android.os.Handler#sendMessageAtTime",
+        "android.view.LayoutInflater#rInflate",
         "android.view.View#isInEditMode",
-        "com.android.internal.util.XmlUtils#convertValueToInt"
+        "com.android.internal.util.XmlUtils#convertValueToInt",
         // TODO: comment out once DelegateClass is working
         // "android.content.res.Resources$Theme#obtainStyledAttributes",
     };