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