From 54d88f7678387a6eb871ec2dccd36af4ff35b1fe Mon Sep 17 00:00:00 2001
From: Deepanshu Gupta <deepanshu@google.com>
Date: Tue, 10 Sep 2013 15:39:41 -0700
Subject: Fix ClassCastException when rendering ListView

Bug: b.android.com/59300
Change-Id: Ia350adb3308daa8170bff755302760790163c811
---
 .../bridge/impl/binding/AdapterHelper.java         | 148 ++++++++++++
 .../layoutlib/bridge/impl/binding/AdapterItem.java |  74 ++++++
 .../layoutlib/bridge/impl/binding/BaseAdapter.java | 247 ---------------------
 .../layoutlib/bridge/impl/binding/FakeAdapter.java |  24 +-
 .../bridge/impl/binding/FakeExpandableAdapter.java |  50 ++++-
 5 files changed, 285 insertions(+), 258 deletions(-)
 create mode 100644 tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
 create mode 100644 tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java
 delete mode 100644 tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java

(limited to 'tools')

diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
new file mode 100644
index 0000000..6c998af
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2013 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 com.android.layoutlib.bridge.impl.binding;
+
+import com.android.ide.common.rendering.api.DataBindingItem;
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.ide.common.rendering.api.IProjectCallback.ViewAttribute;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.RenderAction;
+import com.android.util.Pair;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.Checkable;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * A Helper class to do fake data binding in {@link AdapterView} objects.
+ */
+@SuppressWarnings("deprecation")
+public class AdapterHelper {
+
+    static Pair<View, Boolean> getView(AdapterItem item, AdapterItem parentItem, ViewGroup parent,
+            IProjectCallback callback, ResourceReference adapterRef, boolean skipCallbackParser) {
+        // we don't care about recycling here because we never scroll.
+        DataBindingItem dataBindingItem = item.getDataBindingItem();
+
+        BridgeContext context = RenderAction.getCurrentContext();
+
+        Pair<View, Boolean> pair = context.inflateView(dataBindingItem.getViewReference(),
+                parent, false /*attachToRoot*/, skipCallbackParser);
+
+        View view = pair.getFirst();
+        skipCallbackParser |= pair.getSecond();
+
+        if (view != null) {
+            fillView(context, view, item, parentItem, callback, adapterRef);
+        } else {
+            // create a text view to display an error.
+            TextView tv = new TextView(context);
+            tv.setText("Unable to find layout: " + dataBindingItem.getViewReference().getName());
+            view = tv;
+        }
+
+        return Pair.of(view, skipCallbackParser);
+    }
+
+    private static void fillView(BridgeContext context, View view, AdapterItem item,
+            AdapterItem parentItem, IProjectCallback callback, ResourceReference adapterRef) {
+        if (view instanceof ViewGroup) {
+            ViewGroup group = (ViewGroup) view;
+            final int count = group.getChildCount();
+            for (int i = 0 ; i < count ; i++) {
+                fillView(context, group.getChildAt(i), item, parentItem, callback, adapterRef);
+            }
+        } else {
+            int id = view.getId();
+            if (id != 0) {
+                ResourceReference resolvedRef = context.resolveId(id);
+                if (resolvedRef != null) {
+                    int fullPosition = item.getFullPosition();
+                    int positionPerType = item.getPositionPerType();
+                    int fullParentPosition = parentItem != null ? parentItem.getFullPosition() : 0;
+                    int parentPositionPerType = parentItem != null ?
+                            parentItem.getPositionPerType() : 0;
+
+                    if (view instanceof TextView) {
+                        TextView tv = (TextView) view;
+                        Object value = callback.getAdapterItemValue(
+                                adapterRef, context.getViewKey(view),
+                                item.getDataBindingItem().getViewReference(),
+                                fullPosition, positionPerType,
+                                fullParentPosition, parentPositionPerType,
+                                resolvedRef, ViewAttribute.TEXT, tv.getText().toString());
+                        if (value != null) {
+                            if (value.getClass() != ViewAttribute.TEXT.getAttributeClass()) {
+                                Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
+                                        "Wrong Adapter Item value class for TEXT. Expected String, got %s",
+                                        value.getClass().getName()), null);
+                            } else {
+                                tv.setText((String) value);
+                            }
+                        }
+                    }
+
+                    if (view instanceof Checkable) {
+                        Checkable cb = (Checkable) view;
+
+                        Object value = callback.getAdapterItemValue(
+                                adapterRef, context.getViewKey(view),
+                                item.getDataBindingItem().getViewReference(),
+                                fullPosition, positionPerType,
+                                fullParentPosition, parentPositionPerType,
+                                resolvedRef, ViewAttribute.IS_CHECKED, cb.isChecked());
+                        if (value != null) {
+                            if (value.getClass() != ViewAttribute.IS_CHECKED.getAttributeClass()) {
+                                Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
+                                        "Wrong Adapter Item value class for TEXT. Expected Boolean, got %s",
+                                        value.getClass().getName()), null);
+                            } else {
+                                cb.setChecked((Boolean) value);
+                            }
+                        }
+                    }
+
+                    if (view instanceof ImageView) {
+                        ImageView iv = (ImageView) view;
+
+                        Object value = callback.getAdapterItemValue(
+                                adapterRef, context.getViewKey(view),
+                                item.getDataBindingItem().getViewReference(),
+                                fullPosition, positionPerType,
+                                fullParentPosition, parentPositionPerType,
+                                resolvedRef, ViewAttribute.SRC, iv.getDrawable());
+                        if (value != null) {
+                            if (value.getClass() != ViewAttribute.SRC.getAttributeClass()) {
+                                Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
+                                        "Wrong Adapter Item value class for TEXT. Expected Boolean, got %s",
+                                        value.getClass().getName()), null);
+                            } else {
+                                // FIXME
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java
new file mode 100644
index 0000000..8e28dba
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterItem.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 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 com.android.layoutlib.bridge.impl.binding;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.android.ide.common.rendering.api.DataBindingItem;
+
+/**
+ * This is the items provided by the adapter. They are dynamically generated.
+ */
+final class AdapterItem {
+    private final DataBindingItem mItem;
+    private final int mType;
+    private final int mFullPosition;
+    private final int mPositionPerType;
+    private List<AdapterItem> mChildren;
+
+    protected AdapterItem(DataBindingItem item, int type, int fullPosition,
+            int positionPerType) {
+        mItem = item;
+        mType = type;
+        mFullPosition = fullPosition;
+        mPositionPerType = positionPerType;
+    }
+
+    void addChild(AdapterItem child) {
+        if (mChildren == null) {
+            mChildren = new ArrayList<AdapterItem>();
+        }
+
+        mChildren.add(child);
+    }
+
+    List<AdapterItem> getChildren() {
+        if (mChildren != null) {
+            return mChildren;
+        }
+
+        return Collections.emptyList();
+    }
+
+    int getType() {
+        return mType;
+    }
+
+    int getFullPosition() {
+        return mFullPosition;
+    }
+
+    int getPositionPerType() {
+        return mPositionPerType;
+    }
+
+    DataBindingItem getDataBindingItem() {
+        return mItem;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java
deleted file mode 100644
index e0414fe..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/BaseAdapter.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * 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 com.android.layoutlib.bridge.impl.binding;
-
-import com.android.ide.common.rendering.api.AdapterBinding;
-import com.android.ide.common.rendering.api.DataBindingItem;
-import com.android.ide.common.rendering.api.IProjectCallback;
-import com.android.ide.common.rendering.api.LayoutLog;
-import com.android.ide.common.rendering.api.ResourceReference;
-import com.android.ide.common.rendering.api.IProjectCallback.ViewAttribute;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.android.BridgeContext;
-import com.android.layoutlib.bridge.impl.RenderAction;
-import com.android.util.Pair;
-
-import android.database.DataSetObserver;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.Checkable;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Base adapter to do fake data binding in {@link AdapterView} objects.
- */
-public class BaseAdapter {
-
-    /**
-     * This is the items provided by the adapter. They are dynamically generated.
-     */
-    protected final static class AdapterItem {
-        private final DataBindingItem mItem;
-        private final int mType;
-        private final int mFullPosition;
-        private final int mPositionPerType;
-        private List<AdapterItem> mChildren;
-
-        protected AdapterItem(DataBindingItem item, int type, int fullPosition,
-                int positionPerType) {
-            mItem = item;
-            mType = type;
-            mFullPosition = fullPosition;
-            mPositionPerType = positionPerType;
-        }
-
-        void addChild(AdapterItem child) {
-            if (mChildren == null) {
-                mChildren = new ArrayList<AdapterItem>();
-            }
-
-            mChildren.add(child);
-        }
-
-        List<AdapterItem> getChildren() {
-            if (mChildren != null) {
-                return mChildren;
-            }
-
-            return Collections.emptyList();
-        }
-
-        int getType() {
-            return mType;
-        }
-
-        int getFullPosition() {
-            return mFullPosition;
-        }
-
-        int getPositionPerType() {
-            return mPositionPerType;
-        }
-
-        DataBindingItem getDataBindingItem() {
-            return mItem;
-        }
-    }
-
-    private final AdapterBinding mBinding;
-    private final IProjectCallback mCallback;
-    private final ResourceReference mAdapterRef;
-    private boolean mSkipCallbackParser = false;
-
-    protected final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
-
-    protected BaseAdapter(ResourceReference adapterRef, AdapterBinding binding,
-            IProjectCallback callback) {
-        mAdapterRef = adapterRef;
-        mBinding = binding;
-        mCallback = callback;
-    }
-
-    // ------- Some Adapter method used by all children classes.
-
-    public boolean areAllItemsEnabled() {
-        return true;
-    }
-
-    public boolean hasStableIds() {
-        return true;
-    }
-
-    public boolean isEmpty() {
-        return mItems.size() == 0;
-    }
-
-    public void registerDataSetObserver(DataSetObserver observer) {
-        // pass
-    }
-
-    public void unregisterDataSetObserver(DataSetObserver observer) {
-        // pass
-    }
-
-    // -------
-
-
-    protected AdapterBinding getBinding() {
-        return mBinding;
-    }
-
-    protected View getView(AdapterItem item, AdapterItem parentItem, View convertView,
-            ViewGroup parent) {
-        // we don't care about recycling here because we never scroll.
-        DataBindingItem dataBindingItem = item.getDataBindingItem();
-
-        BridgeContext context = RenderAction.getCurrentContext();
-
-        Pair<View, Boolean> pair = context.inflateView(dataBindingItem.getViewReference(),
-                parent, false /*attachToRoot*/, mSkipCallbackParser);
-
-        View view = pair.getFirst();
-        mSkipCallbackParser |= pair.getSecond();
-
-        if (view != null) {
-            fillView(context, view, item, parentItem);
-        } else {
-            // create a text view to display an error.
-            TextView tv = new TextView(context);
-            tv.setText("Unable to find layout: " + dataBindingItem.getViewReference().getName());
-            view = tv;
-        }
-
-        return view;
-    }
-
-    private void fillView(BridgeContext context, View view, AdapterItem item,
-            AdapterItem parentItem) {
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-            final int count = group.getChildCount();
-            for (int i = 0 ; i < count ; i++) {
-                fillView(context, group.getChildAt(i), item, parentItem);
-            }
-        } else {
-            int id = view.getId();
-            if (id != 0) {
-                ResourceReference resolvedRef = context.resolveId(id);
-                if (resolvedRef != null) {
-                    int fullPosition = item.getFullPosition();
-                    int positionPerType = item.getPositionPerType();
-                    int fullParentPosition = parentItem != null ? parentItem.getFullPosition() : 0;
-                    int parentPositionPerType = parentItem != null ?
-                            parentItem.getPositionPerType() : 0;
-
-                    if (view instanceof TextView) {
-                        TextView tv = (TextView) view;
-                        Object value = mCallback.getAdapterItemValue(
-                                mAdapterRef, context.getViewKey(view),
-                                item.getDataBindingItem().getViewReference(),
-                                fullPosition, positionPerType,
-                                fullParentPosition, parentPositionPerType,
-                                resolvedRef, ViewAttribute.TEXT, tv.getText().toString());
-                        if (value != null) {
-                            if (value.getClass() != ViewAttribute.TEXT.getAttributeClass()) {
-                                Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
-                                        "Wrong Adapter Item value class for TEXT. Expected String, got %s",
-                                        value.getClass().getName()), null);
-                            } else {
-                                tv.setText((String) value);
-                            }
-                        }
-                    }
-
-                    if (view instanceof Checkable) {
-                        Checkable cb = (Checkable) view;
-
-                        Object value = mCallback.getAdapterItemValue(
-                                mAdapterRef, context.getViewKey(view),
-                                item.getDataBindingItem().getViewReference(),
-                                fullPosition, positionPerType,
-                                fullParentPosition, parentPositionPerType,
-                                resolvedRef, ViewAttribute.IS_CHECKED, cb.isChecked());
-                        if (value != null) {
-                            if (value.getClass() != ViewAttribute.IS_CHECKED.getAttributeClass()) {
-                                Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
-                                        "Wrong Adapter Item value class for TEXT. Expected Boolean, got %s",
-                                        value.getClass().getName()), null);
-                            } else {
-                                cb.setChecked((Boolean) value);
-                            }
-                        }
-                    }
-
-                    if (view instanceof ImageView) {
-                        ImageView iv = (ImageView) view;
-
-                        Object value = mCallback.getAdapterItemValue(
-                                mAdapterRef, context.getViewKey(view),
-                                item.getDataBindingItem().getViewReference(),
-                                fullPosition, positionPerType,
-                                fullParentPosition, parentPositionPerType,
-                                resolvedRef, ViewAttribute.SRC, iv.getDrawable());
-                        if (value != null) {
-                            if (value.getClass() != ViewAttribute.SRC.getAttributeClass()) {
-                                Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
-                                        "Wrong Adapter Item value class for TEXT. Expected Boolean, got %s",
-                                        value.getClass().getName()), null);
-                            } else {
-                                // FIXME
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
index 22570b9..9a13f5a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
@@ -20,10 +20,12 @@ import com.android.ide.common.rendering.api.AdapterBinding;
 import com.android.ide.common.rendering.api.DataBindingItem;
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.util.Pair;
 
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
+import android.widget.BaseAdapter;
 import android.widget.ListAdapter;
 import android.widget.SpinnerAdapter;
 
@@ -35,17 +37,23 @@ import java.util.List;
  * and {@link SpinnerAdapter}.
  *
  */
-public class FakeAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
+@SuppressWarnings("deprecation")
+public class FakeAdapter extends BaseAdapter {
 
     // don't use a set because the order is important.
     private final List<ResourceReference> mTypes = new ArrayList<ResourceReference>();
+    private final IProjectCallback mCallback;
+    private final ResourceReference mAdapterRef;
+    private final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
+    private boolean mSkipCallbackParser = false;
 
     public FakeAdapter(ResourceReference adapterRef, AdapterBinding binding,
             IProjectCallback callback) {
-        super(adapterRef, binding, callback);
+        mAdapterRef = adapterRef;
+        mCallback = callback;
 
-        final int repeatCount = getBinding().getRepeatCount();
-        final int itemCount = getBinding().getItemCount();
+        final int repeatCount = binding.getRepeatCount();
+        final int itemCount = binding.getItemCount();
 
         // Need an array to count for each type.
         // This is likely too big, but is the max it can be.
@@ -54,7 +62,7 @@ public class FakeAdapter extends BaseAdapter implements ListAdapter, SpinnerAdap
         // We put several repeating sets.
         for (int r = 0 ; r < repeatCount ; r++) {
             // loop on the type of list items, and add however many for each type.
-            for (DataBindingItem dataBindingItem : getBinding()) {
+            for (DataBindingItem dataBindingItem : binding) {
                 ResourceReference viewRef = dataBindingItem.getViewReference();
                 int typeIndex = mTypes.indexOf(viewRef);
                 if (typeIndex == -1) {
@@ -103,7 +111,11 @@ public class FakeAdapter extends BaseAdapter implements ListAdapter, SpinnerAdap
     public View getView(int position, View convertView, ViewGroup parent) {
         // we don't care about recycling here because we never scroll.
         AdapterItem item = mItems.get(position);
-        return getView(item, null /*parentGroup*/, convertView, parent);
+        Pair<View, Boolean> pair = AdapterHelper.getView(item, null /*parentGroup*/, parent,
+                mCallback, mAdapterRef, mSkipCallbackParser);
+        mSkipCallbackParser = pair.getSecond();
+        return pair.getFirst();
+
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
index 199e040..e539579 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
@@ -20,7 +20,9 @@ import com.android.ide.common.rendering.api.AdapterBinding;
 import com.android.ide.common.rendering.api.DataBindingItem;
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.util.Pair;
 
+import android.database.DataSetObserver;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ExpandableListAdapter;
@@ -29,8 +31,14 @@ import android.widget.HeterogeneousExpandableList;
 import java.util.ArrayList;
 import java.util.List;
 
-public class FakeExpandableAdapter extends BaseAdapter implements ExpandableListAdapter,
-        HeterogeneousExpandableList {
+@SuppressWarnings("deprecation")
+public class FakeExpandableAdapter implements ExpandableListAdapter, HeterogeneousExpandableList {
+
+    private final IProjectCallback mCallback;
+    private final ResourceReference mAdapterRef;
+    private boolean mSkipCallbackParser = false;
+
+    protected final List<AdapterItem> mItems = new ArrayList<AdapterItem>();
 
     // don't use a set because the order is important.
     private final List<ResourceReference> mGroupTypes = new ArrayList<ResourceReference>();
@@ -38,7 +46,8 @@ public class FakeExpandableAdapter extends BaseAdapter implements ExpandableList
 
     public FakeExpandableAdapter(ResourceReference adapterRef, AdapterBinding binding,
             IProjectCallback callback) {
-        super(adapterRef, binding, callback);
+        mAdapterRef = adapterRef;
+        mCallback = callback;
 
         createItems(binding, binding.getItemCount(), binding.getRepeatCount(), mGroupTypes, 1);
     }
@@ -125,7 +134,10 @@ public class FakeExpandableAdapter extends BaseAdapter implements ExpandableList
             ViewGroup parent) {
         // we don't care about recycling here because we never scroll.
         AdapterItem item = mItems.get(groupPosition);
-        return getView(item, null /*parentItem*/, convertView, parent);
+        Pair<View, Boolean> pair = AdapterHelper.getView(item, null /*parentItem*/, parent,
+                mCallback, mAdapterRef, mSkipCallbackParser);
+        mSkipCallbackParser = pair.getSecond();
+        return pair.getFirst();
     }
 
     @Override
@@ -134,7 +146,10 @@ public class FakeExpandableAdapter extends BaseAdapter implements ExpandableList
         // we don't care about recycling here because we never scroll.
         AdapterItem parentItem = mItems.get(groupPosition);
         AdapterItem item = getChildItem(groupPosition, childPosition);
-        return getView(item, parentItem, convertView, parent);
+        Pair<View, Boolean> pair = AdapterHelper.getView(item, parentItem, parent, mCallback,
+                mAdapterRef, mSkipCallbackParser);
+        mSkipCallbackParser = pair.getSecond();
+        return pair.getFirst();
     }
 
     @Override
@@ -172,6 +187,31 @@ public class FakeExpandableAdapter extends BaseAdapter implements ExpandableList
         // pass
     }
 
+    @Override
+    public void registerDataSetObserver(DataSetObserver observer) {
+        // pass
+    }
+
+    @Override
+    public void unregisterDataSetObserver(DataSetObserver observer) {
+        // pass
+    }
+
+    @Override
+    public boolean hasStableIds() {
+        return true;
+    }
+
+    @Override
+    public boolean areAllItemsEnabled() {
+        return true;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return mItems.isEmpty();
+    }
+
     // ---- HeterogeneousExpandableList
 
     @Override
-- 
cgit v1.1