Merge "Merge 2fae858d from Honeycomb-mr1. do not merge." into gingerbread

This commit is contained in:
Xavier Ducrohet
2011-05-20 13:56:42 -07:00
committed by Android (Google) Code Review
11 changed files with 799 additions and 51 deletions

View File

@ -25,6 +25,7 @@ import com.android.ide.common.rendering.api.LayoutLog;
import com.android.ide.common.rendering.api.RenderSession;
import com.android.ide.common.rendering.api.Result;
import com.android.ide.common.rendering.api.SessionParams;
import com.android.ide.common.rendering.api.Result.Status;
import com.android.layoutlib.bridge.android.BridgeAssetManager;
import com.android.layoutlib.bridge.impl.FontLoader;
import com.android.layoutlib.bridge.impl.RenderDrawable;
@ -39,6 +40,9 @@ import android.graphics.Bitmap;
import android.graphics.Typeface;
import android.graphics.Typeface_Delegate;
import android.os.Looper;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import java.io.File;
import java.lang.ref.SoftReference;
@ -194,7 +198,8 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
Capability.RENDER,
//Capability.LAYOUT_ONLY, // disable to run on ADT 10.0 which doesn't include this.
Capability.EMBEDDED_LAYOUT,
Capability.VIEW_MANIPULATION);
Capability.VIEW_MANIPULATION,
Capability.ADAPTER_BINDING);
BridgeAssetManager.initSystem();
@ -367,6 +372,40 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
}
}
@Override
public Result getViewParent(Object viewObject) {
if (viewObject instanceof View) {
return Status.SUCCESS.createResult(((View)viewObject).getParent());
}
throw new IllegalArgumentException("viewObject is not a View");
}
@Override
public Result getViewIndex(Object viewObject) {
if (viewObject instanceof View) {
View view = (View) viewObject;
ViewParent parentView = view.getParent();
if (parentView instanceof ViewGroup) {
Status.SUCCESS.createResult(((ViewGroup) parentView).indexOfChild(view));
}
return Status.SUCCESS.createResult();
}
throw new IllegalArgumentException("viewObject is not a View");
}
@Override
public int getViewBaseline(Object viewObject) {
if (viewObject instanceof View) {
return ((View) viewObject).getBaseline();
}
throw new IllegalArgumentException("viewObject is not a View");
}
/**
* Returns the lock for the bridge
*/

View File

@ -22,12 +22,10 @@ import com.android.ide.common.rendering.api.RenderParams;
import com.android.ide.common.rendering.api.RenderSession;
import com.android.ide.common.rendering.api.Result;
import com.android.ide.common.rendering.api.ViewInfo;
import com.android.ide.common.rendering.api.Result.Status;
import com.android.layoutlib.bridge.impl.RenderSessionImpl;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import java.awt.image.BufferedImage;
import java.util.List;
@ -82,31 +80,6 @@ public class BridgeRenderSession extends RenderSession {
return super.setProperty(objectView, propertyName, propertyValue);
}
@Override
public Result getViewParent(Object viewObject) {
if (viewObject instanceof View) {
return Status.SUCCESS.createResult(((View)viewObject).getParent());
}
throw new IllegalArgumentException("viewObject is not a View");
}
@Override
public Result getViewIndex(Object viewObject) {
if (viewObject instanceof View) {
View view = (View) viewObject;
ViewParent parentView = view.getParent();
if (parentView instanceof ViewGroup) {
Status.SUCCESS.createResult(((ViewGroup) parentView).indexOfChild(view));
}
return Status.SUCCESS.createResult();
}
throw new IllegalArgumentException("viewObject is not a View");
}
@Override
public Result render(long timeout) {
try {

View File

@ -16,9 +16,11 @@
package com.android.layoutlib.bridge.android;
import com.android.ide.common.rendering.api.ILayoutPullParser;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.StyleResourceValue;
import com.android.layoutlib.bridge.Bridge;
@ -27,6 +29,10 @@ import com.android.layoutlib.bridge.impl.Stack;
import com.android.resources.ResourceType;
import com.android.util.Pair;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@ -57,11 +63,13 @@ import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
@ -265,6 +273,107 @@ public final class BridgeContext extends Activity {
}
public ResourceReference resolveId(int id) {
// first get the String related to this id in the framework
Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
if (resourceInfo != null) {
return new ResourceReference(resourceInfo.getSecond(), true);
}
// didn't find a match in the framework? look in the project.
if (mProjectCallback != null) {
resourceInfo = mProjectCallback.resolveResourceId(id);
if (resourceInfo != null) {
return new ResourceReference(resourceInfo.getSecond(), false);
}
}
return null;
}
public Pair<View, Boolean> inflateView(ResourceReference resource, ViewGroup parent,
boolean attachToRoot, boolean skipCallbackParser) {
String layoutName = resource.getName();
boolean isPlatformLayout = resource.isFramework();
if (isPlatformLayout == false && skipCallbackParser == false) {
// check if the project callback can provide us with a custom parser.
ILayoutPullParser parser = mProjectCallback.getParser(layoutName);
if (parser != null) {
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser,
this, resource.isFramework());
try {
pushParser(blockParser);
return Pair.of(
mBridgeInflater.inflate(blockParser, parent, attachToRoot),
true);
} finally {
popParser();
}
}
}
ResourceValue resValue;
if (resource instanceof ResourceValue) {
resValue = (ResourceValue) resource;
} else {
if (isPlatformLayout) {
resValue = mRenderResources.getFrameworkResource(ResourceType.LAYOUT,
resource.getName());
} else {
resValue = mRenderResources.getProjectResource(ResourceType.LAYOUT,
resource.getName());
}
}
if (resValue != null) {
File xml = new File(resValue.getValue());
if (xml.isFile()) {
// we need to create a pull parser around the layout XML file, and then
// give that to our XmlBlockParser
try {
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new FileReader(xml));
// set the resource ref to have correct view cookies
mBridgeInflater.setResourceReference(resource);
BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser,
this, resource.isFramework());
try {
pushParser(blockParser);
return Pair.of(
mBridgeInflater.inflate(blockParser, parent, attachToRoot),
false);
} finally {
popParser();
}
} catch (XmlPullParserException e) {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
"Failed to configure parser for " + xml, e, null /*data*/);
// we'll return null below.
} catch (FileNotFoundException e) {
// this shouldn't happen since we check above.
} finally {
mBridgeInflater.setResourceReference(null);
}
} else {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
String.format("File %s is missing!", xml), null);
}
} else {
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
String.format("Layout %s%s does not exist.", isPlatformLayout ? "android:" : "",
layoutName), null);
}
return Pair.of(null, false);
}
// ------------- Activity Methods
@Override

View File

@ -19,6 +19,7 @@ package com.android.layoutlib.bridge.android;
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.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.resources.ResourceType;
@ -44,6 +45,7 @@ public final class BridgeInflater extends LayoutInflater {
private final IProjectCallback mProjectCallback;
private boolean mIsInMerge = false;
private ResourceReference mResourceReference;
/**
* List of class prefixes which are tried first by default.
@ -223,23 +225,33 @@ public final class BridgeInflater extends LayoutInflater {
// 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), 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.
int testDepth = mIsInMerge ? 2 : 1;
if (viewKey == null && parser.getDepth() == testDepth) {
if (viewKey == null) {
int currentDepth = parser.getDepth();
// test whether we are in an included file or in a adapter binding view.
BridgeXmlBlockParser previousParser = bc.getPreviousParser();
if (previousParser != null) {
viewKey = previousParser.getViewCookie();
// looks like we inside an embedded layout.
// only apply the cookie of the calling node (<include>) if we are at the
// top level of the embedded layout. If there is a merge tag, then
// skip it and look for the 2nd level
int testDepth = mIsInMerge ? 2 : 1;
if (currentDepth == testDepth) {
viewKey = previousParser.getViewCookie();
// if we are in a merge, wrap the cookie in a MergeCookie.
if (viewKey != null && mIsInMerge) {
viewKey = new MergeCookie(viewKey);
}
}
} else if (mResourceReference != null && currentDepth == 1) {
// else if there's a resource reference, this means we are in an adapter
// binding case. Set the resource ref as the view cookie only for the top
// level view.
viewKey = mResourceReference;
}
}
if (viewKey != null) {
if (testDepth == 2) {
// include-merge case
viewKey = new MergeCookie(viewKey);
}
bc.addViewKey(view, viewKey);
}
}
@ -250,6 +262,10 @@ public final class BridgeInflater extends LayoutInflater {
mIsInMerge = isInMerge;
}
public void setResourceReference(ResourceReference reference) {
mResourceReference = reference;
}
@Override
public LayoutInflater cloneInContext(Context newContext) {
return new BridgeInflater(this, newContext);

View File

@ -232,9 +232,8 @@ public final class BridgeResources extends Resources {
try {
// check if the current parser can provide us with a custom parser.
BridgeXmlBlockParser currentParser = mContext.getCurrentParser();
if (currentParser != null) {
parser = currentParser.getParser(value.getName());
if (mPlatformResourceFlag[0] == false) {
parser = mProjectCallback.getParser(value.getName());
}
// create a new one manually if needed.

View File

@ -69,14 +69,6 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
return mPlatformFile;
}
public ILayoutPullParser getParser(String layoutName) {
if (mParser instanceof ILayoutPullParser) {
return ((ILayoutPullParser)mParser).getParser(layoutName);
}
return null;
}
public Object getViewCookie() {
if (mParser instanceof ILayoutPullParser) {
return ((ILayoutPullParser)mParser).getViewCookie();

View File

@ -22,12 +22,14 @@ import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
import com.android.ide.common.rendering.api.AdapterBinding;
import com.android.ide.common.rendering.api.IAnimationListener;
import com.android.ide.common.rendering.api.ILayoutPullParser;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.RenderParams;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.RenderSession;
import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.Result;
import com.android.ide.common.rendering.api.SessionParams;
@ -44,6 +46,8 @@ import com.android.layoutlib.bridge.android.BridgeWindowSession;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.bars.PhoneSystemBar;
import com.android.layoutlib.bridge.bars.TitleBar;
import com.android.layoutlib.bridge.impl.binding.FakeAdapter;
import com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
import com.android.resources.ResourceType;
import com.android.resources.ScreenSize;
import com.android.util.Pair;
@ -62,8 +66,13 @@ import android.view.ViewGroup;
import android.view.View.AttachInfo;
import android.view.View.MeasureSpec;
import android.view.ViewGroup.LayoutParams;
import android.widget.AbsListView;
import android.widget.AbsSpinner;
import android.widget.AdapterView;
import android.widget.ExpandableListView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TabHost;
import android.widget.TabWidget;
import android.widget.TabHost.TabSpec;
@ -268,6 +277,9 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
View view = mInflater.inflate(mBlockParser, mContentRoot);
// done with the parser, pop it.
context.popParser();
// set the AttachInfo on the root view.
AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
new Handler(), null);
@ -875,6 +887,75 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
throws PostInflateException {
if (view instanceof TabHost) {
setupTabHost((TabHost)view, projectCallback);
} else if (view instanceof AdapterView<?>) {
// get the view ID.
int id = view.getId();
BridgeContext context = getContext();
// get a ResourceReference from the integer ID.
ResourceReference listRef = context.resolveId(id);
if (listRef != null) {
SessionParams params = getParams();
AdapterBinding binding = params.getAdapterBindings().get(listRef);
// if there was no adapter binding, trying to get it from the call back.
if (binding == null) {
binding = params.getProjectCallback().getAdapterBinding(listRef,
context.getViewKey(view), view);
}
if (binding != null) {
if (view instanceof AbsListView) {
if ((binding.getFooterCount() > 0 || binding.getHeaderCount() > 0) &&
view instanceof ListView) {
ListView list = (ListView) view;
boolean skipCallbackParser = false;
int count = binding.getHeaderCount();
for (int i = 0 ; i < count ; i++) {
Pair<View, Boolean> pair = context.inflateView(
binding.getHeaderAt(i),
list, false /*attachToRoot*/, skipCallbackParser);
if (pair.getFirst() != null) {
list.addHeaderView(pair.getFirst());
}
skipCallbackParser |= pair.getSecond();
}
count = binding.getFooterCount();
for (int i = 0 ; i < count ; i++) {
Pair<View, Boolean> pair = context.inflateView(
binding.getFooterAt(i),
list, false /*attachToRoot*/, skipCallbackParser);
if (pair.getFirst() != null) {
list.addFooterView(pair.getFirst());
}
skipCallbackParser |= pair.getSecond();
}
}
if (view instanceof ExpandableListView) {
((ExpandableListView) view).setAdapter(
new FakeExpandableAdapter(
listRef, binding, params.getProjectCallback()));
} else {
((AbsListView) view).setAdapter(
new FakeAdapter(
listRef, binding, params.getProjectCallback()));
}
} else if (view instanceof AbsSpinner) {
((AbsSpinner) view).setAdapter(
new FakeAdapter(
listRef, binding, params.getProjectCallback()));
}
}
}
} else if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup)view;
final int count = group.getChildCount();

View File

@ -115,7 +115,7 @@ public final class ResourceHelper {
public static ColorStateList getColorStateList(ResourceValue resValue, BridgeContext context) {
String value = resValue.getValue();
if (value != null) {
if (value != null && RenderResources.REFERENCE_NULL.equals(value) == false) {
// first check if the value is a file (xml most likely)
File f = new File(value);
if (f.isFile()) {

View File

@ -0,0 +1,247 @@
/*
* 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
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,113 @@
/*
* 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.ResourceReference;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.SpinnerAdapter;
import java.util.ArrayList;
import java.util.List;
/**
* Fake adapter to do fake data binding in {@link AdapterView} objects for {@link ListAdapter}
* and {@link SpinnerAdapter}.
*
*/
public class FakeAdapter extends BaseAdapter implements ListAdapter, SpinnerAdapter {
// don't use a set because the order is important.
private final List<ResourceReference> mTypes = new ArrayList<ResourceReference>();
public FakeAdapter(ResourceReference adapterRef, AdapterBinding binding,
IProjectCallback callback) {
super(adapterRef, binding, callback);
final int repeatCount = getBinding().getRepeatCount();
final int itemCount = getBinding().getItemCount();
// Need an array to count for each type.
// This is likely too big, but is the max it can be.
int[] typeCount = new int[itemCount];
// 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()) {
ResourceReference viewRef = dataBindingItem.getViewReference();
int typeIndex = mTypes.indexOf(viewRef);
if (typeIndex == -1) {
typeIndex = mTypes.size();
mTypes.add(viewRef);
}
int count = dataBindingItem.getCount();
int index = typeCount[typeIndex];
typeCount[typeIndex] += count;
for (int k = 0 ; k < count ; k++) {
mItems.add(new AdapterItem(dataBindingItem, typeIndex, mItems.size(), index++));
}
}
}
}
public boolean isEnabled(int position) {
return true;
}
public int getCount() {
return mItems.size();
}
public Object getItem(int position) {
return mItems.get(position);
}
public long getItemId(int position) {
return position;
}
public int getItemViewType(int position) {
return mItems.get(position).getType();
}
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);
}
public int getViewTypeCount() {
return mTypes.size();
}
// ---- SpinnerAdapter
public View getDropDownView(int position, View convertView, ViewGroup parent) {
// pass
return null;
}
}

View File

@ -0,0 +1,179 @@
/*
* 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.ResourceReference;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListAdapter;
import android.widget.HeterogeneousExpandableList;
import java.util.ArrayList;
import java.util.List;
public class FakeExpandableAdapter extends BaseAdapter implements ExpandableListAdapter,
HeterogeneousExpandableList {
// don't use a set because the order is important.
private final List<ResourceReference> mGroupTypes = new ArrayList<ResourceReference>();
private final List<ResourceReference> mChildrenTypes = new ArrayList<ResourceReference>();
public FakeExpandableAdapter(ResourceReference adapterRef, AdapterBinding binding,
IProjectCallback callback) {
super(adapterRef, binding, callback);
createItems(binding, binding.getItemCount(), binding.getRepeatCount(), mGroupTypes, 1);
}
private void createItems(Iterable<DataBindingItem> iterable, final int itemCount,
final int repeatCount, List<ResourceReference> types, int depth) {
// Need an array to count for each type.
// This is likely too big, but is the max it can be.
int[] typeCount = new int[itemCount];
// 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 : iterable) {
ResourceReference viewRef = dataBindingItem.getViewReference();
int typeIndex = types.indexOf(viewRef);
if (typeIndex == -1) {
typeIndex = types.size();
types.add(viewRef);
}
List<DataBindingItem> children = dataBindingItem.getChildren();
int count = dataBindingItem.getCount();
// if there are children, we use the count as a repeat count for the children.
if (children.size() > 0) {
count = 1;
}
int index = typeCount[typeIndex];
typeCount[typeIndex] += count;
for (int k = 0 ; k < count ; k++) {
AdapterItem item = new AdapterItem(dataBindingItem, typeIndex, mItems.size(),
index++);
mItems.add(item);
if (children.size() > 0) {
createItems(dataBindingItem, depth + 1);
}
}
}
}
}
private void createItems(DataBindingItem item, int depth) {
if (depth == 2) {
createItems(item, item.getChildren().size(), item.getCount(), mChildrenTypes, depth);
}
}
private AdapterItem getChildItem(int groupPosition, int childPosition) {
AdapterItem item = mItems.get(groupPosition);
List<AdapterItem> children = item.getChildren();
return children.get(childPosition);
}
// ---- ExpandableListAdapter
public int getGroupCount() {
return mItems.size();
}
public int getChildrenCount(int groupPosition) {
AdapterItem item = mItems.get(groupPosition);
return item.getChildren().size();
}
public Object getGroup(int groupPosition) {
return mItems.get(groupPosition);
}
public Object getChild(int groupPosition, int childPosition) {
return getChildItem(groupPosition, childPosition);
}
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
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);
}
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
// 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);
}
public long getGroupId(int groupPosition) {
return groupPosition;
}
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
public long getCombinedGroupId(long groupId) {
return groupId << 16 | 0x0000FFFF;
}
public long getCombinedChildId(long groupId, long childId) {
return groupId << 16 | childId;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public void onGroupCollapsed(int groupPosition) {
// pass
}
public void onGroupExpanded(int groupPosition) {
// pass
}
// ---- HeterogeneousExpandableList
public int getChildType(int groupPosition, int childPosition) {
return getChildItem(groupPosition, childPosition).getType();
}
public int getChildTypeCount() {
return mChildrenTypes.size();
}
public int getGroupType(int groupPosition) {
return mItems.get(groupPosition).getType();
}
public int getGroupTypeCount() {
return mGroupTypes.size();
}
}