Merge "Merge 2fae858d
from Honeycomb-mr1. do not merge." into gingerbread
This commit is contained in:
committed by
Android (Google) Code Review
commit
bb43828aa7
@ -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
|
||||
*/
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user