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