Home | History | Annotate | Download | only in descriptors
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ide.eclipse.adt.internal.editors.layout.descriptors;
     18 
     19 import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
     20 import static com.android.ide.common.layout.LayoutConstants.ATTR_CLASS;
     21 import static com.android.ide.common.layout.LayoutConstants.ATTR_NAME;
     22 import static com.android.ide.common.layout.LayoutConstants.ATTR_TAG;
     23 import static com.android.ide.common.layout.LayoutConstants.FQCN_GESTURE_OVERLAY_VIEW;
     24 
     25 import com.android.ide.common.api.IAttributeInfo.Format;
     26 import com.android.ide.common.resources.platform.AttributeInfo;
     27 import com.android.ide.common.resources.platform.DeclareStyleableInfo;
     28 import com.android.ide.common.resources.platform.ViewClassInfo;
     29 import com.android.ide.common.resources.platform.ViewClassInfo.LayoutParamsInfo;
     30 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
     31 import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
     32 import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescriptor;
     33 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
     34 import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
     35 import com.android.ide.eclipse.adt.internal.editors.descriptors.SeparatorAttributeDescriptor;
     36 import com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor;
     37 import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.ClassAttributeDescriptor;
     38 import com.android.sdklib.IAndroidTarget;
     39 import com.android.sdklib.SdkConstants;
     40 
     41 import java.util.ArrayList;
     42 import java.util.Collection;
     43 import java.util.Collections;
     44 import java.util.HashMap;
     45 import java.util.List;
     46 import java.util.Map;
     47 import java.util.Map.Entry;
     48 
     49 
     50 /**
     51  * Complete description of the layout structure.
     52  */
     53 public final class LayoutDescriptors implements IDescriptorProvider {
     54 
     55     /**
     56      * The XML name of the special {@code <include>} layout tag.
     57      * A synthetic element with that name is created as part of the view descriptors list
     58      * returned by {@link #getViewDescriptors()}.
     59      */
     60     public static final String VIEW_INCLUDE = "include";      //$NON-NLS-1$
     61 
     62     /**
     63      * The XML name of the special {@code <merge>} layout tag.
     64      * A synthetic element with that name is created as part of the view descriptors list
     65      * returned by {@link #getViewDescriptors()}.
     66      */
     67     public static final String VIEW_MERGE = "merge";          //$NON-NLS-1$
     68 
     69     /**
     70      * The XML name of the special {@code <fragment>} layout tag.
     71      * A synthetic element with that name is created as part of the view descriptors list
     72      * returned by {@link #getViewDescriptors()}.
     73      */
     74     public static final String VIEW_FRAGMENT = "fragment";    //$NON-NLS-1$
     75 
     76     /**
     77      * The XML name of the special {@code <view>} layout tag. This is used to add generic
     78      * views with a class attribute to specify the view.
     79      * <p>
     80      * TODO: We should add a synthetic descriptor for this, similar to our descriptors for
     81      * include, merge and requestFocus.
     82      */
     83     public static final String VIEW_VIEWTAG = "view";           //$NON-NLS-1$
     84 
     85     /**
     86      * The XML name of the special {@code <requestFocus>} layout tag.
     87      * A synthetic element with that name is created as part of the view descriptors list
     88      * returned by {@link #getViewDescriptors()}.
     89      */
     90     public static final String REQUEST_FOCUS = "requestFocus";//$NON-NLS-1$
     91 
     92     /**
     93      * The attribute name of the include tag's url naming the resource to be inserted
     94      * <p>
     95      * <b>NOTE</b>: The layout attribute is NOT in the Android namespace!
     96      */
     97     public static final String ATTR_LAYOUT = "layout"; //$NON-NLS-1$
     98 
     99     // Public attributes names, attributes descriptors and elements descriptors
    100     public static final String ID_ATTR = "id"; //$NON-NLS-1$
    101 
    102     /** The document descriptor. Contains all layouts and views linked together. */
    103     private DocumentDescriptor mRootDescriptor =
    104         new DocumentDescriptor("layout_doc", null); //$NON-NLS-1$
    105 
    106     /** The list of all known ViewLayout descriptors. */
    107     private List<ViewElementDescriptor> mLayoutDescriptors = Collections.emptyList();
    108 
    109     /** Read-Only list of View Descriptors. */
    110     private List<ViewElementDescriptor> mROLayoutDescriptors;
    111 
    112     /** The list of all known View (not ViewLayout) descriptors. */
    113     private List<ViewElementDescriptor> mViewDescriptors = Collections.emptyList();
    114 
    115     /** Read-Only list of View Descriptors. */
    116     private List<ViewElementDescriptor> mROViewDescriptors;
    117 
    118     /** The descriptor matching android.view.View. */
    119     private ViewElementDescriptor mBaseViewDescriptor;
    120 
    121     /** Map from view full class name to view descriptor */
    122     private Map<String, ViewElementDescriptor> mFqcnToDescriptor =
    123         // As of 3.1 there are 58 items in this map
    124         new HashMap<String, ViewElementDescriptor>(80);
    125 
    126     /** Returns the document descriptor. Contains all layouts and views linked together. */
    127     @Override
    128     public DocumentDescriptor getDescriptor() {
    129         return mRootDescriptor;
    130     }
    131 
    132     /** Returns the read-only list of all known ViewLayout descriptors. */
    133     public List<ViewElementDescriptor> getLayoutDescriptors() {
    134         return mROLayoutDescriptors;
    135     }
    136 
    137     /** Returns the read-only list of all known View (not ViewLayout) descriptors. */
    138     public List<ViewElementDescriptor> getViewDescriptors() {
    139         return mROViewDescriptors;
    140     }
    141 
    142     @Override
    143     public ElementDescriptor[] getRootElementDescriptors() {
    144         return mRootDescriptor.getChildren();
    145     }
    146 
    147     /**
    148      * Returns the descriptor matching android.view.View, which is guaranteed
    149      * to be a {@link ViewElementDescriptor}.
    150      */
    151     public ViewElementDescriptor getBaseViewDescriptor() {
    152         if (mBaseViewDescriptor == null) {
    153             mBaseViewDescriptor = findDescriptorByClass(SdkConstants.CLASS_VIEW);
    154         }
    155         return mBaseViewDescriptor;
    156     }
    157 
    158     /**
    159      * Updates the document descriptor.
    160      * <p/>
    161      * It first computes the new children of the descriptor and then update them
    162      * all at once.
    163      * <p/>
    164      *  TODO: differentiate groups from views in the tree UI? => rely on icons
    165      * <p/>
    166      *
    167      * @param views The list of views in the framework.
    168      * @param layouts The list of layouts in the framework.
    169      * @param styleMap A map from style names to style information provided by the SDK
    170      * @param target The android target being initialized
    171      */
    172     public synchronized void updateDescriptors(ViewClassInfo[] views, ViewClassInfo[] layouts,
    173             Map<String, DeclareStyleableInfo> styleMap, IAndroidTarget target) {
    174 
    175         // This map links every ViewClassInfo to the ElementDescriptor we created.
    176         // It is filled by convertView() and used later to fix the super-class hierarchy.
    177         HashMap<ViewClassInfo, ViewElementDescriptor> infoDescMap =
    178             new HashMap<ViewClassInfo, ViewElementDescriptor>();
    179 
    180         ArrayList<ViewElementDescriptor> newViews = new ArrayList<ViewElementDescriptor>(40);
    181         if (views != null) {
    182             for (ViewClassInfo info : views) {
    183                 ViewElementDescriptor desc = convertView(info, infoDescMap);
    184                 newViews.add(desc);
    185                 mFqcnToDescriptor.put(desc.getFullClassName(), desc);
    186             }
    187         }
    188 
    189         // Create <include> as a synthetic regular view.
    190         // Note: ViewStub is already described by attrs.xml
    191         insertInclude(newViews);
    192 
    193         List<ViewElementDescriptor> newLayouts = new ArrayList<ViewElementDescriptor>(30);
    194         if (layouts != null) {
    195             for (ViewClassInfo info : layouts) {
    196                 ViewElementDescriptor desc = convertView(info, infoDescMap);
    197                 newLayouts.add(desc);
    198                 mFqcnToDescriptor.put(desc.getFullClassName(), desc);
    199             }
    200         }
    201 
    202         // Find View and inherit all its layout attributes
    203         AttributeDescriptor[] frameLayoutAttrs = findViewLayoutAttributes(
    204                 SdkConstants.CLASS_FRAMELAYOUT);
    205 
    206         if (target.getVersion().getApiLevel() >= 4) {
    207             ViewElementDescriptor fragmentTag = createFragment(frameLayoutAttrs, styleMap);
    208             newViews.add(fragmentTag);
    209         }
    210 
    211         List<ElementDescriptor> newDescriptors = new ArrayList<ElementDescriptor>(80);
    212         newDescriptors.addAll(newLayouts);
    213         newDescriptors.addAll(newViews);
    214 
    215         // Link all layouts to everything else here.. recursively
    216         for (ViewElementDescriptor layoutDesc : newLayouts) {
    217             layoutDesc.setChildren(newDescriptors);
    218         }
    219 
    220         // The gesture overlay descriptor is really a layout but not included in the layouts list
    221         // so handle it specially
    222         ViewElementDescriptor gestureView = findDescriptorByClass(FQCN_GESTURE_OVERLAY_VIEW);
    223         if (gestureView != null) {
    224             gestureView.setChildren(newDescriptors);
    225             // Inherit layout attributes from FrameLayout
    226             gestureView.setLayoutAttributes(frameLayoutAttrs);
    227         }
    228 
    229         fixSuperClasses(infoDescMap);
    230 
    231         ViewElementDescriptor requestFocus = createRequestFocus();
    232         newViews.add(requestFocus);
    233         newDescriptors.add(requestFocus);
    234 
    235         // The <merge> tag can only be a root tag, so it is added at the end.
    236         // It gets everything else as children but it is not made a child itself.
    237         ViewElementDescriptor mergeTag = createMerge(frameLayoutAttrs);
    238         mergeTag.setChildren(newDescriptors);  // mergeTag makes a copy of the list
    239         newDescriptors.add(mergeTag);
    240         newLayouts.add(mergeTag);
    241 
    242         // Sort palette contents
    243         Collections.sort(newViews);
    244         Collections.sort(newLayouts);
    245 
    246         mViewDescriptors = newViews;
    247         mLayoutDescriptors  = newLayouts;
    248         mRootDescriptor.setChildren(newDescriptors);
    249 
    250         mBaseViewDescriptor = null;
    251         mROLayoutDescriptors = Collections.unmodifiableList(mLayoutDescriptors);
    252         mROViewDescriptors = Collections.unmodifiableList(mViewDescriptors);
    253     }
    254 
    255     /**
    256      * Creates an element descriptor from a given {@link ViewClassInfo}.
    257      *
    258      * @param info The {@link ViewClassInfo} to convert into a new {@link ViewElementDescriptor}.
    259      * @param infoDescMap This map links every ViewClassInfo to the ElementDescriptor it created.
    260      *                    It is filled by here and used later to fix the super-class hierarchy.
    261      */
    262     private ViewElementDescriptor convertView(
    263             ViewClassInfo info,
    264             HashMap<ViewClassInfo, ViewElementDescriptor> infoDescMap) {
    265         String xmlName = info.getShortClassName();
    266         String uiName = xmlName;
    267         String fqcn = info.getFullClassName();
    268         if (ViewElementDescriptor.viewNeedsPackage(fqcn)) {
    269             xmlName = fqcn;
    270         }
    271         String tooltip = info.getJavaDoc();
    272 
    273         // Average is around 90, max (in 3.2) is 145
    274         ArrayList<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>(120);
    275 
    276         // All views and groups have an implicit "style" attribute which is a reference.
    277         AttributeInfo styleInfo = new AttributeInfo(
    278                 "style",    //$NON-NLS-1$ xmlLocalName
    279                 Format.REFERENCE_SET);
    280         styleInfo.setJavaDoc("A reference to a custom style"); //tooltip
    281         DescriptorsUtils.appendAttribute(attributes,
    282                 "style",    //$NON-NLS-1$
    283                 null,       //nsUri
    284                 styleInfo,
    285                 false,      //required
    286                 null);      // overrides
    287         styleInfo.setDefinedBy(SdkConstants.CLASS_VIEW);
    288 
    289         // Process all View attributes
    290         DescriptorsUtils.appendAttributes(attributes,
    291                 null, // elementName
    292                 SdkConstants.NS_RESOURCES,
    293                 info.getAttributes(),
    294                 null, // requiredAttributes
    295                 null /* overrides */);
    296 
    297         List<String> attributeSources = new ArrayList<String>();
    298         if (info.getAttributes() != null && info.getAttributes().length > 0) {
    299             attributeSources.add(fqcn);
    300         }
    301 
    302         for (ViewClassInfo link = info.getSuperClass();
    303                 link != null;
    304                 link = link.getSuperClass()) {
    305             AttributeInfo[] attrList = link.getAttributes();
    306             if (attrList.length > 0) {
    307                 attributeSources.add(link.getFullClassName());
    308                 DescriptorsUtils.appendAttributes(attributes,
    309                         null, // elementName
    310                         SdkConstants.NS_RESOURCES,
    311                         attrList,
    312                         null, // requiredAttributes
    313                         null /* overrides */);
    314             }
    315         }
    316 
    317         // Process all LayoutParams attributes
    318         ArrayList<AttributeDescriptor> layoutAttributes = new ArrayList<AttributeDescriptor>();
    319         LayoutParamsInfo layoutParams = info.getLayoutData();
    320 
    321         for(; layoutParams != null; layoutParams = layoutParams.getSuperClass()) {
    322             for (AttributeInfo attrInfo : layoutParams.getAttributes()) {
    323                 if (DescriptorsUtils.containsAttribute(layoutAttributes,
    324                         SdkConstants.NS_RESOURCES, attrInfo)) {
    325                     continue;
    326                 }
    327                 DescriptorsUtils.appendAttribute(layoutAttributes,
    328                         null, // elementName
    329                         SdkConstants.NS_RESOURCES,
    330                         attrInfo,
    331                         false, // required
    332                         null /* overrides */);
    333             }
    334         }
    335 
    336         ViewElementDescriptor desc = new ViewElementDescriptor(
    337                 xmlName,
    338                 uiName,
    339                 fqcn,
    340                 tooltip,
    341                 null, // sdk_url
    342                 attributes.toArray(new AttributeDescriptor[attributes.size()]),
    343                 layoutAttributes.toArray(new AttributeDescriptor[layoutAttributes.size()]),
    344                 null, // children
    345                 false /* mandatory */);
    346         desc.setAttributeSources(Collections.unmodifiableList(attributeSources));
    347         infoDescMap.put(info, desc);
    348         return desc;
    349     }
    350 
    351     /**
    352      * Creates a new <include> descriptor and adds it to the list of view descriptors.
    353      *
    354      * @param knownViews A list of view descriptors being populated. Also used to find the
    355      *   View descriptor and extract its layout attributes.
    356      */
    357     private void insertInclude(List<ViewElementDescriptor> knownViews) {
    358         String xmlName = VIEW_INCLUDE;
    359 
    360         // Create the include custom attributes
    361         ArrayList<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>();
    362 
    363         // Note that the "layout" attribute does NOT have the Android namespace
    364         DescriptorsUtils.appendAttribute(attributes,
    365                 null, //elementXmlName
    366                 null, //nsUri
    367                 new AttributeInfo(
    368                         ATTR_LAYOUT,
    369                         Format.REFERENCE_SET ),
    370                 true,  //required
    371                 null); //overrides
    372 
    373         DescriptorsUtils.appendAttribute(attributes,
    374                 null, //elementXmlName
    375                 SdkConstants.NS_RESOURCES, //nsUri
    376                 new AttributeInfo(
    377                         "id",           //$NON-NLS-1$
    378                         Format.REFERENCE_SET ),
    379                 true,  //required
    380                 null); //overrides
    381 
    382         // Find View and inherit all its layout attributes
    383         AttributeDescriptor[] viewLayoutAttribs = findViewLayoutAttributes(
    384                 SdkConstants.CLASS_VIEW);
    385 
    386         // Create the include descriptor
    387         ViewElementDescriptor desc = new ViewElementDescriptor(xmlName,
    388                 xmlName, // ui_name
    389                 VIEW_INCLUDE, // "class name"; the GLE only treats this as an element tag
    390                 "Lets you statically include XML layouts inside other XML layouts.",  // tooltip
    391                 null, // sdk_url
    392                 attributes.toArray(new AttributeDescriptor[attributes.size()]),
    393                 viewLayoutAttribs,  // layout attributes
    394                 null, // children
    395                 false /* mandatory */);
    396 
    397         knownViews.add(desc);
    398     }
    399 
    400     /**
    401      * Creates and returns a new {@code <merge>} descriptor.
    402      * @param viewLayoutAttribs The layout attributes to use for the new descriptor
    403      */
    404     private ViewElementDescriptor createMerge(AttributeDescriptor[] viewLayoutAttribs) {
    405         String xmlName = VIEW_MERGE;
    406 
    407         // Create the include descriptor
    408         ViewElementDescriptor desc = new ViewElementDescriptor(xmlName,
    409                 xmlName, // ui_name
    410                 VIEW_MERGE, // "class name"; the GLE only treats this as an element tag
    411                 "A root tag useful for XML layouts inflated using a ViewStub.",  // tooltip
    412                 null,  // sdk_url
    413                 null,  // attributes
    414                 viewLayoutAttribs,  // layout attributes
    415                 null,  // children
    416                 false  /* mandatory */);
    417 
    418         return desc;
    419     }
    420 
    421     /**
    422      * Creates and returns a new {@code <fragment>} descriptor.
    423      * @param viewLayoutAttribs The layout attributes to use for the new descriptor
    424      * @param styleMap The style map provided by the SDK
    425      */
    426     private ViewElementDescriptor createFragment(AttributeDescriptor[] viewLayoutAttribs,
    427             Map<String, DeclareStyleableInfo> styleMap) {
    428         String xmlName = VIEW_FRAGMENT;
    429         final ViewElementDescriptor descriptor;
    430 
    431         // First try to create the descriptor from metadata in attrs.xml:
    432         DeclareStyleableInfo style = styleMap.get("Fragment"); //$NON-NLS-1$
    433         String fragmentTooltip =
    434             "A Fragment is a piece of an application's user interface or behavior that "
    435             + "can be placed in an Activity";
    436         String sdkUrl = "http://developer.android.com/guide/topics/fundamentals/fragments.html";
    437         TextAttributeDescriptor classAttribute = new ClassAttributeDescriptor(
    438                 // Should accept both CLASS_V4_FRAGMENT and CLASS_FRAGMENT
    439                 null /*superClassName*/,
    440                 ATTR_CLASS, null /* namespace */,
    441                 new AttributeInfo(ATTR_CLASS, Format.STRING_SET),
    442                 true /*mandatory*/)
    443                 .setTooltip("Supply the name of the fragment class to instantiate");
    444 
    445         if (style != null) {
    446             descriptor = new ViewElementDescriptor(
    447                     VIEW_FRAGMENT, VIEW_FRAGMENT, VIEW_FRAGMENT,
    448                     fragmentTooltip,  // tooltip
    449                     sdkUrl, //,
    450                     null /* attributes */,
    451                     viewLayoutAttribs, // layout attributes
    452                     null /*childrenElements*/,
    453                     false /*mandatory*/);
    454             ArrayList<AttributeDescriptor> descs = new ArrayList<AttributeDescriptor>();
    455             // The class attribute is not included in the attrs.xml
    456             descs.add(classAttribute);
    457             DescriptorsUtils.appendAttributes(descs,
    458                     null,   // elementName
    459                     SdkConstants.NS_RESOURCES,
    460                     style.getAttributes(),
    461                     null,   // requiredAttributes
    462                     null);  // overrides
    463             //descriptor.setTooltip(style.getJavaDoc());
    464             descriptor.setAttributes(descs.toArray(new AttributeDescriptor[descs.size()]));
    465         } else {
    466             // The above will only work on API 11 and up. However, fragments are *also* available
    467             // on older platforms, via the fragment support library, so add in a manual
    468             // entry if necessary.
    469             descriptor = new ViewElementDescriptor(xmlName,
    470                 xmlName, // ui_name
    471                 xmlName, // "class name"; the GLE only treats this as an element tag
    472                 fragmentTooltip,
    473                 sdkUrl,
    474                 new AttributeDescriptor[] {
    475                     new ClassAttributeDescriptor(
    476                             null /*superClassName*/,
    477                             ATTR_NAME, ANDROID_URI,
    478                             new AttributeInfo(ATTR_NAME, Format.STRING_SET),
    479                             true /*mandatory*/)
    480                             .setTooltip("Supply the name of the fragment class to instantiate"),
    481                     classAttribute,
    482                     new ClassAttributeDescriptor(
    483                             null /*superClassName*/,
    484                             ATTR_TAG, ANDROID_URI,
    485                             new AttributeInfo(ATTR_TAG, Format.STRING_SET),
    486                             true /*mandatory*/)
    487                             .setTooltip("Supply a tag for the top-level view containing a String"),
    488                 }, // attributes
    489                 viewLayoutAttribs,  // layout attributes
    490                 null,  // children
    491                 false  /* mandatory */);
    492         }
    493 
    494         return descriptor;
    495     }
    496 
    497     /**
    498      * Creates and returns a new {@code <requestFocus>} descriptor.
    499      */
    500     private ViewElementDescriptor createRequestFocus() {
    501         String xmlName = REQUEST_FOCUS;
    502 
    503         // Create the include descriptor
    504         return new ViewElementDescriptor(
    505                 xmlName,  // xml_name
    506                 xmlName, // ui_name
    507                 xmlName, // "class name"; the GLE only treats this as an element tag
    508                 "Requests focus for the parent element or one of its descendants", // tooltip
    509                 null,  // sdk_url
    510                 null,  // attributes
    511                 null,  // layout attributes
    512                 null,  // children
    513                 false  /* mandatory */);
    514     }
    515 
    516     /**
    517      * Finds the descriptor and retrieves all its layout attributes.
    518      */
    519     private AttributeDescriptor[] findViewLayoutAttributes(
    520             String viewFqcn) {
    521         ViewElementDescriptor viewDesc = findDescriptorByClass(viewFqcn);
    522         if (viewDesc != null) {
    523             return viewDesc.getLayoutAttributes();
    524         }
    525 
    526         return null;
    527     }
    528 
    529     /**
    530      * Set the super-class of each {@link ViewElementDescriptor} by using the super-class
    531      * information available in the {@link ViewClassInfo}.
    532      */
    533     private void fixSuperClasses(Map<ViewClassInfo, ViewElementDescriptor> infoDescMap) {
    534 
    535         for (Entry<ViewClassInfo, ViewElementDescriptor> entry : infoDescMap.entrySet()) {
    536             ViewClassInfo info = entry.getKey();
    537             ViewElementDescriptor desc = entry.getValue();
    538 
    539             ViewClassInfo sup = info.getSuperClass();
    540             if (sup != null) {
    541                 ViewElementDescriptor supDesc = infoDescMap.get(sup);
    542                 while (supDesc == null && sup != null) {
    543                     // We don't have a descriptor for the super-class. That means the class is
    544                     // probably abstract, so we just need to walk up the super-class chain till
    545                     // we find one we have. All views derive from android.view.View so we should
    546                     // surely find that eventually.
    547                     sup = sup.getSuperClass();
    548                     if (sup != null) {
    549                         supDesc = infoDescMap.get(sup);
    550                     }
    551                 }
    552                 if (supDesc != null) {
    553                     desc.setSuperClass(supDesc);
    554                 }
    555             }
    556         }
    557     }
    558 
    559     /**
    560      * Returns the {@link ViewElementDescriptor} with the given fully qualified class
    561      * name, or null if not found. This is a quick map lookup.
    562      *
    563      * @param fqcn the fully qualified class name
    564      * @return the corresponding {@link ViewElementDescriptor} or null
    565      */
    566     public ViewElementDescriptor findDescriptorByClass(String fqcn) {
    567         return mFqcnToDescriptor.get(fqcn);
    568     }
    569 
    570     /**
    571      * Returns the {@link ViewElementDescriptor} with the given XML tag name,
    572      * which usually does not include the package (depending on the
    573      * value of {@link ViewElementDescriptor#viewNeedsPackage(String)}).
    574      *
    575      * @param tag the XML tag name
    576      * @return the corresponding {@link ViewElementDescriptor} or null
    577      */
    578     public ViewElementDescriptor findDescriptorByTag(String tag) {
    579         // TODO: Consider whether we need to add a direct map lookup for this as well.
    580         // Currently not done since this is not frequently needed (only needed for
    581         // exploded rendering which was already performing list iteration.)
    582         for (ViewElementDescriptor descriptor : mLayoutDescriptors) {
    583             if (tag.equals(descriptor.getXmlLocalName())) {
    584                 return descriptor;
    585             }
    586         }
    587 
    588         return null;
    589     }
    590 
    591     /**
    592      * Returns a collection of all the view class names, including layouts
    593      *
    594      * @return a collection of all the view class names, never null
    595      */
    596     public Collection<String> getAllViewClassNames() {
    597         return mFqcnToDescriptor.keySet();
    598     }
    599 }
    600