am 54d88f76: Fix ClassCastException when rendering ListView

* commit '54d88f7678387a6eb871ec2dccd36af4ff35b1fe':
  Fix ClassCastException when rendering ListView
This commit is contained in:
Deepanshu Gupta
2013-09-13 14:55:06 -07:00
committed by Android Git Automerger
4 changed files with 156 additions and 129 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2011 The Android Open Source Project * Copyright (C) 2013 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,7 +16,6 @@
package com.android.layoutlib.bridge.impl.binding; 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.DataBindingItem;
import com.android.ide.common.rendering.api.IProjectCallback; import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.rendering.api.LayoutLog;
@ -27,7 +26,6 @@ import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.impl.RenderAction; import com.android.layoutlib.bridge.impl.RenderAction;
import com.android.util.Pair; import com.android.util.Pair;
import android.database.DataSetObserver;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
@ -35,124 +33,27 @@ import android.widget.Checkable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; 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. * A Helper class to do fake data binding in {@link AdapterView} objects.
*/ */
public class BaseAdapter { @SuppressWarnings("deprecation")
public class AdapterHelper {
/** static Pair<View, Boolean> getView(AdapterItem item, AdapterItem parentItem, ViewGroup parent,
* This is the items provided by the adapter. They are dynamically generated. IProjectCallback callback, ResourceReference adapterRef, boolean skipCallbackParser) {
*/
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. // we don't care about recycling here because we never scroll.
DataBindingItem dataBindingItem = item.getDataBindingItem(); DataBindingItem dataBindingItem = item.getDataBindingItem();
BridgeContext context = RenderAction.getCurrentContext(); BridgeContext context = RenderAction.getCurrentContext();
Pair<View, Boolean> pair = context.inflateView(dataBindingItem.getViewReference(), Pair<View, Boolean> pair = context.inflateView(dataBindingItem.getViewReference(),
parent, false /*attachToRoot*/, mSkipCallbackParser); parent, false /*attachToRoot*/, skipCallbackParser);
View view = pair.getFirst(); View view = pair.getFirst();
mSkipCallbackParser |= pair.getSecond(); skipCallbackParser |= pair.getSecond();
if (view != null) { if (view != null) {
fillView(context, view, item, parentItem); fillView(context, view, item, parentItem, callback, adapterRef);
} else { } else {
// create a text view to display an error. // create a text view to display an error.
TextView tv = new TextView(context); TextView tv = new TextView(context);
@ -160,16 +61,16 @@ public class BaseAdapter {
view = tv; view = tv;
} }
return view; return Pair.of(view, skipCallbackParser);
} }
private void fillView(BridgeContext context, View view, AdapterItem item, private static void fillView(BridgeContext context, View view, AdapterItem item,
AdapterItem parentItem) { AdapterItem parentItem, IProjectCallback callback, ResourceReference adapterRef) {
if (view instanceof ViewGroup) { if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view; ViewGroup group = (ViewGroup) view;
final int count = group.getChildCount(); final int count = group.getChildCount();
for (int i = 0 ; i < count ; i++) { for (int i = 0 ; i < count ; i++) {
fillView(context, group.getChildAt(i), item, parentItem); fillView(context, group.getChildAt(i), item, parentItem, callback, adapterRef);
} }
} else { } else {
int id = view.getId(); int id = view.getId();
@ -184,8 +85,8 @@ public class BaseAdapter {
if (view instanceof TextView) { if (view instanceof TextView) {
TextView tv = (TextView) view; TextView tv = (TextView) view;
Object value = mCallback.getAdapterItemValue( Object value = callback.getAdapterItemValue(
mAdapterRef, context.getViewKey(view), adapterRef, context.getViewKey(view),
item.getDataBindingItem().getViewReference(), item.getDataBindingItem().getViewReference(),
fullPosition, positionPerType, fullPosition, positionPerType,
fullParentPosition, parentPositionPerType, fullParentPosition, parentPositionPerType,
@ -204,8 +105,8 @@ public class BaseAdapter {
if (view instanceof Checkable) { if (view instanceof Checkable) {
Checkable cb = (Checkable) view; Checkable cb = (Checkable) view;
Object value = mCallback.getAdapterItemValue( Object value = callback.getAdapterItemValue(
mAdapterRef, context.getViewKey(view), adapterRef, context.getViewKey(view),
item.getDataBindingItem().getViewReference(), item.getDataBindingItem().getViewReference(),
fullPosition, positionPerType, fullPosition, positionPerType,
fullParentPosition, parentPositionPerType, fullParentPosition, parentPositionPerType,
@ -224,8 +125,8 @@ public class BaseAdapter {
if (view instanceof ImageView) { if (view instanceof ImageView) {
ImageView iv = (ImageView) view; ImageView iv = (ImageView) view;
Object value = mCallback.getAdapterItemValue( Object value = callback.getAdapterItemValue(
mAdapterRef, context.getViewKey(view), adapterRef, context.getViewKey(view),
item.getDataBindingItem().getViewReference(), item.getDataBindingItem().getViewReference(),
fullPosition, positionPerType, fullPosition, positionPerType,
fullParentPosition, parentPositionPerType, fullParentPosition, parentPositionPerType,

View File

@ -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;
}
}

View File

@ -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.DataBindingItem;
import com.android.ide.common.rendering.api.IProjectCallback; import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.ResourceReference; import com.android.ide.common.rendering.api.ResourceReference;
import com.android.util.Pair;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListAdapter; import android.widget.ListAdapter;
import android.widget.SpinnerAdapter; import android.widget.SpinnerAdapter;
@ -35,17 +37,23 @@ import java.util.List;
* and {@link SpinnerAdapter}. * 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. // don't use a set because the order is important.
private final List<ResourceReference> mTypes = new ArrayList<ResourceReference>(); 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, public FakeAdapter(ResourceReference adapterRef, AdapterBinding binding,
IProjectCallback callback) { IProjectCallback callback) {
super(adapterRef, binding, callback); mAdapterRef = adapterRef;
mCallback = callback;
final int repeatCount = getBinding().getRepeatCount(); final int repeatCount = binding.getRepeatCount();
final int itemCount = getBinding().getItemCount(); final int itemCount = binding.getItemCount();
// Need an array to count for each type. // Need an array to count for each type.
// This is likely too big, but is the max it can be. // 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. // We put several repeating sets.
for (int r = 0 ; r < repeatCount ; r++) { for (int r = 0 ; r < repeatCount ; r++) {
// loop on the type of list items, and add however many for each type. // 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(); ResourceReference viewRef = dataBindingItem.getViewReference();
int typeIndex = mTypes.indexOf(viewRef); int typeIndex = mTypes.indexOf(viewRef);
if (typeIndex == -1) { if (typeIndex == -1) {
@ -103,7 +111,11 @@ public class FakeAdapter extends BaseAdapter implements ListAdapter, SpinnerAdap
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
// we don't care about recycling here because we never scroll. // we don't care about recycling here because we never scroll.
AdapterItem item = mItems.get(position); 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 @Override

View File

@ -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.DataBindingItem;
import com.android.ide.common.rendering.api.IProjectCallback; import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.ResourceReference; import com.android.ide.common.rendering.api.ResourceReference;
import com.android.util.Pair;
import android.database.DataSetObserver;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ExpandableListAdapter; import android.widget.ExpandableListAdapter;
@ -29,8 +31,14 @@ import android.widget.HeterogeneousExpandableList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class FakeExpandableAdapter extends BaseAdapter implements ExpandableListAdapter, @SuppressWarnings("deprecation")
HeterogeneousExpandableList { 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. // don't use a set because the order is important.
private final List<ResourceReference> mGroupTypes = new ArrayList<ResourceReference>(); 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, public FakeExpandableAdapter(ResourceReference adapterRef, AdapterBinding binding,
IProjectCallback callback) { IProjectCallback callback) {
super(adapterRef, binding, callback); mAdapterRef = adapterRef;
mCallback = callback;
createItems(binding, binding.getItemCount(), binding.getRepeatCount(), mGroupTypes, 1); createItems(binding, binding.getItemCount(), binding.getRepeatCount(), mGroupTypes, 1);
} }
@ -125,7 +134,10 @@ public class FakeExpandableAdapter extends BaseAdapter implements ExpandableList
ViewGroup parent) { ViewGroup parent) {
// we don't care about recycling here because we never scroll. // we don't care about recycling here because we never scroll.
AdapterItem item = mItems.get(groupPosition); 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 @Override
@ -134,7 +146,10 @@ public class FakeExpandableAdapter extends BaseAdapter implements ExpandableList
// we don't care about recycling here because we never scroll. // we don't care about recycling here because we never scroll.
AdapterItem parentItem = mItems.get(groupPosition); AdapterItem parentItem = mItems.get(groupPosition);
AdapterItem item = getChildItem(groupPosition, childPosition); 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 @Override
@ -172,6 +187,31 @@ public class FakeExpandableAdapter extends BaseAdapter implements ExpandableList
// pass // 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 // ---- HeterogeneousExpandableList
@Override @Override