aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java597
1 files changed, 597 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java
new file mode 100644
index 000000000..7b2fe84f0
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/LayoutDescriptors.java
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.ide.eclipse.adt.internal.editors.layout.descriptors;
+
+import static com.android.SdkConstants.ANDROID_URI;
+import static com.android.SdkConstants.ATTR_CLASS;
+import static com.android.SdkConstants.ATTR_LAYOUT;
+import static com.android.SdkConstants.ATTR_NAME;
+import static com.android.SdkConstants.ATTR_TAG;
+import static com.android.SdkConstants.CLASS_VIEW;
+import static com.android.SdkConstants.FQCN_GESTURE_OVERLAY_VIEW;
+import static com.android.SdkConstants.REQUEST_FOCUS;
+import static com.android.SdkConstants.VIEW_FRAGMENT;
+import static com.android.SdkConstants.VIEW_INCLUDE;
+import static com.android.SdkConstants.VIEW_MERGE;
+import static com.android.SdkConstants.VIEW_TAG;
+
+import com.android.SdkConstants;
+import com.android.ide.common.api.IAttributeInfo.Format;
+import com.android.ide.common.resources.platform.AttributeInfo;
+import com.android.ide.common.resources.platform.DeclareStyleableInfo;
+import com.android.ide.common.resources.platform.ViewClassInfo;
+import com.android.ide.common.resources.platform.ViewClassInfo.LayoutParamsInfo;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.ClassAttributeDescriptor;
+import com.android.sdklib.IAndroidTarget;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+/**
+ * Complete description of the layout structure.
+ */
+public final class LayoutDescriptors implements IDescriptorProvider {
+ /** The document descriptor. Contains all layouts and views linked together. */
+ private DocumentDescriptor mRootDescriptor =
+ new DocumentDescriptor("layout_doc", null); //$NON-NLS-1$
+
+ /** The list of all known ViewLayout descriptors. */
+ private List<ViewElementDescriptor> mLayoutDescriptors = Collections.emptyList();
+
+ /** Read-Only list of View Descriptors. */
+ private List<ViewElementDescriptor> mROLayoutDescriptors;
+
+ /** The list of all known View (not ViewLayout) descriptors. */
+ private List<ViewElementDescriptor> mViewDescriptors = Collections.emptyList();
+
+ /** Read-Only list of View Descriptors. */
+ private List<ViewElementDescriptor> mROViewDescriptors;
+
+ /** The descriptor matching android.view.View. */
+ private ViewElementDescriptor mBaseViewDescriptor;
+
+ /** Map from view full class name to view descriptor */
+ private Map<String, ViewElementDescriptor> mFqcnToDescriptor =
+ // As of 3.1 there are 58 items in this map
+ new HashMap<String, ViewElementDescriptor>(80);
+
+ /** Returns the document descriptor. Contains all layouts and views linked together. */
+ @Override
+ public DocumentDescriptor getDescriptor() {
+ return mRootDescriptor;
+ }
+
+ /** Returns the read-only list of all known ViewLayout descriptors. */
+ public List<ViewElementDescriptor> getLayoutDescriptors() {
+ return mROLayoutDescriptors;
+ }
+
+ /** Returns the read-only list of all known View (not ViewLayout) descriptors. */
+ public List<ViewElementDescriptor> getViewDescriptors() {
+ return mROViewDescriptors;
+ }
+
+ @Override
+ public ElementDescriptor[] getRootElementDescriptors() {
+ return mRootDescriptor.getChildren();
+ }
+
+ /**
+ * Returns the descriptor matching android.view.View, which is guaranteed
+ * to be a {@link ViewElementDescriptor}.
+ */
+ public ViewElementDescriptor getBaseViewDescriptor() {
+ if (mBaseViewDescriptor == null) {
+ mBaseViewDescriptor = findDescriptorByClass(SdkConstants.CLASS_VIEW);
+ }
+ return mBaseViewDescriptor;
+ }
+
+ /**
+ * Updates the document descriptor.
+ * <p/>
+ * It first computes the new children of the descriptor and then update them
+ * all at once.
+ * <p/>
+ * TODO: differentiate groups from views in the tree UI? => rely on icons
+ * <p/>
+ *
+ * @param views The list of views in the framework.
+ * @param layouts The list of layouts in the framework.
+ * @param styleMap A map from style names to style information provided by the SDK
+ * @param target The android target being initialized
+ */
+ public synchronized void updateDescriptors(ViewClassInfo[] views, ViewClassInfo[] layouts,
+ Map<String, DeclareStyleableInfo> styleMap, IAndroidTarget target) {
+
+ // This map links every ViewClassInfo to the ElementDescriptor we created.
+ // It is filled by convertView() and used later to fix the super-class hierarchy.
+ HashMap<ViewClassInfo, ViewElementDescriptor> infoDescMap =
+ new HashMap<ViewClassInfo, ViewElementDescriptor>();
+
+ ArrayList<ViewElementDescriptor> newViews = new ArrayList<ViewElementDescriptor>(40);
+ if (views != null) {
+ for (ViewClassInfo info : views) {
+ ViewElementDescriptor desc = convertView(info, infoDescMap);
+ newViews.add(desc);
+ mFqcnToDescriptor.put(desc.getFullClassName(), desc);
+ }
+ }
+
+ // Create <include> as a synthetic regular view.
+ // Note: ViewStub is already described by attrs.xml
+ insertInclude(newViews);
+
+ List<ViewElementDescriptor> newLayouts = new ArrayList<ViewElementDescriptor>(30);
+ if (layouts != null) {
+ for (ViewClassInfo info : layouts) {
+ ViewElementDescriptor desc = convertView(info, infoDescMap);
+ newLayouts.add(desc);
+ mFqcnToDescriptor.put(desc.getFullClassName(), desc);
+ }
+ }
+
+ // Find View and inherit all its layout attributes
+ AttributeDescriptor[] frameLayoutAttrs = findViewLayoutAttributes(
+ SdkConstants.CLASS_FRAMELAYOUT);
+
+ if (target.getVersion().getApiLevel() >= 4) {
+ ViewElementDescriptor fragmentTag = createFragment(frameLayoutAttrs, styleMap);
+ newViews.add(fragmentTag);
+ }
+
+ List<ElementDescriptor> newDescriptors = new ArrayList<ElementDescriptor>(80);
+ newDescriptors.addAll(newLayouts);
+ newDescriptors.addAll(newViews);
+
+ ViewElementDescriptor viewTag = createViewTag(frameLayoutAttrs);
+ newViews.add(viewTag);
+ newDescriptors.add(viewTag);
+
+ ViewElementDescriptor requestFocus = createRequestFocus();
+ newViews.add(requestFocus);
+ newDescriptors.add(requestFocus);
+
+ // Link all layouts to everything else here.. recursively
+ for (ViewElementDescriptor layoutDesc : newLayouts) {
+ layoutDesc.setChildren(newDescriptors);
+ }
+
+ // The gesture overlay descriptor is really a layout but not included in the layouts list
+ // so handle it specially
+ ViewElementDescriptor gestureView = findDescriptorByClass(FQCN_GESTURE_OVERLAY_VIEW);
+ if (gestureView != null) {
+ gestureView.setChildren(newDescriptors);
+ // Inherit layout attributes from FrameLayout
+ gestureView.setLayoutAttributes(frameLayoutAttrs);
+ }
+
+ fixSuperClasses(infoDescMap);
+
+ // The <merge> tag can only be a root tag, so it is added at the end.
+ // It gets everything else as children but it is not made a child itself.
+ ViewElementDescriptor mergeTag = createMerge(frameLayoutAttrs);
+ mergeTag.setChildren(newDescriptors); // mergeTag makes a copy of the list
+ newDescriptors.add(mergeTag);
+ newLayouts.add(mergeTag);
+
+ // Sort palette contents
+ Collections.sort(newViews);
+ Collections.sort(newLayouts);
+
+ mViewDescriptors = newViews;
+ mLayoutDescriptors = newLayouts;
+ mRootDescriptor.setChildren(newDescriptors);
+
+ mBaseViewDescriptor = null;
+ mROLayoutDescriptors = Collections.unmodifiableList(mLayoutDescriptors);
+ mROViewDescriptors = Collections.unmodifiableList(mViewDescriptors);
+ }
+
+ /**
+ * Creates an element descriptor from a given {@link ViewClassInfo}.
+ *
+ * @param info The {@link ViewClassInfo} to convert into a new {@link ViewElementDescriptor}.
+ * @param infoDescMap This map links every ViewClassInfo to the ElementDescriptor it created.
+ * It is filled by here and used later to fix the super-class hierarchy.
+ */
+ private ViewElementDescriptor convertView(
+ ViewClassInfo info,
+ HashMap<ViewClassInfo, ViewElementDescriptor> infoDescMap) {
+ String xmlName = info.getShortClassName();
+ String uiName = xmlName;
+ String fqcn = info.getFullClassName();
+ if (ViewElementDescriptor.viewNeedsPackage(fqcn)) {
+ xmlName = fqcn;
+ }
+ String tooltip = info.getJavaDoc();
+
+ // Average is around 90, max (in 3.2) is 145
+ ArrayList<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>(120);
+
+ // All views and groups have an implicit "style" attribute which is a reference.
+ AttributeInfo styleInfo = new AttributeInfo(
+ "style", //$NON-NLS-1$ xmlLocalName
+ Format.REFERENCE_SET);
+ styleInfo.setJavaDoc("A reference to a custom style"); //tooltip
+ DescriptorsUtils.appendAttribute(attributes,
+ "style", //$NON-NLS-1$
+ null, //nsUri
+ styleInfo,
+ false, //required
+ null); // overrides
+ styleInfo.setDefinedBy(SdkConstants.CLASS_VIEW);
+
+ // Process all View attributes
+ DescriptorsUtils.appendAttributes(attributes,
+ null, // elementName
+ ANDROID_URI,
+ info.getAttributes(),
+ null, // requiredAttributes
+ null /* overrides */);
+
+ List<String> attributeSources = new ArrayList<String>();
+ if (info.getAttributes() != null && info.getAttributes().length > 0) {
+ attributeSources.add(fqcn);
+ }
+
+ for (ViewClassInfo link = info.getSuperClass();
+ link != null;
+ link = link.getSuperClass()) {
+ AttributeInfo[] attrList = link.getAttributes();
+ if (attrList.length > 0) {
+ attributeSources.add(link.getFullClassName());
+ DescriptorsUtils.appendAttributes(attributes,
+ null, // elementName
+ ANDROID_URI,
+ attrList,
+ null, // requiredAttributes
+ null /* overrides */);
+ }
+ }
+
+ // Process all LayoutParams attributes
+ ArrayList<AttributeDescriptor> layoutAttributes = new ArrayList<AttributeDescriptor>();
+ LayoutParamsInfo layoutParams = info.getLayoutData();
+
+ for(; layoutParams != null; layoutParams = layoutParams.getSuperClass()) {
+ for (AttributeInfo attrInfo : layoutParams.getAttributes()) {
+ if (DescriptorsUtils.containsAttribute(layoutAttributes,
+ ANDROID_URI, attrInfo)) {
+ continue;
+ }
+ DescriptorsUtils.appendAttribute(layoutAttributes,
+ null, // elementName
+ ANDROID_URI,
+ attrInfo,
+ false, // required
+ null /* overrides */);
+ }
+ }
+
+ ViewElementDescriptor desc = new ViewElementDescriptor(
+ xmlName,
+ uiName,
+ fqcn,
+ tooltip,
+ null, // sdk_url
+ attributes.toArray(new AttributeDescriptor[attributes.size()]),
+ layoutAttributes.toArray(new AttributeDescriptor[layoutAttributes.size()]),
+ null, // children
+ false /* mandatory */);
+ desc.setAttributeSources(Collections.unmodifiableList(attributeSources));
+ infoDescMap.put(info, desc);
+ return desc;
+ }
+
+ /**
+ * Creates a new {@code <include>} descriptor and adds it to the list of view descriptors.
+ *
+ * @param knownViews A list of view descriptors being populated. Also used to find the
+ * View descriptor and extract its layout attributes.
+ */
+ private void insertInclude(List<ViewElementDescriptor> knownViews) {
+ String xmlName = VIEW_INCLUDE;
+
+ // Create the include custom attributes
+ ArrayList<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>();
+
+ // Find View and inherit all its layout attributes
+ AttributeDescriptor[] viewLayoutAttribs;
+ AttributeDescriptor[] viewAttributes = null;
+ ViewElementDescriptor viewDesc = findDescriptorByClass(SdkConstants.CLASS_VIEW);
+ if (viewDesc != null) {
+ viewAttributes = viewDesc.getAttributes();
+ attributes = new ArrayList<AttributeDescriptor>(viewAttributes.length + 1);
+ viewLayoutAttribs = viewDesc.getLayoutAttributes();
+ } else {
+ viewLayoutAttribs = new AttributeDescriptor[0];
+ }
+
+ // Note that the "layout" attribute does NOT have the Android namespace
+ DescriptorsUtils.appendAttribute(attributes,
+ null, //elementXmlName
+ null, //nsUri
+ new AttributeInfo(
+ ATTR_LAYOUT,
+ Format.REFERENCE_SET ),
+ true, //required
+ null); //overrides
+
+ if (viewAttributes != null) {
+ for (AttributeDescriptor descriptor : viewAttributes) {
+ attributes.add(descriptor);
+ }
+ }
+
+ // Create the include descriptor
+ ViewElementDescriptor desc = new ViewElementDescriptor(xmlName,
+ xmlName, // ui_name
+ VIEW_INCLUDE, // "class name"; the GLE only treats this as an element tag
+ "Lets you statically include XML layouts inside other XML layouts.", // tooltip
+ null, // sdk_url
+ attributes.toArray(new AttributeDescriptor[attributes.size()]),
+ viewLayoutAttribs, // layout attributes
+ null, // children
+ false /* mandatory */);
+
+ knownViews.add(desc);
+ }
+
+ /**
+ * Creates and returns a new {@code <merge>} descriptor.
+ * @param viewLayoutAttribs The layout attributes to use for the new descriptor
+ */
+ private ViewElementDescriptor createMerge(AttributeDescriptor[] viewLayoutAttribs) {
+ String xmlName = VIEW_MERGE;
+
+ // Create the include descriptor
+ ViewElementDescriptor desc = new ViewElementDescriptor(xmlName,
+ xmlName, // ui_name
+ VIEW_MERGE, // "class name"; the GLE only treats this as an element tag
+ "A root tag useful for XML layouts inflated using a ViewStub.", // tooltip
+ null, // sdk_url
+ null, // attributes
+ viewLayoutAttribs, // layout attributes
+ null, // children
+ false /* mandatory */);
+
+ return desc;
+ }
+
+ /**
+ * Creates and returns a new {@code <fragment>} descriptor.
+ * @param viewLayoutAttribs The layout attributes to use for the new descriptor
+ * @param styleMap The style map provided by the SDK
+ */
+ private ViewElementDescriptor createFragment(AttributeDescriptor[] viewLayoutAttribs,
+ Map<String, DeclareStyleableInfo> styleMap) {
+ String xmlName = VIEW_FRAGMENT;
+ final ViewElementDescriptor descriptor;
+
+ // First try to create the descriptor from metadata in attrs.xml:
+ DeclareStyleableInfo style = styleMap.get("Fragment"); //$NON-NLS-1$
+ String fragmentTooltip =
+ "A Fragment is a piece of an application's user interface or behavior that "
+ + "can be placed in an Activity";
+ String sdkUrl = "http://developer.android.com/guide/topics/fundamentals/fragments.html";
+ TextAttributeDescriptor classAttribute = new ClassAttributeDescriptor(
+ // Should accept both CLASS_V4_FRAGMENT and CLASS_FRAGMENT
+ null /*superClassName*/,
+ ATTR_CLASS, null /* namespace */,
+ new AttributeInfo(ATTR_CLASS, Format.STRING_SET),
+ true /*mandatory*/)
+ .setTooltip("Supply the name of the fragment class to instantiate");
+
+ if (style != null) {
+ descriptor = new ViewElementDescriptor(
+ VIEW_FRAGMENT, VIEW_FRAGMENT, VIEW_FRAGMENT,
+ fragmentTooltip, // tooltip
+ sdkUrl, //,
+ null /* attributes */,
+ viewLayoutAttribs, // layout attributes
+ null /*childrenElements*/,
+ false /*mandatory*/);
+ ArrayList<AttributeDescriptor> descs = new ArrayList<AttributeDescriptor>();
+ // The class attribute is not included in the attrs.xml
+ descs.add(classAttribute);
+ DescriptorsUtils.appendAttributes(descs,
+ null, // elementName
+ ANDROID_URI,
+ style.getAttributes(),
+ null, // requiredAttributes
+ null); // overrides
+ //descriptor.setTooltip(style.getJavaDoc());
+ descriptor.setAttributes(descs.toArray(new AttributeDescriptor[descs.size()]));
+ } else {
+ // The above will only work on API 11 and up. However, fragments are *also* available
+ // on older platforms, via the fragment support library, so add in a manual
+ // entry if necessary.
+ descriptor = new ViewElementDescriptor(xmlName,
+ xmlName, // ui_name
+ xmlName, // "class name"; the GLE only treats this as an element tag
+ fragmentTooltip,
+ sdkUrl,
+ new AttributeDescriptor[] {
+ new ClassAttributeDescriptor(
+ null /*superClassName*/,
+ ATTR_NAME, ANDROID_URI,
+ new AttributeInfo(ATTR_NAME, Format.STRING_SET),
+ true /*mandatory*/)
+ .setTooltip("Supply the name of the fragment class to instantiate"),
+ classAttribute,
+ new ClassAttributeDescriptor(
+ null /*superClassName*/,
+ ATTR_TAG, ANDROID_URI,
+ new AttributeInfo(ATTR_TAG, Format.STRING_SET),
+ true /*mandatory*/)
+ .setTooltip("Supply a tag for the top-level view containing a String"),
+ }, // attributes
+ viewLayoutAttribs, // layout attributes
+ null, // children
+ false /* mandatory */);
+ }
+
+ return descriptor;
+ }
+
+ /**
+ * Creates and returns a new {@code <view>} descriptor.
+ * @param viewLayoutAttribs The layout attributes to use for the new descriptor
+ * @param styleMap The style map provided by the SDK
+ */
+ private ViewElementDescriptor createViewTag(AttributeDescriptor[] viewLayoutAttribs) {
+ String xmlName = VIEW_TAG;
+
+ TextAttributeDescriptor classAttribute = new ClassAttributeDescriptor(
+ CLASS_VIEW,
+ ATTR_CLASS, null /* namespace */,
+ new AttributeInfo(ATTR_CLASS, Format.STRING_SET),
+ true /*mandatory*/)
+ .setTooltip("Supply the name of the view class to instantiate");
+
+ // Create the include descriptor
+ ViewElementDescriptor desc = new ViewElementDescriptor(xmlName,
+ xmlName, // ui_name
+ xmlName, // "class name"; the GLE only treats this as an element tag
+ "A view tag whose class attribute names the class to be instantiated", // tooltip
+ null, // sdk_url
+ new AttributeDescriptor[] { // attributes
+ classAttribute
+ },
+ viewLayoutAttribs, // layout attributes
+ null, // children
+ false /* mandatory */);
+
+ return desc;
+ }
+
+ /**
+ * Creates and returns a new {@code <requestFocus>} descriptor.
+ */
+ private ViewElementDescriptor createRequestFocus() {
+ String xmlName = REQUEST_FOCUS;
+
+ // Create the include descriptor
+ return new ViewElementDescriptor(
+ xmlName, // xml_name
+ xmlName, // ui_name
+ xmlName, // "class name"; the GLE only treats this as an element tag
+ "Requests focus for the parent element or one of its descendants", // tooltip
+ null, // sdk_url
+ null, // attributes
+ null, // layout attributes
+ null, // children
+ false /* mandatory */);
+ }
+
+ /**
+ * Finds the descriptor and retrieves all its layout attributes.
+ */
+ private AttributeDescriptor[] findViewLayoutAttributes(
+ String viewFqcn) {
+ ViewElementDescriptor viewDesc = findDescriptorByClass(viewFqcn);
+ if (viewDesc != null) {
+ return viewDesc.getLayoutAttributes();
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the super-class of each {@link ViewElementDescriptor} by using the super-class
+ * information available in the {@link ViewClassInfo}.
+ */
+ private void fixSuperClasses(Map<ViewClassInfo, ViewElementDescriptor> infoDescMap) {
+
+ for (Entry<ViewClassInfo, ViewElementDescriptor> entry : infoDescMap.entrySet()) {
+ ViewClassInfo info = entry.getKey();
+ ViewElementDescriptor desc = entry.getValue();
+
+ ViewClassInfo sup = info.getSuperClass();
+ if (sup != null) {
+ ViewElementDescriptor supDesc = infoDescMap.get(sup);
+ while (supDesc == null && sup != null) {
+ // We don't have a descriptor for the super-class. That means the class is
+ // probably abstract, so we just need to walk up the super-class chain till
+ // we find one we have. All views derive from android.view.View so we should
+ // surely find that eventually.
+ sup = sup.getSuperClass();
+ if (sup != null) {
+ supDesc = infoDescMap.get(sup);
+ }
+ }
+ if (supDesc != null) {
+ desc.setSuperClass(supDesc);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the {@link ViewElementDescriptor} with the given fully qualified class
+ * name, or null if not found. This is a quick map lookup.
+ *
+ * @param fqcn the fully qualified class name
+ * @return the corresponding {@link ViewElementDescriptor} or null
+ */
+ public ViewElementDescriptor findDescriptorByClass(String fqcn) {
+ return mFqcnToDescriptor.get(fqcn);
+ }
+
+ /**
+ * Returns the {@link ViewElementDescriptor} with the given XML tag name,
+ * which usually does not include the package (depending on the
+ * value of {@link ViewElementDescriptor#viewNeedsPackage(String)}).
+ *
+ * @param tag the XML tag name
+ * @return the corresponding {@link ViewElementDescriptor} or null
+ */
+ public ViewElementDescriptor findDescriptorByTag(String tag) {
+ // TODO: Consider whether we need to add a direct map lookup for this as well.
+ // Currently not done since this is not frequently needed (only needed for
+ // exploded rendering which was already performing list iteration.)
+ for (ViewElementDescriptor descriptor : mLayoutDescriptors) {
+ if (tag.equals(descriptor.getXmlLocalName())) {
+ return descriptor;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a collection of all the view class names, including layouts
+ *
+ * @return a collection of all the view class names, never null
+ */
+ public Collection<String> getAllViewClassNames() {
+ return mFqcnToDescriptor.keySet();
+ }
+}