blob: 34a0c0359707748251622fec7ff40f279b3e4200 [file] [log] [blame]
The Android Open Source Project88b60792009-03-03 19:28:42 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
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
17import com.sun.javadoc.*;
18
19import org.clearsilver.HDF;
20
21import java.util.*;
22import java.io.*;
23import java.lang.reflect.Proxy;
24import java.lang.reflect.Array;
25import java.lang.reflect.InvocationHandler;
26import java.lang.reflect.InvocationTargetException;
27import java.lang.reflect.Method;
28
29public class DroidDoc
30{
31 private static final String SDK_CONSTANT_ANNOTATION = "android.annotation.SdkConstant";
32 private static final String SDK_CONSTANT_TYPE_ACTIVITY_ACTION = "android.annotation.SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION";
33 private static final String SDK_CONSTANT_TYPE_BROADCAST_ACTION = "android.annotation.SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION";
34 private static final String SDK_CONSTANT_TYPE_SERVICE_ACTION = "android.annotation.SdkConstant.SdkConstantType.SERVICE_INTENT_ACTION";
35 private static final String SDK_CONSTANT_TYPE_CATEGORY = "android.annotation.SdkConstant.SdkConstantType.INTENT_CATEGORY";
Xavier Ducrohetf9b6d382009-12-14 17:55:05 -080036 private static final String SDK_CONSTANT_TYPE_FEATURE = "android.annotation.SdkConstant.SdkConstantType.FEATURE";
The Android Open Source Project88b60792009-03-03 19:28:42 -080037 private static final String SDK_WIDGET_ANNOTATION = "android.annotation.Widget";
38 private static final String SDK_LAYOUT_ANNOTATION = "android.annotation.Layout";
39
40 private static final int TYPE_NONE = 0;
41 private static final int TYPE_WIDGET = 1;
42 private static final int TYPE_LAYOUT = 2;
43 private static final int TYPE_LAYOUT_PARAM = 3;
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -070044
The Android Open Source Project88b60792009-03-03 19:28:42 -080045 public static final int SHOW_PUBLIC = 0x00000001;
46 public static final int SHOW_PROTECTED = 0x00000003;
47 public static final int SHOW_PACKAGE = 0x00000007;
48 public static final int SHOW_PRIVATE = 0x0000000f;
49 public static final int SHOW_HIDDEN = 0x0000001f;
50
51 public static int showLevel = SHOW_PROTECTED;
52
53 public static final String javadocDir = "reference/";
54 public static String htmlExtension;
55
56 public static RootDoc root;
57 public static ArrayList<String[]> mHDFData = new ArrayList<String[]>();
58 public static Map<Character,String> escapeChars = new HashMap<Character,String>();
59 public static String title = "";
Scott Main25fda192009-08-04 11:26:30 -070060 public static SinceTagger sinceTagger = new SinceTagger();
The Android Open Source Project88b60792009-03-03 19:28:42 -080061
62 public static boolean checkLevel(int level)
63 {
64 return (showLevel & level) == level;
65 }
66
67 public static boolean checkLevel(boolean pub, boolean prot, boolean pkgp,
68 boolean priv, boolean hidden)
69 {
70 int level = 0;
71 if (hidden && !checkLevel(SHOW_HIDDEN)) {
72 return false;
73 }
74 if (pub && checkLevel(SHOW_PUBLIC)) {
75 return true;
76 }
77 if (prot && checkLevel(SHOW_PROTECTED)) {
78 return true;
79 }
80 if (pkgp && checkLevel(SHOW_PACKAGE)) {
81 return true;
82 }
83 if (priv && checkLevel(SHOW_PRIVATE)) {
84 return true;
85 }
86 return false;
87 }
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -070088
The Android Open Source Project88b60792009-03-03 19:28:42 -080089 public static boolean start(RootDoc r)
90 {
91 String keepListFile = null;
92 String proofreadFile = null;
93 String todoFile = null;
94 String sdkValuePath = null;
95 ArrayList<SampleCode> sampleCodes = new ArrayList<SampleCode>();
96 String stubsDir = null;
97 //Create the dependency graph for the stubs directory
98 boolean apiXML = false;
Joe Onoratob7c41aa2009-07-20 11:57:59 -040099 boolean noDocs = false;
Scott Main2fa99f12009-11-20 10:41:49 -0800100 boolean offlineMode = false;
The Android Open Source Project88b60792009-03-03 19:28:42 -0800101 String apiFile = null;
102 String debugStubsFile = "";
103 HashSet<String> stubPackages = null;
104
105 root = r;
106
107 String[][] options = r.options();
108 for (String[] a: options) {
109 if (a[0].equals("-d")) {
110 ClearPage.outputDir = a[1];
111 }
112 else if (a[0].equals("-templatedir")) {
113 ClearPage.addTemplateDir(a[1]);
114 }
115 else if (a[0].equals("-hdf")) {
116 mHDFData.add(new String[] {a[1], a[2]});
117 }
118 else if (a[0].equals("-toroot")) {
119 ClearPage.toroot = a[1];
120 }
121 else if (a[0].equals("-samplecode")) {
122 sampleCodes.add(new SampleCode(a[1], a[2], a[3]));
123 }
124 else if (a[0].equals("-htmldir")) {
Bill Napier0e143c02010-08-24 22:16:01 -0700125 ClearPage.htmlDirs.add(a[1]);
The Android Open Source Project88b60792009-03-03 19:28:42 -0800126 }
127 else if (a[0].equals("-title")) {
128 DroidDoc.title = a[1];
129 }
130 else if (a[0].equals("-werror")) {
131 Errors.setWarningsAreErrors(true);
132 }
133 else if (a[0].equals("-error") || a[0].equals("-warning")
134 || a[0].equals("-hide")) {
135 try {
136 int level = -1;
137 if (a[0].equals("-error")) {
138 level = Errors.ERROR;
139 }
140 else if (a[0].equals("-warning")) {
141 level = Errors.WARNING;
142 }
143 else if (a[0].equals("-hide")) {
144 level = Errors.HIDDEN;
145 }
146 Errors.setErrorLevel(Integer.parseInt(a[1]), level);
147 }
148 catch (NumberFormatException e) {
149 // already printed below
150 return false;
151 }
152 }
153 else if (a[0].equals("-keeplist")) {
154 keepListFile = a[1];
155 }
156 else if (a[0].equals("-proofread")) {
157 proofreadFile = a[1];
158 }
159 else if (a[0].equals("-todo")) {
160 todoFile = a[1];
161 }
162 else if (a[0].equals("-public")) {
163 showLevel = SHOW_PUBLIC;
164 }
165 else if (a[0].equals("-protected")) {
166 showLevel = SHOW_PROTECTED;
167 }
168 else if (a[0].equals("-package")) {
169 showLevel = SHOW_PACKAGE;
170 }
171 else if (a[0].equals("-private")) {
172 showLevel = SHOW_PRIVATE;
173 }
174 else if (a[0].equals("-hidden")) {
175 showLevel = SHOW_HIDDEN;
176 }
177 else if (a[0].equals("-stubs")) {
178 stubsDir = a[1];
179 }
180 else if (a[0].equals("-stubpackages")) {
181 stubPackages = new HashSet();
182 for (String pkg: a[1].split(":")) {
183 stubPackages.add(pkg);
184 }
185 }
186 else if (a[0].equals("-sdkvalues")) {
187 sdkValuePath = a[1];
188 }
189 else if (a[0].equals("-apixml")) {
190 apiXML = true;
191 apiFile = a[1];
192 }
Joe Onoratob7c41aa2009-07-20 11:57:59 -0400193 else if (a[0].equals("-nodocs")) {
194 noDocs = true;
195 }
Jesse Wilson5e0dd412009-06-01 17:59:44 -0700196 else if (a[0].equals("-since")) {
197 sinceTagger.addVersion(a[1], a[2]);
198 }
Scott Main2fa99f12009-11-20 10:41:49 -0800199 else if (a[0].equals("-offlinemode")) {
200 offlineMode = true;
201 }
The Android Open Source Project88b60792009-03-03 19:28:42 -0800202 }
203
204 // read some prefs from the template
205 if (!readTemplateSettings()) {
206 return false;
207 }
208
209 // Set up the data structures
210 Converter.makeInfo(r);
211
Joe Onoratob7c41aa2009-07-20 11:57:59 -0400212 if (!noDocs) {
213 long startTime = System.nanoTime();
214
Jesse Wilson5e0dd412009-06-01 17:59:44 -0700215 // Apply @since tags from the XML file
216 sinceTagger.tagAll(Converter.rootClasses());
217
Joe Onoratob7c41aa2009-07-20 11:57:59 -0400218 // Files for proofreading
219 if (proofreadFile != null) {
220 Proofread.initProofread(proofreadFile);
221 }
222 if (todoFile != null) {
223 TodoFile.writeTodoFile(todoFile);
224 }
225
226 // HTML Pages
Bill Napier0e143c02010-08-24 22:16:01 -0700227 if (!ClearPage.htmlDirs.isEmpty()) {
Joe Onoratob7c41aa2009-07-20 11:57:59 -0400228 writeHTMLPages();
229 }
230
231 // Navigation tree
232 NavTree.writeNavTree(javadocDir);
233
234 // Packages Pages
235 writePackages(javadocDir
Bill Napier0e143c02010-08-24 22:16:01 -0700236 + (!ClearPage.htmlDirs.isEmpty()
Joe Onoratob7c41aa2009-07-20 11:57:59 -0400237 ? "packages" + htmlExtension
238 : "index" + htmlExtension));
239
240 // Classes
241 writeClassLists();
242 writeClasses();
243 writeHierarchy();
244 // writeKeywords();
245
246 // Lists for JavaScript
247 writeLists();
248 if (keepListFile != null) {
249 writeKeepList(keepListFile);
250 }
251
252 // Sample Code
253 for (SampleCode sc: sampleCodes) {
Scott Main2fa99f12009-11-20 10:41:49 -0800254 sc.write(offlineMode);
Joe Onoratob7c41aa2009-07-20 11:57:59 -0400255 }
256
257 // Index page
258 writeIndex();
259
260 Proofread.finishProofread(proofreadFile);
261
262 if (sdkValuePath != null) {
263 writeSdkValues(sdkValuePath);
264 }
265
266 long time = System.nanoTime() - startTime;
267 System.out.println("DroidDoc took " + (time / 1000000000) + " sec. to write docs to "
268 + ClearPage.outputDir);
The Android Open Source Project88b60792009-03-03 19:28:42 -0800269 }
The Android Open Source Project88b60792009-03-03 19:28:42 -0800270
271 // Stubs
272 if (stubsDir != null) {
273 Stubs.writeStubs(stubsDir, apiXML, apiFile, stubPackages);
274 }
Jesse Wilson5e0dd412009-06-01 17:59:44 -0700275
The Android Open Source Project88b60792009-03-03 19:28:42 -0800276 Errors.printErrors();
277 return !Errors.hadError;
278 }
279
280 private static void writeIndex() {
281 HDF data = makeHDF();
282 ClearPage.write(data, "index.cs", javadocDir + "index" + htmlExtension);
283 }
284
285 private static boolean readTemplateSettings()
286 {
287 HDF data = makeHDF();
288 htmlExtension = data.getValue("template.extension", ".html");
289 int i=0;
290 while (true) {
291 String k = data.getValue("template.escape." + i + ".key", "");
292 String v = data.getValue("template.escape." + i + ".value", "");
293 if ("".equals(k)) {
294 break;
295 }
296 if (k.length() != 1) {
297 System.err.println("template.escape." + i + ".key must have a length of 1: " + k);
298 return false;
299 }
300 escapeChars.put(k.charAt(0), v);
301 i++;
302 }
303 return true;
304 }
305
306 public static String escape(String s) {
307 if (escapeChars.size() == 0) {
308 return s;
309 }
310 StringBuffer b = null;
311 int begin = 0;
312 final int N = s.length();
313 for (int i=0; i<N; i++) {
314 char c = s.charAt(i);
315 String mapped = escapeChars.get(c);
316 if (mapped != null) {
317 if (b == null) {
318 b = new StringBuffer(s.length() + mapped.length());
319 }
320 if (begin != i) {
321 b.append(s.substring(begin, i));
322 }
323 b.append(mapped);
324 begin = i+1;
325 }
326 }
327 if (b != null) {
328 if (begin != N) {
329 b.append(s.substring(begin, N));
330 }
331 return b.toString();
332 }
333 return s;
334 }
335
336 public static void setPageTitle(HDF data, String title)
337 {
338 String s = title;
339 if (DroidDoc.title.length() > 0) {
340 s += " - " + DroidDoc.title;
341 }
342 data.setValue("page.title", s);
343 }
344
345 public static LanguageVersion languageVersion()
346 {
347 return LanguageVersion.JAVA_1_5;
348 }
349
350 public static int optionLength(String option)
351 {
352 if (option.equals("-d")) {
353 return 2;
354 }
355 if (option.equals("-templatedir")) {
356 return 2;
357 }
358 if (option.equals("-hdf")) {
359 return 3;
360 }
361 if (option.equals("-toroot")) {
362 return 2;
363 }
364 if (option.equals("-samplecode")) {
365 return 4;
366 }
367 if (option.equals("-htmldir")) {
368 return 2;
369 }
370 if (option.equals("-title")) {
371 return 2;
372 }
373 if (option.equals("-werror")) {
374 return 1;
375 }
376 if (option.equals("-hide")) {
377 return 2;
378 }
379 if (option.equals("-warning")) {
380 return 2;
381 }
382 if (option.equals("-error")) {
383 return 2;
384 }
385 if (option.equals("-keeplist")) {
386 return 2;
387 }
388 if (option.equals("-proofread")) {
389 return 2;
390 }
391 if (option.equals("-todo")) {
392 return 2;
393 }
394 if (option.equals("-public")) {
395 return 1;
396 }
397 if (option.equals("-protected")) {
398 return 1;
399 }
400 if (option.equals("-package")) {
401 return 1;
402 }
403 if (option.equals("-private")) {
404 return 1;
405 }
406 if (option.equals("-hidden")) {
407 return 1;
408 }
409 if (option.equals("-stubs")) {
410 return 2;
411 }
412 if (option.equals("-stubpackages")) {
413 return 2;
414 }
415 if (option.equals("-sdkvalues")) {
416 return 2;
417 }
418 if (option.equals("-apixml")) {
419 return 2;
420 }
Joe Onoratob7c41aa2009-07-20 11:57:59 -0400421 if (option.equals("-nodocs")) {
422 return 1;
423 }
Jesse Wilson5e0dd412009-06-01 17:59:44 -0700424 if (option.equals("-since")) {
425 return 3;
426 }
Scott Main2fa99f12009-11-20 10:41:49 -0800427 if (option.equals("-offlinemode")) {
428 return 1;
429 }
The Android Open Source Project88b60792009-03-03 19:28:42 -0800430 return 0;
431 }
Jesse Wilson5e0dd412009-06-01 17:59:44 -0700432
The Android Open Source Project88b60792009-03-03 19:28:42 -0800433 public static boolean validOptions(String[][] options, DocErrorReporter r)
434 {
435 for (String[] a: options) {
436 if (a[0].equals("-error") || a[0].equals("-warning")
437 || a[0].equals("-hide")) {
438 try {
439 Integer.parseInt(a[1]);
440 }
441 catch (NumberFormatException e) {
442 r.printError("bad -" + a[0] + " value must be a number: "
443 + a[1]);
444 return false;
445 }
446 }
447 }
448
449 return true;
450 }
451
452 public static HDF makeHDF()
453 {
454 HDF data = new HDF();
455
456 for (String[] p: mHDFData) {
457 data.setValue(p[0], p[1]);
458 }
459
460 try {
461 for (String p: ClearPage.hdfFiles) {
462 data.readFile(p);
463 }
464 }
465 catch (IOException e) {
466 throw new RuntimeException(e);
467 }
468
469 return data;
470 }
471
472 public static HDF makePackageHDF()
473 {
474 HDF data = makeHDF();
475 ClassInfo[] classes = Converter.rootClasses();
476
477 SortedMap<String, PackageInfo> sorted = new TreeMap<String, PackageInfo>();
478 for (ClassInfo cl: classes) {
479 PackageInfo pkg = cl.containingPackage();
480 String name;
481 if (pkg == null) {
482 name = "";
483 } else {
484 name = pkg.name();
485 }
486 sorted.put(name, pkg);
487 }
488
489 int i = 0;
490 for (String s: sorted.keySet()) {
491 PackageInfo pkg = sorted.get(s);
492
493 if (pkg.isHidden()) {
494 continue;
495 }
496 Boolean allHidden = true;
497 int pass = 0;
498 ClassInfo[] classesToCheck = null;
499 while (pass < 5 ) {
500 switch(pass) {
501 case 0:
502 classesToCheck = pkg.ordinaryClasses();
503 break;
504 case 1:
505 classesToCheck = pkg.enums();
506 break;
507 case 2:
508 classesToCheck = pkg.errors();
509 break;
510 case 3:
511 classesToCheck = pkg.exceptions();
512 break;
513 case 4:
514 classesToCheck = pkg.interfaces();
515 break;
516 default:
517 System.err.println("Error reading package: " + pkg.name());
518 break;
519 }
520 for (ClassInfo cl : classesToCheck) {
521 if (!cl.isHidden()) {
522 allHidden = false;
523 break;
524 }
525 }
526 if (!allHidden) {
527 break;
528 }
529 pass++;
530 }
531 if (allHidden) {
532 continue;
533 }
534
535 data.setValue("reference", "true");
536 data.setValue("docs.packages." + i + ".name", s);
537 data.setValue("docs.packages." + i + ".link", pkg.htmlPage());
Scott Maindf094242009-07-27 09:47:11 -0700538 data.setValue("docs.packages." + i + ".since", pkg.getSince());
The Android Open Source Project88b60792009-03-03 19:28:42 -0800539 TagInfo.makeHDF(data, "docs.packages." + i + ".shortDescr",
540 pkg.firstSentenceTags());
541 i++;
542 }
543
Scott Main25fda192009-08-04 11:26:30 -0700544 sinceTagger.writeVersionNames(data);
The Android Open Source Project88b60792009-03-03 19:28:42 -0800545 return data;
546 }
547
548 public static void writeDirectory(File dir, String relative)
549 {
550 File[] files = dir.listFiles();
551 int i, count = files.length;
552 for (i=0; i<count; i++) {
553 File f = files[i];
554 if (f.isFile()) {
555 String templ = relative + f.getName();
556 int len = templ.length();
557 if (len > 3 && ".cs".equals(templ.substring(len-3))) {
558 HDF data = makeHDF();
559 String filename = templ.substring(0,len-3) + htmlExtension;
560 ClearPage.write(data, templ, filename);
561 }
562 else if (len > 3 && ".jd".equals(templ.substring(len-3))) {
563 String filename = templ.substring(0,len-3) + htmlExtension;
564 DocFile.writePage(f.getAbsolutePath(), relative, filename);
565 }
566 else {
567 ClearPage.copyFile(f, templ);
568 }
569 }
570 else if (f.isDirectory()) {
571 writeDirectory(f, relative + f.getName() + "/");
572 }
573 }
574 }
575
576 public static void writeHTMLPages()
577 {
Bill Napier0e143c02010-08-24 22:16:01 -0700578 for (String htmlDir : ClearPage.htmlDirs) {
579 File f = new File(htmlDir);
580 if (!f.isDirectory()) {
581 System.err.println("htmlDir not a directory: " + htmlDir);
582 }
583 writeDirectory(f, "");
The Android Open Source Project88b60792009-03-03 19:28:42 -0800584 }
The Android Open Source Project88b60792009-03-03 19:28:42 -0800585 }
586
587 public static void writeLists()
588 {
589 HDF data = makeHDF();
590
591 ClassInfo[] classes = Converter.rootClasses();
592
593 SortedMap<String, Object> sorted = new TreeMap<String, Object>();
594 for (ClassInfo cl: classes) {
595 if (cl.isHidden()) {
596 continue;
597 }
598 sorted.put(cl.qualifiedName(), cl);
599 PackageInfo pkg = cl.containingPackage();
600 String name;
601 if (pkg == null) {
602 name = "";
603 } else {
604 name = pkg.name();
605 }
606 sorted.put(name, pkg);
607 }
608
609 int i = 0;
610 for (String s: sorted.keySet()) {
611 data.setValue("docs.pages." + i + ".id" , ""+i);
612 data.setValue("docs.pages." + i + ".label" , s);
613
614 Object o = sorted.get(s);
615 if (o instanceof PackageInfo) {
616 PackageInfo pkg = (PackageInfo)o;
617 data.setValue("docs.pages." + i + ".link" , pkg.htmlPage());
618 data.setValue("docs.pages." + i + ".type" , "package");
619 }
620 else if (o instanceof ClassInfo) {
621 ClassInfo cl = (ClassInfo)o;
622 data.setValue("docs.pages." + i + ".link" , cl.htmlPage());
623 data.setValue("docs.pages." + i + ".type" , "class");
624 }
625 i++;
626 }
627
628 ClearPage.write(data, "lists.cs", javadocDir + "lists.js");
629 }
630
631 public static void cantStripThis(ClassInfo cl, HashSet<ClassInfo> notStrippable) {
632 if (!notStrippable.add(cl)) {
633 // slight optimization: if it already contains cl, it already contains
634 // all of cl's parents
635 return;
636 }
637 ClassInfo supr = cl.superclass();
638 if (supr != null) {
639 cantStripThis(supr, notStrippable);
640 }
641 for (ClassInfo iface: cl.interfaces()) {
642 cantStripThis(iface, notStrippable);
643 }
644 }
645
646 private static String getPrintableName(ClassInfo cl) {
647 ClassInfo containingClass = cl.containingClass();
648 if (containingClass != null) {
649 // This is an inner class.
650 String baseName = cl.name();
651 baseName = baseName.substring(baseName.lastIndexOf('.') + 1);
652 return getPrintableName(containingClass) + '$' + baseName;
653 }
654 return cl.qualifiedName();
655 }
656
657 /**
658 * Writes the list of classes that must be present in order to
659 * provide the non-hidden APIs known to javadoc.
660 *
661 * @param filename the path to the file to write the list to
662 */
663 public static void writeKeepList(String filename) {
664 HashSet<ClassInfo> notStrippable = new HashSet<ClassInfo>();
665 ClassInfo[] all = Converter.allClasses();
666 Arrays.sort(all); // just to make the file a little more readable
667
668 // If a class is public and not hidden, then it and everything it derives
669 // from cannot be stripped. Otherwise we can strip it.
670 for (ClassInfo cl: all) {
671 if (cl.isPublic() && !cl.isHidden()) {
672 cantStripThis(cl, notStrippable);
673 }
674 }
675 PrintStream stream = null;
676 try {
677 stream = new PrintStream(filename);
678 for (ClassInfo cl: notStrippable) {
679 stream.println(getPrintableName(cl));
680 }
681 }
682 catch (FileNotFoundException e) {
683 System.err.println("error writing file: " + filename);
684 }
685 finally {
686 if (stream != null) {
687 stream.close();
688 }
689 }
690 }
691
692 private static PackageInfo[] sVisiblePackages = null;
693 public static PackageInfo[] choosePackages() {
694 if (sVisiblePackages != null) {
695 return sVisiblePackages;
696 }
697
698 ClassInfo[] classes = Converter.rootClasses();
699 SortedMap<String, PackageInfo> sorted = new TreeMap<String, PackageInfo>();
700 for (ClassInfo cl: classes) {
701 PackageInfo pkg = cl.containingPackage();
702 String name;
703 if (pkg == null) {
704 name = "";
705 } else {
706 name = pkg.name();
707 }
708 sorted.put(name, pkg);
709 }
710
711 ArrayList<PackageInfo> result = new ArrayList();
712
713 for (String s: sorted.keySet()) {
714 PackageInfo pkg = sorted.get(s);
715
716 if (pkg.isHidden()) {
717 continue;
718 }
719 Boolean allHidden = true;
720 int pass = 0;
721 ClassInfo[] classesToCheck = null;
722 while (pass < 5 ) {
723 switch(pass) {
724 case 0:
725 classesToCheck = pkg.ordinaryClasses();
726 break;
727 case 1:
728 classesToCheck = pkg.enums();
729 break;
730 case 2:
731 classesToCheck = pkg.errors();
732 break;
733 case 3:
734 classesToCheck = pkg.exceptions();
735 break;
736 case 4:
737 classesToCheck = pkg.interfaces();
738 break;
739 default:
740 System.err.println("Error reading package: " + pkg.name());
741 break;
742 }
743 for (ClassInfo cl : classesToCheck) {
744 if (!cl.isHidden()) {
745 allHidden = false;
746 break;
747 }
748 }
749 if (!allHidden) {
750 break;
751 }
752 pass++;
753 }
754 if (allHidden) {
755 continue;
756 }
757
758 result.add(pkg);
759 }
760
761 sVisiblePackages = result.toArray(new PackageInfo[result.size()]);
762 return sVisiblePackages;
763 }
764
765 public static void writePackages(String filename)
766 {
767 HDF data = makePackageHDF();
768
769 int i = 0;
770 for (PackageInfo pkg: choosePackages()) {
771 writePackage(pkg);
772
773 data.setValue("docs.packages." + i + ".name", pkg.name());
774 data.setValue("docs.packages." + i + ".link", pkg.htmlPage());
775 TagInfo.makeHDF(data, "docs.packages." + i + ".shortDescr",
776 pkg.firstSentenceTags());
777
778 i++;
779 }
780
781 setPageTitle(data, "Package Index");
782
783 TagInfo.makeHDF(data, "root.descr",
784 Converter.convertTags(root.inlineTags(), null));
785
786 ClearPage.write(data, "packages.cs", filename);
787 ClearPage.write(data, "package-list.cs", javadocDir + "package-list");
788
789 Proofread.writePackages(filename,
790 Converter.convertTags(root.inlineTags(), null));
791 }
792
793 public static void writePackage(PackageInfo pkg)
794 {
795 // these this and the description are in the same directory,
796 // so it's okay
797 HDF data = makePackageHDF();
798
799 String name = pkg.name();
800
801 data.setValue("package.name", name);
Jesse Wilson5e0dd412009-06-01 17:59:44 -0700802 data.setValue("package.since", pkg.getSince());
The Android Open Source Project88b60792009-03-03 19:28:42 -0800803 data.setValue("package.descr", "...description...");
804
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -0700805 makeClassListHDF(data, "package.interfaces",
The Android Open Source Project88b60792009-03-03 19:28:42 -0800806 ClassInfo.sortByName(pkg.interfaces()));
807 makeClassListHDF(data, "package.classes",
808 ClassInfo.sortByName(pkg.ordinaryClasses()));
809 makeClassListHDF(data, "package.enums",
810 ClassInfo.sortByName(pkg.enums()));
811 makeClassListHDF(data, "package.exceptions",
812 ClassInfo.sortByName(pkg.exceptions()));
813 makeClassListHDF(data, "package.errors",
814 ClassInfo.sortByName(pkg.errors()));
815 TagInfo.makeHDF(data, "package.shortDescr",
816 pkg.firstSentenceTags());
817 TagInfo.makeHDF(data, "package.descr", pkg.inlineTags());
818
819 String filename = pkg.htmlPage();
820 setPageTitle(data, name);
821 ClearPage.write(data, "package.cs", filename);
822
823 filename = pkg.fullDescriptionHtmlPage();
824 setPageTitle(data, name + " Details");
825 ClearPage.write(data, "package-descr.cs", filename);
826
827 Proofread.writePackage(filename, pkg.inlineTags());
828 }
829
830 public static void writeClassLists()
831 {
832 int i;
833 HDF data = makePackageHDF();
834
835 ClassInfo[] classes = PackageInfo.filterHidden(
836 Converter.convertClasses(root.classes()));
837 if (classes.length == 0) {
838 return ;
839 }
840
841 Sorter[] sorted = new Sorter[classes.length];
842 for (i=0; i<sorted.length; i++) {
843 ClassInfo cl = classes[i];
844 String name = cl.name();
845 sorted[i] = new Sorter(name, cl);
846 }
847
848 Arrays.sort(sorted);
849
850 // make a pass and resolve ones that have the same name
851 int firstMatch = 0;
852 String lastName = sorted[0].label;
853 for (i=1; i<sorted.length; i++) {
854 String s = sorted[i].label;
855 if (!lastName.equals(s)) {
856 if (firstMatch != i-1) {
857 // there were duplicates
858 for (int j=firstMatch; j<i; j++) {
859 PackageInfo pkg = ((ClassInfo)sorted[j].data).containingPackage();
860 if (pkg != null) {
861 sorted[j].label = sorted[j].label + " (" + pkg.name() + ")";
862 }
863 }
864 }
865 firstMatch = i;
866 lastName = s;
867 }
868 }
869
870 // and sort again
871 Arrays.sort(sorted);
872
873 for (i=0; i<sorted.length; i++) {
874 String s = sorted[i].label;
875 ClassInfo cl = (ClassInfo)sorted[i].data;
876 char first = Character.toUpperCase(s.charAt(0));
877 cl.makeShortDescrHDF(data, "docs.classes." + first + '.' + i);
878 }
879
880 setPageTitle(data, "Class Index");
881 ClearPage.write(data, "classes.cs", javadocDir + "classes" + htmlExtension);
882 }
883
884 // we use the word keywords because "index" means something else in html land
885 // the user only ever sees the word index
886/* public static void writeKeywords()
887 {
888 ArrayList<KeywordEntry> keywords = new ArrayList<KeywordEntry>();
889
890 ClassInfo[] classes = PackageInfo.filterHidden(Converter.convertClasses(root.classes()));
891
892 for (ClassInfo cl: classes) {
893 cl.makeKeywordEntries(keywords);
894 }
895
896 HDF data = makeHDF();
897
898 Collections.sort(keywords);
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -0700899
The Android Open Source Project88b60792009-03-03 19:28:42 -0800900 int i=0;
901 for (KeywordEntry entry: keywords) {
902 String base = "keywords." + entry.firstChar() + "." + i;
903 entry.makeHDF(data, base);
904 i++;
905 }
906
907 setPageTitle(data, "Index");
908 ClearPage.write(data, "keywords.cs", javadocDir + "keywords" + htmlExtension);
909 } */
910
911 public static void writeHierarchy()
912 {
913 ClassInfo[] classes = Converter.rootClasses();
914 ArrayList<ClassInfo> info = new ArrayList<ClassInfo>();
915 for (ClassInfo cl: classes) {
916 if (!cl.isHidden()) {
917 info.add(cl);
918 }
919 }
920 HDF data = makePackageHDF();
921 Hierarchy.makeHierarchy(data, info.toArray(new ClassInfo[info.size()]));
922 setPageTitle(data, "Class Hierarchy");
923 ClearPage.write(data, "hierarchy.cs", javadocDir + "hierarchy" + htmlExtension);
924 }
925
926 public static void writeClasses()
927 {
928 ClassInfo[] classes = Converter.rootClasses();
929
930 for (ClassInfo cl: classes) {
931 HDF data = makePackageHDF();
932 if (!cl.isHidden()) {
933 writeClass(cl, data);
934 }
935 }
936 }
937
938 public static void writeClass(ClassInfo cl, HDF data)
939 {
940 cl.makeHDF(data);
941
942 setPageTitle(data, cl.name());
943 ClearPage.write(data, "class.cs", cl.htmlPage());
944
945 Proofread.writeClass(cl.htmlPage(), cl);
946 }
947
948 public static void makeClassListHDF(HDF data, String base,
949 ClassInfo[] classes)
950 {
951 for (int i=0; i<classes.length; i++) {
952 ClassInfo cl = classes[i];
953 if (!cl.isHidden()) {
954 cl.makeShortDescrHDF(data, base + "." + i);
955 }
956 }
957 }
958
959 public static String linkTarget(String source, String target)
960 {
961 String[] src = source.split("/");
962 String[] tgt = target.split("/");
963
964 int srclen = src.length;
965 int tgtlen = tgt.length;
966
967 int same = 0;
968 while (same < (srclen-1)
969 && same < (tgtlen-1)
970 && (src[same].equals(tgt[same]))) {
971 same++;
972 }
973
974 String s = "";
975
976 int up = srclen-same-1;
977 for (int i=0; i<up; i++) {
978 s += "../";
979 }
980
981
982 int N = tgtlen-1;
983 for (int i=same; i<N; i++) {
984 s += tgt[i] + '/';
985 }
986 s += tgt[tgtlen-1];
987
988 return s;
989 }
990
991 /**
Xavier Ducrohet02e14df2009-09-10 14:50:12 -0700992 * Returns true if the given element has an @hide or @pending annotation.
The Android Open Source Project88b60792009-03-03 19:28:42 -0800993 */
994 private static boolean hasHideAnnotation(Doc doc) {
Xavier Ducrohet02e14df2009-09-10 14:50:12 -0700995 String comment = doc.getRawCommentText();
996 return comment.indexOf("@hide") != -1 || comment.indexOf("@pending") != -1;
The Android Open Source Project88b60792009-03-03 19:28:42 -0800997 }
998
999 /**
1000 * Returns true if the given element is hidden.
1001 */
1002 private static boolean isHidden(Doc doc) {
1003 // Methods, fields, constructors.
1004 if (doc instanceof MemberDoc) {
1005 return hasHideAnnotation(doc);
1006 }
1007
1008 // Classes, interfaces, enums, annotation types.
1009 if (doc instanceof ClassDoc) {
1010 ClassDoc classDoc = (ClassDoc) doc;
1011
1012 // Check the containing package.
1013 if (hasHideAnnotation(classDoc.containingPackage())) {
1014 return true;
1015 }
1016
1017 // Check the class doc and containing class docs if this is a
1018 // nested class.
1019 ClassDoc current = classDoc;
1020 do {
1021 if (hasHideAnnotation(current)) {
1022 return true;
1023 }
1024
1025 current = current.containingClass();
1026 } while (current != null);
1027 }
1028
1029 return false;
1030 }
1031
1032 /**
1033 * Filters out hidden elements.
1034 */
1035 private static Object filterHidden(Object o, Class<?> expected) {
1036 if (o == null) {
1037 return null;
1038 }
1039
1040 Class type = o.getClass();
1041 if (type.getName().startsWith("com.sun.")) {
1042 // TODO: Implement interfaces from superclasses, too.
1043 return Proxy.newProxyInstance(type.getClassLoader(),
1044 type.getInterfaces(), new HideHandler(o));
1045 } else if (o instanceof Object[]) {
1046 Class<?> componentType = expected.getComponentType();
1047 Object[] array = (Object[]) o;
1048 List<Object> list = new ArrayList<Object>(array.length);
1049 for (Object entry : array) {
1050 if ((entry instanceof Doc) && isHidden((Doc) entry)) {
1051 continue;
1052 }
1053 list.add(filterHidden(entry, componentType));
1054 }
1055 return list.toArray(
1056 (Object[]) Array.newInstance(componentType, list.size()));
1057 } else {
1058 return o;
1059 }
1060 }
1061
1062 /**
1063 * Filters hidden elements out of method return values.
1064 */
1065 private static class HideHandler implements InvocationHandler {
1066
1067 private final Object target;
1068
1069 public HideHandler(Object target) {
1070 this.target = target;
1071 }
1072
1073 public Object invoke(Object proxy, Method method, Object[] args)
1074 throws Throwable {
1075 String methodName = method.getName();
1076 if (args != null) {
1077 if (methodName.equals("compareTo") ||
1078 methodName.equals("equals") ||
1079 methodName.equals("overrides") ||
1080 methodName.equals("subclassOf")) {
1081 args[0] = unwrap(args[0]);
1082 }
1083 }
1084
1085 if (methodName.equals("getRawCommentText")) {
1086 return filterComment((String) method.invoke(target, args));
1087 }
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001088
The Android Open Source Project88b60792009-03-03 19:28:42 -08001089 // escape "&" in disjunctive types.
1090 if (proxy instanceof Type && methodName.equals("toString")) {
1091 return ((String) method.invoke(target, args))
1092 .replace("&", "&amp;");
1093 }
1094
1095 try {
1096 return filterHidden(method.invoke(target, args),
1097 method.getReturnType());
1098 } catch (InvocationTargetException e) {
1099 throw e.getTargetException();
1100 }
1101 }
1102
1103 private String filterComment(String s) {
1104 if (s == null) {
1105 return null;
1106 }
1107
1108 s = s.trim();
1109
1110 // Work around off by one error
1111 while (s.length() >= 5
1112 && s.charAt(s.length() - 5) == '{') {
1113 s += "&nbsp;";
1114 }
1115
1116 return s;
1117 }
1118
1119 private static Object unwrap(Object proxy) {
1120 if (proxy instanceof Proxy)
1121 return ((HideHandler)Proxy.getInvocationHandler(proxy)).target;
1122 return proxy;
1123 }
1124 }
1125
1126 public static String scope(Scoped scoped) {
1127 if (scoped.isPublic()) {
1128 return "public";
1129 }
1130 else if (scoped.isProtected()) {
1131 return "protected";
1132 }
1133 else if (scoped.isPackagePrivate()) {
1134 return "";
1135 }
1136 else if (scoped.isPrivate()) {
1137 return "private";
1138 }
1139 else {
1140 throw new RuntimeException("invalid scope for object " + scoped);
1141 }
1142 }
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001143
The Android Open Source Project88b60792009-03-03 19:28:42 -08001144 /**
1145 * Collect the values used by the Dev tools and write them in files packaged with the SDK
1146 * @param output the ouput directory for the files.
1147 */
1148 private static void writeSdkValues(String output) {
1149 ArrayList<String> activityActions = new ArrayList<String>();
1150 ArrayList<String> broadcastActions = new ArrayList<String>();
1151 ArrayList<String> serviceActions = new ArrayList<String>();
1152 ArrayList<String> categories = new ArrayList<String>();
Xavier Ducrohetf9b6d382009-12-14 17:55:05 -08001153 ArrayList<String> features = new ArrayList<String>();
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001154
The Android Open Source Project88b60792009-03-03 19:28:42 -08001155 ArrayList<ClassInfo> layouts = new ArrayList<ClassInfo>();
1156 ArrayList<ClassInfo> widgets = new ArrayList<ClassInfo>();
1157 ArrayList<ClassInfo> layoutParams = new ArrayList<ClassInfo>();
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001158
The Android Open Source Project88b60792009-03-03 19:28:42 -08001159 ClassInfo[] classes = Converter.allClasses();
1160
1161 // Go through all the fields of all the classes, looking SDK stuff.
1162 for (ClassInfo clazz : classes) {
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001163
The Android Open Source Project88b60792009-03-03 19:28:42 -08001164 // first check constant fields for the SdkConstant annotation.
1165 FieldInfo[] fields = clazz.allSelfFields();
1166 for (FieldInfo field : fields) {
1167 Object cValue = field.constantValue();
1168 if (cValue != null) {
1169 AnnotationInstanceInfo[] annotations = field.annotations();
1170 if (annotations.length > 0) {
1171 for (AnnotationInstanceInfo annotation : annotations) {
1172 if (SDK_CONSTANT_ANNOTATION.equals(annotation.type().qualifiedName())) {
1173 AnnotationValueInfo[] values = annotation.elementValues();
1174 if (values.length > 0) {
1175 String type = values[0].valueString();
1176 if (SDK_CONSTANT_TYPE_ACTIVITY_ACTION.equals(type)) {
1177 activityActions.add(cValue.toString());
1178 } else if (SDK_CONSTANT_TYPE_BROADCAST_ACTION.equals(type)) {
1179 broadcastActions.add(cValue.toString());
1180 } else if (SDK_CONSTANT_TYPE_SERVICE_ACTION.equals(type)) {
1181 serviceActions.add(cValue.toString());
1182 } else if (SDK_CONSTANT_TYPE_CATEGORY.equals(type)) {
1183 categories.add(cValue.toString());
Xavier Ducrohetf9b6d382009-12-14 17:55:05 -08001184 } else if (SDK_CONSTANT_TYPE_FEATURE.equals(type)) {
1185 features.add(cValue.toString());
The Android Open Source Project88b60792009-03-03 19:28:42 -08001186 }
1187 }
1188 break;
1189 }
1190 }
1191 }
1192 }
1193 }
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001194
The Android Open Source Project88b60792009-03-03 19:28:42 -08001195 // Now check the class for @Widget or if its in the android.widget package
1196 // (unless the class is hidden or abstract, or non public)
1197 if (clazz.isHidden() == false && clazz.isPublic() && clazz.isAbstract() == false) {
1198 boolean annotated = false;
1199 AnnotationInstanceInfo[] annotations = clazz.annotations();
1200 if (annotations.length > 0) {
1201 for (AnnotationInstanceInfo annotation : annotations) {
1202 if (SDK_WIDGET_ANNOTATION.equals(annotation.type().qualifiedName())) {
1203 widgets.add(clazz);
1204 annotated = true;
1205 break;
1206 } else if (SDK_LAYOUT_ANNOTATION.equals(annotation.type().qualifiedName())) {
1207 layouts.add(clazz);
1208 annotated = true;
1209 break;
1210 }
1211 }
1212 }
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001213
The Android Open Source Project88b60792009-03-03 19:28:42 -08001214 if (annotated == false) {
1215 // lets check if this is inside android.widget
1216 PackageInfo pckg = clazz.containingPackage();
1217 String packageName = pckg.name();
1218 if ("android.widget".equals(packageName) ||
1219 "android.view".equals(packageName)) {
1220 // now we check what this class inherits either from android.view.ViewGroup
1221 // or android.view.View, or android.view.ViewGroup.LayoutParams
1222 int type = checkInheritance(clazz);
1223 switch (type) {
1224 case TYPE_WIDGET:
1225 widgets.add(clazz);
1226 break;
1227 case TYPE_LAYOUT:
1228 layouts.add(clazz);
1229 break;
1230 case TYPE_LAYOUT_PARAM:
1231 layoutParams.add(clazz);
1232 break;
1233 }
1234 }
1235 }
1236 }
1237 }
1238
1239 // now write the files, whether or not the list are empty.
1240 // the SDK built requires those files to be present.
1241
1242 Collections.sort(activityActions);
1243 writeValues(output + "/activity_actions.txt", activityActions);
1244
1245 Collections.sort(broadcastActions);
1246 writeValues(output + "/broadcast_actions.txt", broadcastActions);
1247
1248 Collections.sort(serviceActions);
1249 writeValues(output + "/service_actions.txt", serviceActions);
1250
1251 Collections.sort(categories);
1252 writeValues(output + "/categories.txt", categories);
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001253
Xavier Ducrohetf9b6d382009-12-14 17:55:05 -08001254 Collections.sort(features);
1255 writeValues(output + "/features.txt", features);
1256
The Android Open Source Project88b60792009-03-03 19:28:42 -08001257 // before writing the list of classes, we do some checks, to make sure the layout params
1258 // are enclosed by a layout class (and not one that has been declared as a widget)
1259 for (int i = 0 ; i < layoutParams.size();) {
1260 ClassInfo layoutParamClass = layoutParams.get(i);
1261 ClassInfo containingClass = layoutParamClass.containingClass();
1262 if (containingClass == null || layouts.indexOf(containingClass) == -1) {
1263 layoutParams.remove(i);
1264 } else {
1265 i++;
1266 }
1267 }
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001268
The Android Open Source Project88b60792009-03-03 19:28:42 -08001269 writeClasses(output + "/widgets.txt", widgets, layouts, layoutParams);
1270 }
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001271
The Android Open Source Project88b60792009-03-03 19:28:42 -08001272 /**
1273 * Writes a list of values into a text files.
1274 * @param pathname the absolute os path of the output file.
1275 * @param values the list of values to write.
1276 */
1277 private static void writeValues(String pathname, ArrayList<String> values) {
1278 FileWriter fw = null;
1279 BufferedWriter bw = null;
1280 try {
1281 fw = new FileWriter(pathname, false);
1282 bw = new BufferedWriter(fw);
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001283
The Android Open Source Project88b60792009-03-03 19:28:42 -08001284 for (String value : values) {
1285 bw.append(value).append('\n');
1286 }
1287 } catch (IOException e) {
1288 // pass for now
1289 } finally {
1290 try {
1291 if (bw != null) bw.close();
1292 } catch (IOException e) {
1293 // pass for now
1294 }
1295 try {
1296 if (fw != null) fw.close();
1297 } catch (IOException e) {
1298 // pass for now
1299 }
1300 }
1301 }
1302
1303 /**
1304 * Writes the widget/layout/layout param classes into a text files.
1305 * @param pathname the absolute os path of the output file.
1306 * @param widgets the list of widget classes to write.
1307 * @param layouts the list of layout classes to write.
1308 * @param layoutParams the list of layout param classes to write.
1309 */
1310 private static void writeClasses(String pathname, ArrayList<ClassInfo> widgets,
1311 ArrayList<ClassInfo> layouts, ArrayList<ClassInfo> layoutParams) {
1312 FileWriter fw = null;
1313 BufferedWriter bw = null;
1314 try {
1315 fw = new FileWriter(pathname, false);
1316 bw = new BufferedWriter(fw);
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001317
The Android Open Source Project88b60792009-03-03 19:28:42 -08001318 // write the 3 types of classes.
1319 for (ClassInfo clazz : widgets) {
1320 writeClass(bw, clazz, 'W');
1321 }
1322 for (ClassInfo clazz : layoutParams) {
1323 writeClass(bw, clazz, 'P');
1324 }
1325 for (ClassInfo clazz : layouts) {
1326 writeClass(bw, clazz, 'L');
1327 }
1328 } catch (IOException e) {
1329 // pass for now
1330 } finally {
1331 try {
1332 if (bw != null) bw.close();
1333 } catch (IOException e) {
1334 // pass for now
1335 }
1336 try {
1337 if (fw != null) fw.close();
1338 } catch (IOException e) {
1339 // pass for now
1340 }
1341 }
1342 }
1343
1344 /**
1345 * Writes a class name and its super class names into a {@link BufferedWriter}.
1346 * @param writer the BufferedWriter to write into
1347 * @param clazz the class to write
1348 * @param prefix the prefix to put at the beginning of the line.
1349 * @throws IOException
1350 */
1351 private static void writeClass(BufferedWriter writer, ClassInfo clazz, char prefix)
1352 throws IOException {
1353 writer.append(prefix).append(clazz.qualifiedName());
1354 ClassInfo superClass = clazz;
1355 while ((superClass = superClass.superclass()) != null) {
1356 writer.append(' ').append(superClass.qualifiedName());
1357 }
1358 writer.append('\n');
1359 }
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001360
The Android Open Source Project88b60792009-03-03 19:28:42 -08001361 /**
1362 * Checks the inheritance of {@link ClassInfo} objects. This method return
1363 * <ul>
1364 * <li>{@link #TYPE_LAYOUT}: if the class extends <code>android.view.ViewGroup</code></li>
1365 * <li>{@link #TYPE_WIDGET}: if the class extends <code>android.view.View</code></li>
1366 * <li>{@link #TYPE_LAYOUT_PARAM}: if the class extends <code>android.view.ViewGroup$LayoutParams</code></li>
1367 * <li>{@link #TYPE_NONE}: in all other cases</li>
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001368 * </ul>
The Android Open Source Project88b60792009-03-03 19:28:42 -08001369 * @param clazz the {@link ClassInfo} to check.
1370 */
1371 private static int checkInheritance(ClassInfo clazz) {
1372 if ("android.view.ViewGroup".equals(clazz.qualifiedName())) {
1373 return TYPE_LAYOUT;
1374 } else if ("android.view.View".equals(clazz.qualifiedName())) {
1375 return TYPE_WIDGET;
1376 } else if ("android.view.ViewGroup.LayoutParams".equals(clazz.qualifiedName())) {
1377 return TYPE_LAYOUT_PARAM;
1378 }
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001379
The Android Open Source Project88b60792009-03-03 19:28:42 -08001380 ClassInfo parent = clazz.superclass();
1381 if (parent != null) {
1382 return checkInheritance(parent);
1383 }
Xavier Ducrohet5ee390d2009-09-10 13:08:27 -07001384
The Android Open Source Project88b60792009-03-03 19:28:42 -08001385 return TYPE_NONE;
1386 }
1387}