diff --git a/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java index 79149511b..85dbc7ce6 100644 --- a/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java +++ b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunner.java @@ -91,9 +91,8 @@ public class MonkeyRunner { @MonkeyRunnerExported(doc = "Simple help command to dump the MonkeyRunner supported " + "commands", returns = "The help text") - public static String help(PyObject[] args, String[] kws) { - // TODO: implement - return ""; + public static String help(PyObject[] args, String[] kws) { + return MonkeyRunnerHelp.helpString(); } @MonkeyRunnerExported(doc = "Put up an alert dialog to inform the user of something that " + diff --git a/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerHelp.java b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerHelp.java new file mode 100644 index 000000000..ffef5ed4f --- /dev/null +++ b/tools/monkeyrunner/src/com/android/monkeyrunner/MonkeyRunnerHelp.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.monkeyrunner; + +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +import com.android.monkeyrunner.doc.MonkeyRunnerExported; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Set; + +/** + * Utility class for generating inline help documentation + */ +public final class MonkeyRunnerHelp { + private MonkeyRunnerHelp() { } + + private static void getAllExportedClasses(Set fields, + Set methods, + Set> constructors, + Set> enums) { + final Set> classesVisited = Sets.newHashSet(); + Set> classesToVisit = Sets.newHashSet(); + classesToVisit.add(MonkeyRunner.class); + + Predicate> haventSeen = new Predicate>() { + public boolean apply(Class clz) { + return !classesVisited.contains(clz); + } + }; + + while (!classesToVisit.isEmpty()) { + classesVisited.addAll(classesToVisit); + + List> newClasses = Lists.newArrayList(); + for (Class clz : classesToVisit) { + // See if the class itself is annotated and is an enum + if (clz.isEnum() && clz.isAnnotationPresent(MonkeyRunnerExported.class)) { + enums.add(clz); + } + + // Constructors + for (Constructor c : clz.getConstructors()) { + newClasses.addAll(Collections2.filter(Arrays.asList(c.getParameterTypes()), + haventSeen)); + if (c.isAnnotationPresent(MonkeyRunnerExported.class)) { + constructors.add(c); + } + } + + // Fields + for (Field f : clz.getFields()) { + if (haventSeen.apply(f.getClass())) { + newClasses.add(f.getClass()); + } + if (f.isAnnotationPresent(MonkeyRunnerExported.class)) { + fields.add(f); + } + } + + // Methods + for (Method m : clz.getMethods()) { + newClasses.addAll(Collections2.filter(Arrays.asList(m.getParameterTypes()), + haventSeen)); + if (haventSeen.apply(m.getReturnType())) { + newClasses.add(m.getReturnType()); + } + + if (m.isAnnotationPresent(MonkeyRunnerExported.class)) { + methods.add(m); + } + } + + // Containing classes + for (Class toAdd : clz.getClasses()) { + newClasses.add(toAdd); + } + } + + classesToVisit.clear(); + classesToVisit.addAll(newClasses); + } + } + + private static Comparator MEMBER_SORTER = new Comparator() { + public int compare(Member o1, Member o2) { + return o1.getName().compareTo(o2.getName()); + } + }; + + private static Comparator> CLASS_SORTER = new Comparator>() { + public int compare(Class o1, Class o2) { + return o1.getName().compareTo(o2.getName()); + } + }; + + public static String helpString() { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + help(new PrintStream(os, true)); + return os.toString(); + } + + private static void help(PrintStream out) { + Set fields = Sets.newTreeSet(MEMBER_SORTER); + Set methods = Sets.newTreeSet(MEMBER_SORTER); + Set> constructors = Sets.newTreeSet(MEMBER_SORTER); + Set> classes = Sets.newTreeSet(CLASS_SORTER); + getAllExportedClasses(fields, methods, constructors, classes); + + for (Class clz : classes) { + out.println(clz.getCanonicalName() + ":"); + MonkeyRunnerExported annotation = clz.getAnnotation(MonkeyRunnerExported.class); + out.println(" " + annotation.doc()); + Object[] constants = clz.getEnumConstants(); + String[] argDocs = annotation.argDocs(); + if (constants.length > 0) { + out.println(" Values:"); + for (int x = 0; x < constants.length; x++) { + Object constant = constants[x]; + StringBuilder sb = new StringBuilder(); + sb.append(" ").append(constant); + if (argDocs.length > x) { + sb.append(" - ").append(argDocs[x]); + } + + out.println(sb.toString()); + } + } + out.println(); + } + + for (Method m : methods) { + MonkeyRunnerExported annotation = m.getAnnotation(MonkeyRunnerExported.class); + String className = m.getDeclaringClass().getCanonicalName(); + String methodName = className + "." + m.getName(); + out.println(methodName + ":"); + out.println(" " + annotation.doc()); + if (annotation.args().length > 0) { + out.println(" Args:"); + String[] argDocs = annotation.argDocs(); + String[] aargs = annotation.args(); + for (int x = 0; x < aargs.length; x++) { + StringBuilder sb = new StringBuilder(); + sb.append(" ").append(aargs[x]); + if (argDocs.length > x) { + sb.append(" - ").append(argDocs[x]); + } + out.println(sb.toString()); + } + } + if (!"".equals(annotation.returns())) { + out.println(" Returns:"); + out.println(" " + annotation.returns()); + } + out.println(); + } + } +}