AI2 Component  (Version nb184)
ComponentProcessor.java
Go to the documentation of this file.
1 // -*- mode: java; c-basic-offset: 2; -*-
2 // Copyright 2009-2011 Google, All Rights reserved
3 // Copyright 2011-2019 MIT, All rights reserved
4 // Released under the Apache License, Version 2.0
5 // http://www.apache.org/licenses/LICENSE-2.0
6 
7 package com.google.appinventor.components.scripts;
8 
40 import com.google.common.collect.ImmutableSet;
41 import com.google.common.collect.Lists;
42 import com.google.common.collect.Maps;
43 import com.google.common.collect.Sets;
44 
45 import java.io.IOException;
46 import java.io.Writer;
47 
48 import java.text.SimpleDateFormat;
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.Date;
52 import java.util.HashMap;
53 import java.util.HashSet;
54 import java.util.List;
55 import java.util.Map;
56 import java.util.Set;
57 import java.util.SortedMap;
58 
59 import javax.annotation.processing.AbstractProcessor;
60 import javax.annotation.processing.Messager;
61 import javax.annotation.processing.ProcessingEnvironment;
62 import javax.annotation.processing.RoundEnvironment;
63 import javax.lang.model.SourceVersion;
64 import javax.lang.model.element.AnnotationMirror;
65 import javax.lang.model.element.AnnotationValue;
66 import javax.lang.model.element.AnnotationValueVisitor;
67 import javax.lang.model.element.Element;
68 import javax.lang.model.element.ElementKind;
69 import javax.lang.model.element.ExecutableElement;
70 import javax.lang.model.element.Modifier;
71 import javax.lang.model.element.TypeElement;
72 import javax.lang.model.element.VariableElement;
73 import javax.lang.model.type.DeclaredType;
74 import javax.lang.model.type.ExecutableType;
75 import javax.lang.model.type.TypeKind;
76 import javax.lang.model.type.TypeMirror;
77 import javax.lang.model.util.Elements;
78 import javax.lang.model.util.SimpleTypeVisitor7;
79 import javax.lang.model.util.Types;
80 
81 import java.lang.annotation.Annotation;
82 
83 import java.lang.reflect.InvocationTargetException;
84 import java.util.regex.Matcher;
85 import java.util.regex.Pattern;
86 
87 import javax.tools.Diagnostic;
88 import javax.tools.Diagnostic.Kind;
89 import javax.tools.FileObject;
90 import javax.tools.StandardLocation;
91 
124 public abstract class ComponentProcessor extends AbstractProcessor {
125  private static final String OUTPUT_PACKAGE = "";
126 
127  private static final String MISSING_SIMPLE_PROPERTY_ANNOTATION =
128  "Designer property %s does not have a corresponding @SimpleProperty annotation.";
129  private static final String BOXED_TYPE_ERROR =
130  "Found use of boxed type %s. Please use the primitive type %s instead";
131 
132  // Returned by getSupportedAnnotationTypes()
133  private static final Set<String> SUPPORTED_ANNOTATION_TYPES = ImmutableSet.of(
134  "com.google.appinventor.components.annotations.DesignerComponent",
135  "com.google.appinventor.components.annotations.DesignerProperty",
136  "com.google.appinventor.components.annotations.SimpleEvent",
137  "com.google.appinventor.components.annotations.SimpleFunction",
138  "com.google.appinventor.components.annotations.SimpleObject",
139  "com.google.appinventor.components.annotations.SimpleProperty",
140  // TODO(Will): Remove the following string once the deprecated
141  // @SimpleBroadcastReceiver annotation is removed. It should
142  // should remain for the time being because otherwise we'll break
143  // extensions currently using @SimpleBroadcastReceiver.
144  "com.google.appinventor.components.annotations.SimpleBroadcastReceiver",
145  "com.google.appinventor.components.annotations.UsesAssets",
146  "com.google.appinventor.components.annotations.UsesLibraries",
147  "com.google.appinventor.components.annotations.UsesNativeLibraries",
148  "com.google.appinventor.components.annotations.UsesActivities",
149  "com.google.appinventor.components.annotations.UsesBroadcastReceivers",
150  "com.google.appinventor.components.annotations.UsesPermissions",
151  "com.google.appinventor.components.annotations.UsesServices",
152  "com.google.appinventor.components.annotations.UsesContentProviders");
153 
154  // Returned by getRwString()
155  private static final String READ_WRITE = "read-write";
156  private static final String READ_ONLY = "read-only";
157  private static final String WRITE_ONLY = "write-only";
158 
159  // Must match buildserver.compiler.ARMEABI_V7A_SUFFIX
160  private static final String ARMEABI_V7A_SUFFIX = "-v7a";
161  // Must match buildserver.compiler.ARMEABI_V8A_SUFFIX
162  private static final String ARM64_V8A_SUFFIX = "-v8a";
163  // Must match buildserver.compiler.X86_64_SUFFIX
164  private static final String X86_64_SUFFIX = "-x8a";
165 
166  private static final String TYPE_PLACEHOLDER = "%type%";
167 
168  private static final Map<String, String> BOXED_TYPES = new HashMap<>();
169 
170  static {
171  BOXED_TYPES.put("java.lang.Boolean", "boolean");
172  BOXED_TYPES.put("java.lang.Byte", "byte");
173  BOXED_TYPES.put("java.lang.Char", "char");
174  BOXED_TYPES.put("java.lang.Short", "short");
175  BOXED_TYPES.put("java.lang.Integer", "int");
176  BOXED_TYPES.put("java.lang.Long", "long");
177  BOXED_TYPES.put("java.lang.Float", "float");
178  BOXED_TYPES.put("java.lang.Double", "double");
179  }
180 
181  // The next two fields are set in init().
186  private Elements elementUtils;
187  private Types typeUtils;
188 
193  // Set in process()
194  protected Messager messager;
195 
199  private int pass = 0;
200 
207  protected final SortedMap<String, ComponentInfo> components = Maps.newTreeMap();
208 
209  private final List<String> componentTypes = Lists.newArrayList();
210 
216  private final Set<String> visitedTypes = new HashSet<>();
217 
223  protected final class Parameter {
227  protected final String name;
228 
232  protected final String type;
233 
234  protected final boolean color;
235 
242  protected Parameter(String name, String type) {
243  this(name, type, false);
244  }
245 
246  protected Parameter(String name, String type, boolean color) {
247  this.name = name;
248  this.type = type;
249  this.color = color;
250  }
251 
263  protected String parameterToYailType(Parameter parameter) {
264  return javaTypeToYailType(type);
265  }
266  }
267 
271  protected abstract static class Feature {
272  private static final Pattern AT_SIGN = Pattern.compile("[^\\\\]@");
273  private static final Pattern LINK_FORM = Pattern.compile("\\{@link ([A-Za-z]*#?)([A-Za-z]*)[^}]*}");
274  private static final Pattern CODE_FORM = Pattern.compile("\\{@code ([^}]*)}");
275 
276  private final String featureType;
277  protected final String name;
278  protected String description;
279  protected boolean defaultDescription = false;
280  protected String longDescription;
281  protected boolean userVisible;
282  protected boolean deprecated;
283 
284  protected Feature(String name, String description, String longDescription, String featureType,
285  boolean userVisible, boolean deprecated) {
286  this.featureType = featureType;
287  this.name = name;
288  setDescription(description);
289  setLongDescription(longDescription);
290  this.userVisible = userVisible;
291  this.deprecated = deprecated;
292  }
293 
294  public boolean isDefaultDescription() {
295  return defaultDescription;
296  }
297 
298  public void setDescription(String description) {
299  if (description == null || description.isEmpty()) {
300  this.description = featureType + " for " + name;
301  defaultDescription = true;
302  } else {
303  // Throw out the first @ or { and everything after it,
304  // in order to strip out @param, @author, {@link ...}, etc.
305  this.description = description.split("[@{]")[0].trim();
306  defaultDescription = false;
307  }
308  }
309 
310  public void setLongDescription(String longDescription) {
311  if (longDescription == null || longDescription.isEmpty()) {
312  this.longDescription = this.description;
313  } else if (longDescription.contains("@suppressdoc")) {
314  this.longDescription = "";
315  } else {
316  this.longDescription = longDescription;
317  }
318  // Handle links
319  Matcher linkMatcher = LINK_FORM.matcher(this.longDescription);
320  StringBuffer sb = new StringBuffer();
321  int lastEnd = 0;
322  while (linkMatcher.find(lastEnd)) {
323  sb.append(this.longDescription, lastEnd, linkMatcher.start());
324  String clazz = linkMatcher.group(1);
325  if (clazz.endsWith("#")) {
326  clazz = clazz.substring(0, clazz.length() - 1);
327  }
328  if ("Form".equals(clazz)) {
329  clazz = "Screen";
330  }
331  String func = linkMatcher.group(2);
332  sb.append("[");
333  if (!clazz.isEmpty()) {
334  sb.append("`");
335  sb.append(clazz);
336  sb.append("`");
337  if (!func.isEmpty()) {
338  sb.append("'s ");
339  }
340  }
341  if (!func.isEmpty()) {
342  sb.append("`");
343  sb.append(func);
344  sb.append("`");
345  }
346  sb.append("](#");
347  if (clazz.isEmpty()) {
348  sb.append("%type%.");
349  } else {
350  sb.append(clazz);
351  if (!func.isEmpty()) {
352  sb.append(".");
353  }
354  }
355  if (!func.isEmpty()) {
356  sb.append(func);
357  }
358  sb.append(")");
359  lastEnd = linkMatcher.end();
360  }
361  sb.append(this.longDescription.substring(lastEnd));
362  this.longDescription = sb.toString();
363  // Map {@code foo} to `foo`
364  sb = new StringBuffer();
365  Matcher codeMatcher = CODE_FORM.matcher(this.longDescription);
366  lastEnd = 0;
367  while (codeMatcher.find(lastEnd)) {
368  sb.append(this.longDescription, lastEnd, codeMatcher.start());
369  sb.append("`");
370  sb.append(codeMatcher.group(1));
371  sb.append("`");
372  lastEnd = codeMatcher.end();
373  }
374  sb.append(this.longDescription.substring(lastEnd));
375  this.longDescription = sb.toString();
376  // Strip out the Javadoc annotations (@param, etc.) for end-user documentation
377  Matcher m = AT_SIGN.matcher(this.longDescription);
378  if (m.find()) {
379  this.longDescription = this.longDescription.substring(0, m.start() + 1);
380  }
381  // Replace escaped @ with just @, e.g., so we can use @ in email address examples.
382  this.longDescription = this.longDescription.replaceAll("\\\\@", "@").trim();
383  }
384 
385  public String getLongDescription(ComponentInfo component) {
386  if (longDescription == null || longDescription.isEmpty()) {
387  return description;
388  }
389  String name = component.name.equals("Form") ? "Screen" : component.name;
390  return longDescription.replaceAll("%type%", name).trim();
391  }
392 
399  protected boolean isUserVisible() {
400  return userVisible;
401  }
402 
408  protected boolean isDeprecated() {
409  return deprecated;
410  }
411  }
412 
417  protected abstract class ParameterizedFeature extends Feature {
418  // Inherits name, description
419  protected final List<Parameter> parameters;
420 
421  protected ParameterizedFeature(String name, String description, String longDescription,
422  String feature, boolean userVisible, boolean deprecated) {
423  super(name, description, longDescription, feature, userVisible, deprecated);
424  parameters = Lists.newArrayList();
425  }
426 
427  protected void addParameter(String name, String type) {
428  parameters.add(new Parameter(name, type));
429  }
430 
431  protected void addParameter(String name, String type, boolean color) {
432  parameters.add(new Parameter(name, type, color));
433  }
434 
443  protected String toParameterString() {
444  StringBuilder sb = new StringBuilder();
445  int count = 0;
446  for (Parameter param : parameters) {
447  sb.append(param.parameterToYailType(param));
448  sb.append(" ");
449  sb.append(param.name);
450  if (++count != parameters.size()) {
451  sb.append(", ");
452  }
453  }
454  return new String(sb);
455  }
456  }
457 
461  protected final class Event extends ParameterizedFeature
462  implements Cloneable, Comparable<Event> {
463  // Inherits name, description, and parameters
464 
465  protected Event(String name, String description, String longDescription, boolean userVisible, boolean deprecated) {
466  super(name, description, longDescription, "Event", userVisible, deprecated);
467  }
468 
469  @Override
470  public Event clone() {
471  Event that = new Event(name, description, longDescription, userVisible, deprecated);
472  for (Parameter p : parameters) {
473  that.addParameter(p.name, p.type);
474  }
475  return that;
476  }
477 
478  @Override
479  public int compareTo(Event e) {
480  return name.compareTo(e.name);
481  }
482  }
483 
488  protected final class Method extends ParameterizedFeature
489  implements Cloneable, Comparable<Method> {
490  // Inherits name, description, and parameters
491  private String returnType;
492  private boolean color;
493 
494  protected Method(String name, String description, String longDescription, boolean userVisible,
495  boolean deprecated) {
496  super(name, description, longDescription, "Method", userVisible, deprecated);
497  // returnType defaults to null
498  }
499 
500  protected String getReturnType() {
501  return returnType;
502  }
503 
504  protected boolean isColor() {
505  return color;
506  }
507 
508  @Override
509  public Method clone() {
510  Method that = new Method(name, description, longDescription, userVisible, deprecated);
511  for (Parameter p : parameters) {
512  that.addParameter(p.name, p.type);
513  }
514  that.returnType = returnType;
515  return that;
516  }
517 
518  @Override
519  public int compareTo(Method f) {
520  return name.compareTo(f.name);
521  }
522  }
523 
528  protected static final class Property extends Feature implements Cloneable {
529  protected final String name;
530  private PropertyCategory propertyCategory;
531  private String type;
532  private boolean readable;
533  private boolean writable;
534  private String componentInfoName;
535  private boolean color;
536 
537  protected Property(String name, String description, String longDescription,
538  PropertyCategory category, boolean userVisible, boolean deprecated) {
539  super(name, description, longDescription, "Property", userVisible, deprecated);
540  this.name = name;
541  this.propertyCategory = category;
542  // type defaults to null
543  // readable and writable default to false
544  }
545 
546  @Override
547  public Property clone() {
548  Property that = new Property(name, description, longDescription, propertyCategory,
549  isUserVisible(), isDeprecated());
550  that.type = type;
551  that.readable = readable;
552  that.writable = writable;
553  that.componentInfoName = componentInfoName;
554  that.color = color;
555  return that;
556  }
557 
558  @Override
559  public String toString() {
560  StringBuilder sb = new StringBuilder("<Property name: ");
561  sb.append(name);
562  sb.append(", type: ");
563  sb.append(type);
564  if (readable) {
565  sb.append(" readable");
566  }
567  if (writable) {
568  sb.append(" writable");
569  }
570  sb.append(">");
571  return sb.toString();
572  }
573 
580  protected String getDescription() {
581  return description;
582  }
583 
589  protected String getType() {
590  return type;
591  }
592 
598  protected boolean isReadable() {
599  return readable;
600  }
601 
607  protected boolean isWritable() {
608  return writable;
609  }
610 
611  protected boolean isColor() {
612  return color;
613  }
614 
623  protected String getRwString() {
624  if (readable) {
625  if (writable) {
626  return READ_WRITE;
627  } else {
628  return READ_ONLY;
629  }
630  } else {
631  if (!writable) {
632  throw new RuntimeException("Property " + name +
633  " is neither readable nor writable");
634  }
635  return WRITE_ONLY;
636  }
637  }
638  }
639 
644  protected final class ComponentInfo extends Feature {
645  // Inherits name and description
650  protected final Set<String> permissions;
651 
656  protected final Map<String, String[]> conditionalPermissions;
657 
662  protected final Map<String, String[]> conditionalBroadcastReceivers;
663 
668  protected final Map<String, String[]> conditionalServices;
669 
674  protected final Map<String, String[]> conditionalContentProviders;
675 
679  protected final Set<String> libraries;
680 
684  protected final Set<String> nativeLibraries;
685 
689  protected final Set<String> assets;
690 
694  protected final Set<String> activities;
695 
699  protected final Set<String> metadata;
700 
704  protected final Set<String> activityMetadata;
705 
709  protected final Set<String> broadcastReceivers;
710 
714  protected final Set<String> services;
715 
719  protected final Set<String> contentProviders;
720 
728  protected final Set<String> classNameAndActionsBR;
729 
734  protected final SortedMap<String, DesignerProperty> designerProperties;
735 
741  protected final SortedMap<String, Property> properties;
742 
746  protected final SortedMap<String, Method> methods;
747 
751  protected final SortedMap<String, Event> events;
752 
757  protected final boolean abstractClass;
758 
765  protected final String displayName;
766 
767  protected final String type;
768  protected boolean external;
769 
770  private String helpDescription; // Shorter popup description
771  private String helpUrl; // Custom help URL for extensions
772  private String category;
773  private String categoryString;
774  private boolean simpleObject;
775  private boolean designerComponent;
776  private int version;
777  private boolean showOnPalette;
778  private boolean nonVisible;
779  private String iconName;
780  private int androidMinSdk;
781  private String versionName;
782  private String dateBuilt;
783 
784  protected ComponentInfo(Element element) {
785  super(element.getSimpleName().toString(), // Short name
786  elementUtils.getDocComment(element),
787  elementUtils.getDocComment(element),
788  "Component", false, elementUtils.isDeprecated(element));
789  type = element.asType().toString();
790  displayName = getDisplayNameForComponentType(name);
791  permissions = Sets.newHashSet();
792  conditionalPermissions = Maps.newTreeMap();
793  conditionalBroadcastReceivers = Maps.newTreeMap();
794  conditionalServices = Maps.newTreeMap();
795  conditionalContentProviders = Maps.newTreeMap();
796  libraries = Sets.newHashSet();
797  nativeLibraries = Sets.newHashSet();
798  assets = Sets.newHashSet();
799  activities = Sets.newHashSet();
800  metadata = Sets.newHashSet();
801  activityMetadata = Sets.newHashSet();
802  broadcastReceivers = Sets.newHashSet();
803  services = Sets.newHashSet();
804  contentProviders = Sets.newHashSet();
805  classNameAndActionsBR = Sets.newHashSet();
806  designerProperties = Maps.newTreeMap();
807  properties = Maps.newTreeMap();
808  methods = Maps.newTreeMap();
809  events = Maps.newTreeMap();
810  abstractClass = element.getModifiers().contains(Modifier.ABSTRACT);
811  external = false;
812  versionName = null;
813  dateBuilt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(new Date());
814  for (AnnotationMirror am : element.getAnnotationMirrors()) {
815  DeclaredType dt = am.getAnnotationType();
816  String annotationName = am.getAnnotationType().toString();
817  if (annotationName.equals(SimpleObject.class.getName())) {
818  simpleObject = true;
819  SimpleObject simpleObjectAnnotation = element.getAnnotation(SimpleObject.class);
820  external = simpleObjectAnnotation.external();
821  }
822  if (annotationName.equals(DesignerComponent.class.getName())) {
823  designerComponent = true;
824  DesignerComponent designerComponentAnnotation =
825  element.getAnnotation(DesignerComponent.class);
826  Map values = elementUtils.getElementValuesWithDefaults(am);
827  for (Map.Entry entry : (Set<Map.Entry>) values.entrySet()) {
828  if (((ExecutableElement) entry.getKey()).getSimpleName().contentEquals("dateBuilt")) {
829  // ------------------- Ulli ---------------------------------
830 // Folgende Zeilen eingefügt
831 String tempDate = "" + entry.getValue(); // get value from entry
832 if (tempDate.length() > 2) {
833  tempDate = tempDate.substring(1, tempDate.length() - 1); // strip off \" at start and end
834  dateBuilt = tempDate;
835 }
836 // Ulli Ende
837 
838  entry.setValue(new AnnotationValue() {
839  @Override
840  public Object getValue() {
841  return dateBuilt;
842  }
843 
844  @Override
845  public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) {
846  return v.visit(this, p);
847  }
848 
849  @Override
850  public String toString() {
851  return "\"" + dateBuilt + "\"";
852  }
853  });
854  }
855  }
856 
857  // Override javadoc description with explicit description
858  // if provided.
859  String explicitDescription = designerComponentAnnotation.description();
860  if (!explicitDescription.isEmpty()) {
861  setDescription(explicitDescription);
862  }
863 
864  // Set helpDescription to the designerHelpDescription field if
865  // provided; otherwise, use description
866  helpDescription = designerComponentAnnotation.designerHelpDescription();
867  if (helpDescription.isEmpty()) {
868  helpDescription = description;
869  }
870  helpUrl = designerComponentAnnotation.helpUrl();
871  if (!helpUrl.startsWith("http:") && !helpUrl.startsWith("https:")) {
872  helpUrl = ""; // only accept http: or https: URLs (e.g., no javascript:)
873  }
874 
875  category = designerComponentAnnotation.category().getName();
876  categoryString = designerComponentAnnotation.category().toString();
877  version = designerComponentAnnotation.version();
878  showOnPalette = designerComponentAnnotation.showOnPalette();
879  nonVisible = designerComponentAnnotation.nonVisible();
880  iconName = designerComponentAnnotation.iconName();
881  androidMinSdk = designerComponentAnnotation.androidMinSdk();
882  versionName = designerComponentAnnotation.versionName();
883  userVisible = designerComponentAnnotation.showOnPalette();
884  }
885  }
886  }
887 
898  protected String getHelpDescription() {
899  return helpDescription;
900  }
901 
907  protected String getHelpUrl() {
908  return helpUrl;
909  }
910 
917  protected String getCategory() {
918  return category;
919  }
920 
928  protected String getCategoryString() {
929  return categoryString;
930  }
931 
938  protected int getVersion() {
939  return version;
940  }
941 
948  protected boolean getShowOnPalette() {
949  return showOnPalette;
950  }
951 
960  protected boolean getNonVisible() {
961  return nonVisible;
962  }
963 
969  protected boolean getExternal() {
970  return external;
971  }
972 
979  protected String getIconName() {
980  return iconName;
981  }
982 
989  protected int getAndroidMinSdk() {
990  return androidMinSdk;
991  }
992 
993  protected String getVersionName() {
994  return versionName;
995  }
996 
997  protected String getDateBuilt() {
998  return dateBuilt;
999  }
1000 
1001  private String getDisplayNameForComponentType(String componentTypeName) {
1002  // Users don't know what a 'Form' is. They know it as a 'Screen'.
1003  return "Form".equals(componentTypeName) ? "Screen" : componentTypeName;
1004  }
1005 
1006  protected String getName() {
1007  if (name.equals("Form")) {
1008  return "Screen";
1009  } else {
1010  return name;
1011  }
1012  }
1013 
1014  }
1015 
1022  @Override
1023  public Set<String> getSupportedAnnotationTypes() {
1024  return SUPPORTED_ANNOTATION_TYPES;
1025  }
1026 
1027  @Override
1028  public SourceVersion getSupportedSourceVersion() {
1029  return SourceVersion.RELEASE_7;
1030  }
1031 
1032  @Override
1033  public void init(ProcessingEnvironment processingEnv) {
1034  super.init(processingEnv);
1035  elementUtils = processingEnv.getElementUtils();
1036  typeUtils = processingEnv.getTypeUtils();
1037  }
1038 
1051  @Override
1052  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
1053  // This method will be called many times for the source code.
1054  // Only do something on the first pass.
1055  pass++;
1056  if (pass > 1) {
1057  return true;
1058  }
1059 
1060  messager = processingEnv.getMessager();
1061 
1062  List<Element> elements = new ArrayList<>();
1063  List<Element> excludedElements = new ArrayList<>();
1064  for (TypeElement te : annotations) {
1065  if (te.getSimpleName().toString().equals("DesignerComponent")) {
1066  elements.addAll(roundEnv.getElementsAnnotatedWith(te));
1067  } else if (te.getSimpleName().toString().equals("SimpleObject")) {
1068  for (Element element : roundEnv.getElementsAnnotatedWith(te)) {
1069  SimpleObject annotation = element.getAnnotation(SimpleObject.class);
1070  if (!annotation.external()) {
1071  elements.add(element);
1072  } else {
1073  excludedElements.add(element);
1074  }
1075  }
1076  }
1077  }
1078  for (Element element : elements) {
1079  processComponent(element);
1080  }
1081 
1082  // Put the component class names (including abstract classes)
1083  componentTypes.addAll(components.keySet());
1084  for (Element element : excludedElements) {
1085  componentTypes.add(element.asType().toString()); // allow extensions to reference one another
1086  }
1087 
1088  // Remove non-components before calling outputResults.
1089  List<String> removeList = Lists.newArrayList();
1090  for (Map.Entry<String, ComponentInfo> entry : components.entrySet()) {
1091  ComponentInfo component = entry.getValue();
1092  if (component.abstractClass || !component.designerComponent) {
1093  removeList.add(entry.getKey());
1094  }
1095  }
1096  components.keySet().removeAll(removeList);
1097 
1098  try {
1099  // This is an abstract method implemented in concrete subclasses.
1100  outputResults();
1101  } catch (IOException e) {
1102  throw new RuntimeException(e);
1103  }
1104 
1105  // We need to return false here so that sibling annotation processors can run
1106  return false;
1107  }
1108 
1109  /*
1110  * This processes an element if it represents a component, reading in its
1111  * information and adding it to components. If this component is a
1112  * subclass of another component, this method recursively calls itself on the
1113  * superclass.
1114  */
1115  private void processComponent(Element element) {
1116  boolean isForDesigner = element.getAnnotation(DesignerComponent.class) != null;
1117  // If the element is not a component (e.g., Float), return early.
1118  if (element.getAnnotation(SimpleObject.class) == null && !isForDesigner) {
1119  return;
1120  }
1121 
1122  // If we already processed this component, return early.
1123  String longComponentName = ((TypeElement) element).getQualifiedName().toString();
1124  if (components.containsKey(longComponentName)) {
1125  return;
1126  }
1127 
1128  // Create new ComponentInfo.
1129  ComponentInfo componentInfo = new ComponentInfo(element);
1130 
1131  // Check if this extends another component (DesignerComponent or SimpleObject).
1132  List<? extends TypeMirror> directSupertypes = typeUtils.directSupertypes(element.asType());
1133  if (!directSupertypes.isEmpty()) {
1134  // Only look at the first one. Later ones would be interfaces,
1135  // which we don't care about.
1136  String parentName = directSupertypes.get(0).toString();
1137  Element e = ((DeclaredType) directSupertypes.get(0)).asElement();
1138  parentName = ((TypeElement) e).getQualifiedName().toString();
1139  ComponentInfo parentComponent = components.get(parentName);
1140  if (parentComponent == null) {
1141  // Try to process the parent component now.
1142  Element parentElement = elementUtils.getTypeElement(parentName);
1143  if (parentElement != null) {
1144  processComponent(parentElement);
1145  parentComponent = components.get(parentName);
1146  }
1147  }
1148 
1149  // If we still can't find the parent class, we don't care about it, since it's not a
1150  // component (but something like java.lang.Object). Otherwise, we need to copy its
1151  // build info, designer properties, properties, methods, and events.
1152  if (parentComponent != null) {
1153  // Copy its build info, designer properties, properties, methods, and events.
1154  componentInfo.permissions.addAll(parentComponent.permissions);
1155  componentInfo.libraries.addAll(parentComponent.libraries);
1156  componentInfo.nativeLibraries.addAll(parentComponent.nativeLibraries);
1157  componentInfo.assets.addAll(parentComponent.assets);
1158  componentInfo.activities.addAll(parentComponent.activities);
1159  componentInfo.metadata.addAll(parentComponent.metadata);
1160  componentInfo.activityMetadata.addAll(parentComponent.activityMetadata);
1161  componentInfo.broadcastReceivers.addAll(parentComponent.broadcastReceivers);
1162  componentInfo.services.addAll(parentComponent.services);
1163  componentInfo.contentProviders.addAll(parentComponent.contentProviders);
1164  // TODO(Will): Remove the following call once the deprecated
1165  // @SimpleBroadcastReceiver annotation is removed. It should
1166  // should remain for the time being because otherwise we'll break
1167  // extensions currently using @SimpleBroadcastReceiver.
1168  componentInfo.classNameAndActionsBR.addAll(parentComponent.classNameAndActionsBR);
1169  // Since we don't modify DesignerProperties, we can just call Map.putAll to copy the
1170  // designer properties from parentComponent to componentInfo.
1171  componentInfo.designerProperties.putAll(parentComponent.designerProperties);
1172  // NOTE(lizlooney) We can't just call Map.putAll to copy the events/properties/methods from
1173  // parentComponent to componentInfo because then each component will share a single
1174  // Event/Property/Method and if one component overrides something about an
1175  // Event/Property/Method, then it will affect all the other components that are sharing
1176  // that Event/Property/Method.
1177  for (Map.Entry<String, Event> entry : parentComponent.events.entrySet()) {
1178  componentInfo.events.put(entry.getKey(), entry.getValue().clone());
1179  }
1180  for (Map.Entry<String, Property> entry : parentComponent.properties.entrySet()) {
1181  componentInfo.properties.put(entry.getKey(), entry.getValue().clone());
1182  }
1183  for (Map.Entry<String, Method> entry : parentComponent.methods.entrySet()) {
1184  componentInfo.methods.put(entry.getKey(), entry.getValue().clone());
1185  }
1186  }
1187  }
1188 
1189  // Gather permissions.
1190  UsesPermissions usesPermissions = element.getAnnotation(UsesPermissions.class);
1191  if (usesPermissions != null) {
1192  for (String permission : usesPermissions.permissionNames().split(",")) {
1193  updateWithNonEmptyValue(componentInfo.permissions, permission);
1194  }
1195  Collections.addAll(componentInfo.permissions, usesPermissions.value());
1196  }
1197 
1198  // Gather library names.
1199  UsesLibraries usesLibraries = element.getAnnotation(UsesLibraries.class);
1200  if (usesLibraries != null) {
1201  for (String library : usesLibraries.libraries().split(",")) {
1202  updateWithNonEmptyValue(componentInfo.libraries, library);
1203  }
1204  Collections.addAll(componentInfo.libraries, usesLibraries.value());
1205  }
1206 
1207  // Gather native library names.
1208  UsesNativeLibraries usesNativeLibraries = element.getAnnotation(UsesNativeLibraries.class);
1209  if (usesNativeLibraries != null) {
1210  for (String nativeLibrary : usesNativeLibraries.libraries().split(",")) {
1211  updateWithNonEmptyValue(componentInfo.nativeLibraries, nativeLibrary);
1212  }
1213  for (String v7aLibrary : usesNativeLibraries.v7aLibraries().split(",")) {
1214  updateWithNonEmptyValue(componentInfo.nativeLibraries, v7aLibrary.trim() + ARMEABI_V7A_SUFFIX);
1215  }
1216  for (String v8aLibrary : usesNativeLibraries.v8aLibraries().split(",")) {
1217  updateWithNonEmptyValue(componentInfo.nativeLibraries, v8aLibrary.trim() + ARM64_V8A_SUFFIX);
1218  }
1219  for (String x8664Library : usesNativeLibraries.x86_64Libraries().split(",")) {
1220  updateWithNonEmptyValue(componentInfo.nativeLibraries, x8664Library.trim() + X86_64_SUFFIX);
1221  }
1222 
1223  }
1224 
1225  // Gather required files.
1226  UsesAssets usesAssets = element.getAnnotation(UsesAssets.class);
1227  if (usesAssets != null) {
1228  for (String file : usesAssets.fileNames().split(",")) {
1229  updateWithNonEmptyValue(componentInfo.assets, file);
1230  }
1231  }
1232 
1233  // Gather the required activities and build their element strings.
1234  UsesActivities usesActivities = element.getAnnotation(UsesActivities.class);
1235  if (usesActivities != null) {
1236  try {
1237  for (ActivityElement ae : usesActivities.activities()) {
1238  updateWithNonEmptyValue(componentInfo.activities, activityElementToString(ae));
1239  }
1240  } catch (IllegalAccessException e) {
1241  messager.printMessage(Diagnostic.Kind.ERROR, "IllegalAccessException when gathering " +
1242  "activity attributes and subelements for component " + componentInfo.name);
1243  throw new RuntimeException(e);
1244  } catch (InvocationTargetException e) {
1245  messager.printMessage(Diagnostic.Kind.ERROR, "InvocationTargetException when gathering " +
1246  "activity attributes and subelements for component " + componentInfo.name);
1247  throw new RuntimeException(e);
1248  }
1249  }
1250 
1251  // Gather the required metadata and build their element strings.
1252  UsesApplicationMetadata usesApplicationMetadata = element.getAnnotation(UsesApplicationMetadata.class);
1253  if (usesApplicationMetadata != null) {
1254  try {
1255  for (MetaDataElement me : usesApplicationMetadata.metaDataElements()) {
1256  updateWithNonEmptyValue(componentInfo.metadata, metaDataElementToString(me));
1257  }
1258  } catch (IllegalAccessException e) {
1259  messager.printMessage(Diagnostic.Kind.ERROR, "IllegalAccessException when gathering " +
1260  "application metadata and subelements for component " + componentInfo.name);
1261  throw new RuntimeException(e);
1262  } catch (InvocationTargetException e) {
1263  messager.printMessage(Diagnostic.Kind.ERROR, "InvocationTargetException when gathering " +
1264  "application metadata and subelements for component " + componentInfo.name);
1265  throw new RuntimeException(e);
1266  }
1267  }
1268 
1269  // Gather the required activity metadata and build their element strings.
1270  UsesActivityMetadata usesActivityMetadata = element.getAnnotation(UsesActivityMetadata.class);
1271  if (usesActivityMetadata != null) {
1272  try {
1273  for (MetaDataElement me : usesActivityMetadata.metaDataElements()) {
1274  updateWithNonEmptyValue(componentInfo.activityMetadata, metaDataElementToString(me));
1275  }
1276  } catch (IllegalAccessException e) {
1277  messager.printMessage(Diagnostic.Kind.ERROR, "IllegalAccessException when gathering " +
1278  "application metadata and subelements for component " + componentInfo.name);
1279  throw new RuntimeException(e);
1280  } catch (InvocationTargetException e) {
1281  messager.printMessage(Diagnostic.Kind.ERROR, "InvocationTargetException when gathering " +
1282  "application metadata and subelements for component " + componentInfo.name);
1283  throw new RuntimeException(e);
1284  }
1285  }
1286 
1287  // Gather the required broadcast receivers and build their element strings.
1288  UsesBroadcastReceivers usesBroadcastReceivers = element.getAnnotation(UsesBroadcastReceivers.class);
1289  if (usesBroadcastReceivers != null) {
1290  try {
1291  for (ReceiverElement re : usesBroadcastReceivers.receivers()) {
1292  updateWithNonEmptyValue(componentInfo.broadcastReceivers, receiverElementToString(re));
1293  }
1294  } catch (IllegalAccessException e) {
1295  messager.printMessage(Diagnostic.Kind.ERROR, "IllegalAccessException when gathering " +
1296  "broadcast receiver attributes and subelements for component " + componentInfo.name);
1297  throw new RuntimeException(e);
1298  } catch (InvocationTargetException e) {
1299  messager.printMessage(Diagnostic.Kind.ERROR, "InvocationTargetException when gathering " +
1300  "broadcast receiver attributes and subelements for component " + componentInfo.name);
1301  throw new RuntimeException(e);
1302  }
1303  }
1304 
1305  // Gather the required services and build their element strings.
1306  UsesServices usesServices = element.getAnnotation(UsesServices.class);
1307  if (usesServices != null) {
1308  try {
1309  for (ServiceElement se : usesServices.services()) {
1310  updateWithNonEmptyValue(componentInfo.services, serviceElementToString(se));
1311  }
1312  } catch (IllegalAccessException e) {
1313  messager.printMessage(Diagnostic.Kind.ERROR, "IllegalAccessException when gathering " +
1314  "service attributes and subelements for component " + componentInfo.name);
1315  throw new RuntimeException(e);
1316  } catch (InvocationTargetException e) {
1317  messager.printMessage(Diagnostic.Kind.ERROR, "InvocationTargetException when gathering " +
1318  "service attributes and subelements for component " + componentInfo.name);
1319  throw new RuntimeException(e);
1320  }
1321  }
1322 
1323  // Gather the required content providers and build their element strings.
1324  UsesContentProviders usesContentProviders = element.getAnnotation(UsesContentProviders.class);
1325  if (usesContentProviders != null) {
1326  try {
1327  for (ProviderElement pe : usesContentProviders.providers()) {
1328  updateWithNonEmptyValue(componentInfo.contentProviders, providerElementToString(pe));
1329  }
1330  } catch (IllegalAccessException e) {
1331  messager.printMessage(Diagnostic.Kind.ERROR, "IllegalAccessException when gathering " +
1332  "provider attributes and subelements for component " + componentInfo.name);
1333  throw new RuntimeException(e);
1334  } catch (InvocationTargetException e) {
1335  messager.printMessage(Diagnostic.Kind.ERROR, "InvocationTargetException when gathering " +
1336  "provider attributes and subelements for component " + componentInfo.name);
1337  throw new RuntimeException(e);
1338  }
1339  }
1340 
1341  // TODO(Will): Remove the following legacy code once the deprecated
1342  // @SimpleBroadcastReceiver annotation is removed. It should
1343  // should remain for the time being because otherwise we'll break
1344  // extensions currently using @SimpleBroadcastReceiver.
1345  //
1346  // Gather required actions for legacy Broadcast Receivers. The annotation
1347  // has a Class Name and zero or more Filter Actions. In the
1348  // resulting String, Class name will go first, and each Action
1349  // will be added, separated by a comma.
1350 
1351  SimpleBroadcastReceiver simpleBroadcastReceiver = element.getAnnotation(SimpleBroadcastReceiver.class);
1352  if (simpleBroadcastReceiver != null) {
1353  for (String className : simpleBroadcastReceiver.className().split(",")){
1354  StringBuffer nameAndActions = new StringBuffer();
1355  nameAndActions.append(className.trim());
1356  for (String action : simpleBroadcastReceiver.actions().split(",")) {
1357  nameAndActions.append("," + action.trim());
1358  }
1359  componentInfo.classNameAndActionsBR.add(nameAndActions.toString());
1360  break; // We only need one class name; If more than one is passed, ignore all but first.
1361  }
1362  }
1363 
1364  // Build up event information.
1365  processEvents(componentInfo, element);
1366 
1367  // Build up property information.
1368  processProperties(componentInfo, element);
1369 
1370  // Build up method information.
1371  processMethods(componentInfo, element);
1372 
1373  if (isForDesigner) {
1374  processDescriptions(componentInfo);
1375  }
1376 
1377  // Add it to our components map.
1378  components.put(longComponentName, componentInfo);
1379  }
1380 
1381  private void processDescriptions(ComponentInfo info) {
1382  final String name = info.displayName;
1383  info.description = info.description.replaceAll(TYPE_PLACEHOLDER, name);
1384  info.helpUrl = info.helpUrl.replaceAll(TYPE_PLACEHOLDER, name);
1385  for (Property property : info.properties.values()) {
1386  property.description = property.description.replaceAll(TYPE_PLACEHOLDER, name);
1387  }
1388  for (Event event : info.events.values()) {
1389  event.description = event.description.replaceAll(TYPE_PLACEHOLDER, name);
1390  }
1391  for (Method method : info.methods.values()) {
1392  method.description = method.description.replaceAll(TYPE_PLACEHOLDER, name);
1393  }
1394  }
1395 
1396  private boolean isPublicMethod(Element element) {
1397  return element.getModifiers().contains(Modifier.PUBLIC)
1398  && element.getKind() == ElementKind.METHOD;
1399  }
1400 
1401  private Property executableElementToProperty(Element element, String componentInfoName) {
1402  String propertyName = element.getSimpleName().toString();
1403  SimpleProperty simpleProperty = element.getAnnotation(SimpleProperty.class);
1404 
1405  if (!(element.asType() instanceof ExecutableType)) {
1406  throw new RuntimeException("element.asType() is not an ExecutableType for " +
1407  propertyName);
1408  }
1409 
1410  // Use Javadoc for property unless description is set to a non-empty string.
1411  String description = elementUtils.getDocComment(element);
1412  String longDescription = description;
1413  if (!simpleProperty.description().isEmpty()) {
1414  description = simpleProperty.description();
1415  }
1416  if (description == null) {
1417  description = "";
1418  }
1419  // Read only until the first javadoc parameter
1420  description = description.split("[^\\\\][@{]")[0].trim();
1421 
1422  Property property = new Property(propertyName,
1423  description,
1424  longDescription,
1425  simpleProperty.category(),
1426  simpleProperty.userVisible(),
1427  elementUtils.isDeprecated(element));
1428 
1429  // Get parameters to tell if this is a getter or setter.
1430  ExecutableType executableType = (ExecutableType) element.asType();
1431  List<? extends TypeMirror> parameters = executableType.getParameterTypes();
1432 
1433  // Check if it is a setter or getter, and set the property's readable, writable,
1434  // and type fields appropriately.
1435  TypeMirror typeMirror;
1436  if (parameters.size() == 0) {
1437  // It is a getter.
1438  property.readable = true;
1439  typeMirror = executableType.getReturnType();
1440  if (typeMirror.getKind().equals(TypeKind.VOID)) {
1441  throw new RuntimeException("Property method is void and has no parameters: "
1442  + propertyName);
1443  }
1444  if (element.getAnnotation(IsColor.class) != null) {
1445  property.color = true;
1446  }
1447  } else {
1448  // It is a setter.
1449  property.writable = true;
1450  if (parameters.size() != 1) {
1451  throw new RuntimeException("Too many parameters for setter for " +
1452  propertyName);
1453  }
1454  typeMirror = parameters.get(0);
1455  for (VariableElement ve : ((ExecutableElement) element).getParameters()) {
1456  if (ve.getAnnotation(IsColor.class) != null) {
1457  property.color = true;
1458  }
1459  }
1460  }
1461 
1462  // Use typeMirror to set the property's type.
1463  if (!typeMirror.getKind().equals(TypeKind.VOID)) {
1464  property.type = typeMirror.toString();
1465  updateComponentTypes(typeMirror);
1466  }
1467 
1468  property.componentInfoName = componentInfoName;
1469 
1470  return property;
1471  }
1472 
1473  // Transform an @ActivityElement into an XML element String for use later
1474  // in creating AndroidManifest.xml.
1475  private static String activityElementToString(ActivityElement element)
1476  throws IllegalAccessException, InvocationTargetException {
1477  // First, we build the <activity> element's opening tag including any
1478  // receiver element attributes.
1479  StringBuilder elementString = new StringBuilder(" <activity ");
1480  elementString.append(elementAttributesToString(element));
1481  elementString.append(">\\n");
1482 
1483  // Now, we collect any <activity> subelements.
1484  elementString.append(subelementsToString(element.metaDataElements()));
1485  elementString.append(subelementsToString(element.intentFilters()));
1486 
1487  // Finally, we close the <activity> element and create its String.
1488  return elementString.append(" </activity>\\n").toString();
1489  }
1490 
1491  // Transform a @ReceiverElement into an XML element String for use later
1492  // in creating AndroidManifest.xml.
1493  private static String receiverElementToString(ReceiverElement element)
1494  throws IllegalAccessException, InvocationTargetException {
1495  // First, we build the <receiver> element's opening tag including any
1496  // receiver element attributes.
1497  StringBuilder elementString = new StringBuilder(" <receiver ");
1498  elementString.append(elementAttributesToString(element));
1499  elementString.append(">\\n");
1500 
1501  // Now, we collect any <receiver> subelements.
1502  elementString.append(subelementsToString(element.metaDataElements()));
1503  elementString.append(subelementsToString(element.intentFilters()));
1504 
1505  // Finally, we close the <receiver> element and create its String.
1506  return elementString.append(" </receiver>\\n").toString();
1507  }
1508 
1509  // Transform a @ServiceElement into an XML element String for use later
1510  // in creating AndroidManifest.xml.
1511  private static String serviceElementToString(ServiceElement element)
1512  throws IllegalAccessException, InvocationTargetException {
1513  // First, we build the <service> element's opening tag including any
1514  // service element attributes.
1515  StringBuilder elementString = new StringBuilder(" <service ");
1516  elementString.append(elementAttributesToString(element));
1517  elementString.append(">\\n");
1518 
1519  // Now, we collect any <service> subelements.
1520  elementString.append(subelementsToString(element.metaDataElements()));
1521  elementString.append(subelementsToString(element.intentFilters()));
1522 
1523  // Finally, we close the <service> element and create its String.
1524  return elementString.append(" </service>\\n").toString();
1525  }
1526 
1527  // Transform a @ProviderElement into an XML element String for use later
1528  // in creating AndroidManifest.xml.
1529  private static String providerElementToString(ProviderElement element)
1530  throws IllegalAccessException, InvocationTargetException {
1531  // First, we build the <provider> element's opening tag including any
1532  // content provider element attributes.
1533  StringBuilder elementString = new StringBuilder(" <provider ");
1534  elementString.append(elementAttributesToString(element));
1535  elementString.append(">\\n");
1536 
1537  // Now, we collect any <provider> subelements.
1538  elementString.append(subelementsToString(element.metaDataElements()));
1539  elementString.append(subelementsToString(element.pathPermissionElement()));
1540  elementString.append(subelementsToString(element.grantUriPermissionElement()));
1541 
1542  // Finally, we close the <provider> element and create its String.
1543  return elementString.append(" </provider>\\n").toString();
1544  }
1545 
1546  // Transform a @MetaDataElement into an XML element String for use later
1547  // in creating AndroidManifest.xml.
1548  private static String metaDataElementToString(MetaDataElement element)
1549  throws IllegalAccessException, InvocationTargetException {
1550  // First, we build the <meta-data> element's opening tag including any
1551  // receiver element attributes.
1552  StringBuilder elementString = new StringBuilder(" <meta-data ");
1553  elementString.append(elementAttributesToString(element));
1554  // Finally, we close the <meta-data> element and create its String.
1555  return elementString.append("/>\\n").toString();
1556  }
1557 
1558  // Transform an @IntentFilterElement into an XML element String for use later
1559  // in creating AndroidManifest.xml.
1560  private static String intentFilterElementToString(IntentFilterElement element)
1561  throws IllegalAccessException, InvocationTargetException {
1562  // First, we build the <intent-filter> element's opening tag including any
1563  // receiver element attributes.
1564  StringBuilder elementString = new StringBuilder(" <intent-filter ");
1565  elementString.append(elementAttributesToString(element));
1566  elementString.append(">\\n");
1567 
1568  // Now, we collect any <intent-filter> subelements.
1569  elementString.append(subelementsToString(element.actionElements()));
1570  elementString.append(subelementsToString(element.categoryElements()));
1571  elementString.append(subelementsToString(element.dataElements()));
1572 
1573  // Finally, we close the <intent-filter> element and create its String.
1574  return elementString.append(" </intent-filter>\\n").toString();
1575  }
1576 
1577  // Transform an @ActionElement into an XML element String for use later
1578  // in creating AndroidManifest.xml.
1579  private static String actionElementToString(ActionElement element)
1580  throws IllegalAccessException, InvocationTargetException {
1581  // First, we build the <action> element's opening tag including any
1582  // receiver element attributes.
1583  StringBuilder elementString = new StringBuilder(" <action ");
1584  elementString.append(elementAttributesToString(element));
1585  // Finally, we close the <action> element and create its String.
1586  return elementString.append("/>\\n").toString();
1587  }
1588 
1589  // Transform a @CategoryElement into an XML element String for use later
1590  // in creating AndroidManifest.xml.
1591  private static String categoryElementToString(CategoryElement element)
1592  throws IllegalAccessException, InvocationTargetException {
1593  // First, we build the <category> element's opening tag including any
1594  // receiver element attributes.
1595  StringBuilder elementString = new StringBuilder(" <category ");
1596  elementString.append(elementAttributesToString(element));
1597  // Finally, we close the <category> element and create its String.
1598  return elementString.append("/>\\n").toString();
1599  }
1600 
1601  // Transform a @DataElement into an XML element String for use later
1602  // in creating AndroidManifest.xml.
1603  private static String dataElementToString(DataElement element)
1604  throws IllegalAccessException, InvocationTargetException {
1605  // First, we build the <data> element's opening tag including any
1606  // receiver element attributes.
1607  StringBuilder elementString = new StringBuilder(" <data ");
1608  elementString.append(elementAttributesToString(element));
1609  // Finally, we close the <data> element and create its String.
1610  return elementString.append("/>\\n").toString();
1611  }
1612 
1613  // Transform a @PathPermissionElement into an XML element String for use later
1614  // in creating AndroidManifest.xml.
1615  private static String pathPermissionElementToString(PathPermissionElement element)
1616  throws IllegalAccessException, InvocationTargetException {
1617  // First, we build the <path-permission> element's opening tag including any
1618  // receiver element attributes.
1619  StringBuilder elementString = new StringBuilder(" <path-permission ");
1620  elementString.append(elementAttributesToString(element));
1621  // Finally, we close the <path-permission> element and create its String.
1622  return elementString.append("/>\\n").toString();
1623  }
1624 
1625  // Transform a @GrantUriPermissionElement into an XML element String for use later
1626  // in creating AndroidManifest.xml.
1627  private static String grantUriPermissionElementToString(GrantUriPermissionElement element)
1628  throws IllegalAccessException, InvocationTargetException {
1629  // First, we build the <grant-uri-permission> element's opening tag including any
1630  // receiver element attributes.
1631  StringBuilder elementString = new StringBuilder(" <grant-uri-permission ");
1632  elementString.append(elementAttributesToString(element));
1633  // Finally, we close the <grant-uri-permission> element and create its String.
1634  return elementString.append("/>\\n").toString();
1635  }
1636 
1637  // Build the attribute String for a given XML element modeled by an
1638  // annotation.
1639  //
1640  // Note that we use the fully qualified names for certain classes in the
1641  // "java.lang.reflect" package to avoid namespace collisions.
1642  private static String elementAttributesToString(Annotation element)
1643  throws IllegalAccessException, InvocationTargetException {
1644  StringBuilder attributeString = new StringBuilder("");
1645  Class<? extends Annotation> clazz = element.annotationType();
1646  java.lang.reflect.Method[] methods = clazz.getDeclaredMethods();
1647  String attributeSeparator = "";
1648  for (java.lang.reflect.Method method : methods) {
1649  int modCode = method.getModifiers();
1650  if (java.lang.reflect.Modifier.isPublic(modCode)
1651  && !java.lang.reflect.Modifier.isStatic(modCode)) {
1652  if (method.getReturnType().getSimpleName().equals("String")) {
1653  // It is an XML element attribute.
1654  String attributeValue = (String) method.invoke(clazz.cast(element));
1655  if (!attributeValue.equals("")) {
1656  attributeString.append(attributeSeparator);
1657  attributeString.append("android:");
1658  attributeString.append(method.getName());
1659  attributeString.append("=\\\"");
1660  attributeString.append(attributeValue);
1661  attributeString.append("\\\"");
1662  attributeSeparator = " ";
1663  }
1664  }
1665  }
1666  }
1667  return attributeString.toString();
1668  }
1669 
1670  // Build the subelement String for a given array of XML elements modeled by
1671  // corresponding annotations.
1672  private static String subelementsToString(Annotation[] subelements)
1673  throws IllegalAccessException, InvocationTargetException {
1674  StringBuilder subelementString = new StringBuilder("");
1675  for (Annotation subelement : subelements) {
1676  if (subelement instanceof MetaDataElement) {
1677  subelementString.append(metaDataElementToString((MetaDataElement) subelement));
1678  } else if (subelement instanceof IntentFilterElement) {
1679  subelementString.append(intentFilterElementToString((IntentFilterElement) subelement));
1680  } else if (subelement instanceof ActionElement) {
1681  subelementString.append(actionElementToString((ActionElement) subelement));
1682  } else if (subelement instanceof CategoryElement) {
1683  subelementString.append(categoryElementToString((CategoryElement) subelement));
1684  } else if (subelement instanceof DataElement) {
1685  subelementString.append(dataElementToString((DataElement) subelement));
1686  } else if (subelement instanceof PathPermissionElement) {
1687  subelementString.append(pathPermissionElementToString((PathPermissionElement) subelement));
1688  } else if (subelement instanceof GrantUriPermissionElement) {
1689  subelementString.append(grantUriPermissionElementToString((GrantUriPermissionElement) subelement));
1690  }
1691  }
1692  return subelementString.toString();
1693  }
1694 
1695  private void processProperties(ComponentInfo componentInfo,
1696  Element componentElement) {
1697  // We no longer support properties that use the variant type.
1698 
1699  Map<String, Element> propertyElementsToCheck = new HashMap<>();
1700 
1701  for (Element element : componentElement.getEnclosedElements()) {
1702  if (!isPublicMethod(element)) {
1703  continue;
1704  }
1705 
1706  // Get the name of the prospective property.
1707  String propertyName = element.getSimpleName().toString();
1708  processConditionalAnnotations(componentInfo, element, propertyName);
1709 
1710  // Designer property information
1711  DesignerProperty designerProperty = element.getAnnotation(DesignerProperty.class);
1712  if (designerProperty != null) {
1713  componentInfo.designerProperties.put(propertyName, designerProperty);
1714  propertyElementsToCheck.put(propertyName, element);
1715  }
1716 
1717  // If property is overridden without again using SimpleProperty, remove
1718  // it. For example, this is done for Ball.Width(), which overrides the
1719  // inherited property Width() because Ball uses Radius() instead.
1720  if (element.getAnnotation(SimpleProperty.class) == null) {
1721  if (componentInfo.properties.containsKey(propertyName)) {
1722  // Look at the prior property's componentInfoName.
1723  Property priorProperty = componentInfo.properties.get(propertyName);
1724  if (priorProperty.componentInfoName.equals(componentInfo.name)) {
1725  // The prior property's componentInfoName is the same as this componentInfo's name.
1726  // This is just a read-only or write-only property. We don't need to do anything
1727  // special here.
1728  } else {
1729  // The prior property's componentInfoName is the different than this componentInfo's
1730  // name. This is an overridden property without the SimpleProperty annotation and we
1731  // need to remove it.
1732  componentInfo.properties.remove(propertyName);
1733  }
1734  }
1735  } else {
1736  // Create a new Property element, then compare and combine it with any
1737  // prior Property element with the same property name, verifying that
1738  // they are consistent.
1739  Property newProperty = executableElementToProperty(element, componentInfo.name);
1740  if (designerProperty != null
1741  && designerProperty.editorType().equals(PropertyTypeConstants.PROPERTY_TYPE_COLOR)) {
1742  // Properties that use a color editor should be marked as a color property
1743  newProperty.color = true;
1744  }
1745 
1746  if (componentInfo.properties.containsKey(propertyName)) {
1747  Property priorProperty = componentInfo.properties.get(propertyName);
1748 
1749  if (!priorProperty.type.equals(newProperty.type)) {
1750  // The 'real' type of a property is determined by its getter, if
1751  // it has one. In theory there can be multiple setters which
1752  // take different types and those types can differ from the
1753  // getter.
1754  if (newProperty.readable) {
1755  priorProperty.type = newProperty.type;
1756  } else if (priorProperty.writable) {
1757  // TODO(user): handle lang_def and document generation for multiple setters.
1758  throw new RuntimeException("Inconsistent types " + priorProperty.type +
1759  " and " + newProperty.type + " for property " +
1760  propertyName + " in component " + componentInfo.name);
1761  }
1762  }
1763 
1764  // Merge newProperty into priorProperty, which is already in the properties map.
1765  if ((priorProperty.description.isEmpty() || priorProperty.isDefaultDescription()
1766  || element.getAnnotation(Override.class) != null)
1767  && !newProperty.description.isEmpty() && !newProperty.isDefaultDescription()) {
1768  priorProperty.setDescription(newProperty.description);
1769  }
1770  if (!newProperty.longDescription.isEmpty()) { /* Latter descriptions of the same property
1771  override earlier descriptions. */
1772  priorProperty.longDescription = newProperty.longDescription;
1773  }
1774  if (priorProperty.propertyCategory == PropertyCategory.UNSET) {
1775  priorProperty.propertyCategory = newProperty.propertyCategory;
1776  } else if (newProperty.propertyCategory != priorProperty.propertyCategory &&
1777  newProperty.propertyCategory != PropertyCategory.UNSET) {
1778  throw new RuntimeException(
1779  "Property " + propertyName + " has inconsistent categories " +
1780  priorProperty.propertyCategory + " and " +
1781  newProperty.propertyCategory + " in component " +
1782  componentInfo.name);
1783  }
1784  priorProperty.readable = priorProperty.readable || newProperty.readable;
1785  priorProperty.writable = priorProperty.writable || newProperty.writable;
1786  priorProperty.userVisible = priorProperty.isUserVisible() && newProperty.isUserVisible();
1787  priorProperty.deprecated = priorProperty.isDeprecated() && newProperty.isDeprecated();
1788  priorProperty.componentInfoName = componentInfo.name;
1789  priorProperty.color = newProperty.color || priorProperty.color;
1790  } else {
1791  // Add the new property to the properties map.
1792  componentInfo.properties.put(propertyName, newProperty);
1793  }
1794  }
1795  }
1796 
1797  // Verify that every DesignerComponent has a corresponding property entry. A mismatch results
1798  // in App Inventor being unable to generate code for the designer since the type information
1799  // is in the block property only. We check that the designer property name is also present
1800  // in the block properties. If not, an error is reported and the build terminates.
1801  Set<String> propertyNames = new HashSet<>(componentInfo.designerProperties.keySet());
1802  propertyNames.removeAll(componentInfo.properties.keySet());
1803  if (!propertyNames.isEmpty()) {
1804  for (String propertyName : propertyNames) {
1805  messager.printMessage(Kind.ERROR,
1806  String.format(MISSING_SIMPLE_PROPERTY_ANNOTATION, propertyName),
1807  propertyElementsToCheck.get(propertyName));
1808  }
1809  }
1810  }
1811 
1812  // Note: The top halves of the bodies of processEvent() and processMethods()
1813  // are very similar. I tried refactoring in several ways but it just made
1814  // things more complex.
1815  private void processEvents(ComponentInfo componentInfo,
1816  Element componentElement) {
1817  for (Element element : componentElement.getEnclosedElements()) {
1818  if (!isPublicMethod(element)) {
1819  continue;
1820  }
1821 
1822  // Get the name of the prospective event.
1823  String eventName = element.getSimpleName().toString();
1824  processConditionalAnnotations(componentInfo, element, eventName);
1825 
1826  SimpleEvent simpleEventAnnotation = element.getAnnotation(SimpleEvent.class);
1827 
1828  // Remove overriden events unless SimpleEvent is again specified.
1829  // See comment in processProperties for an example.
1830  if (simpleEventAnnotation == null) {
1831  if (componentInfo.events.containsKey(eventName)) {
1832  componentInfo.events.remove(eventName);
1833  }
1834  } else {
1835  String eventDescription = simpleEventAnnotation.description();
1836  String longEventDescription = elementUtils.getDocComment(element);
1837  if (eventDescription.isEmpty()) {
1838  eventDescription = longEventDescription;
1839  if (eventDescription == null) {
1840  messager.printMessage(Diagnostic.Kind.WARNING,
1841  "In component " + componentInfo.name +
1842  ", event " + eventName +
1843  " is missing a description.");
1844  eventDescription = "";
1845  }
1846  }
1847  boolean userVisible = simpleEventAnnotation.userVisible();
1848  boolean deprecated = elementUtils.isDeprecated(element);
1849  Event event = new Event(eventName, eventDescription, longEventDescription, userVisible, deprecated);
1850  componentInfo.events.put(event.name, event);
1851 
1852  // Verify that this element has an ExecutableType.
1853  if (!(element instanceof ExecutableElement)) {
1854  throw new RuntimeException("In component " + componentInfo.name +
1855  ", the representation of SimpleEvent " + eventName +
1856  " does not implement ExecutableElement.");
1857  }
1858  ExecutableElement e = (ExecutableElement) element;
1859 
1860  // Extract the parameters.
1861  for (VariableElement ve : e.getParameters()) {
1862  event.addParameter(ve.getSimpleName().toString(),
1863  ve.asType().toString(),
1864  ve.getAnnotation(IsColor.class) != null);
1865  updateComponentTypes(ve.asType());
1866  }
1867  }
1868  }
1869  }
1870 
1871  private void processMethods(ComponentInfo componentInfo,
1872  Element componentElement) {
1873  for (Element element : componentElement.getEnclosedElements()) {
1874  if (!isPublicMethod(element)) {
1875  continue;
1876  }
1877 
1878  // Get the name of the prospective method.
1879  String methodName = element.getSimpleName().toString();
1880  processConditionalAnnotations(componentInfo, element, methodName);
1881 
1882  SimpleFunction simpleFunctionAnnotation = element.getAnnotation(SimpleFunction.class);
1883 
1884  // Remove overriden methods unless SimpleFunction is again specified.
1885  // See comment in processProperties for an example.
1886  if (simpleFunctionAnnotation == null) {
1887  if (componentInfo.methods.containsKey(methodName)) {
1888  componentInfo.methods.remove(methodName);
1889  }
1890  } else {
1891  String methodLongDescription = elementUtils.getDocComment(element);
1892  String methodDescription = simpleFunctionAnnotation.description();
1893  if (methodDescription.isEmpty()) {
1894  methodDescription = methodLongDescription;
1895  if (methodDescription == null) {
1896  messager.printMessage(Diagnostic.Kind.WARNING,
1897  "In component " + componentInfo.name +
1898  ", method " + methodName +
1899  " is missing a description.");
1900  methodDescription = "";
1901  }
1902  }
1903  boolean userVisible = simpleFunctionAnnotation.userVisible();
1904  boolean deprecated = elementUtils.isDeprecated(element);
1905  Method method = new Method(methodName, methodDescription, methodLongDescription, userVisible, deprecated);
1906  componentInfo.methods.put(method.name, method);
1907 
1908  // Verify that this element has an ExecutableType.
1909  if (!(element instanceof ExecutableElement)) {
1910  throw new RuntimeException("In component " + componentInfo.name +
1911  ", the representation of SimpleFunction " + methodName +
1912  " does not implement ExecutableElement.");
1913  }
1914  ExecutableElement e = (ExecutableElement) element;
1915 
1916  // Extract the parameters.
1917  for (VariableElement ve : e.getParameters()) {
1918  method.addParameter(ve.getSimpleName().toString(),
1919  ve.asType().toString(),
1920  ve.getAnnotation(IsColor.class) != null);
1921  updateComponentTypes(ve.asType());
1922  }
1923 
1924  // Extract the return type.
1925  if (e.getReturnType().getKind() != TypeKind.VOID) {
1926  method.returnType = e.getReturnType().toString();
1927  if (e.getAnnotation(IsColor.class) != null) {
1928  method.color = true;
1929  }
1930  updateComponentTypes(e.getReturnType());
1931  }
1932  }
1933  }
1934  }
1935 
1945  private void processConditionalAnnotations(ComponentInfo componentInfo, Element element,
1946  String blockName) {
1947  // Conditional UsesPermissions
1948  UsesPermissions usesPermissions = element.getAnnotation(UsesPermissions.class);
1949  if (usesPermissions != null) {
1950  componentInfo.conditionalPermissions.put(blockName, usesPermissions.value());
1951  }
1952 
1953  UsesBroadcastReceivers broadcastReceiver = element.getAnnotation(UsesBroadcastReceivers.class);
1954  if (broadcastReceiver != null) {
1955  try {
1956  Set<String> receivers = new HashSet<>();
1957  for (ReceiverElement re : broadcastReceiver.receivers()) {
1958  updateWithNonEmptyValue(receivers, receiverElementToString(re));
1959  }
1960  componentInfo.conditionalBroadcastReceivers.put(blockName, receivers.toArray(new String[0]));
1961  } catch (Exception e) {
1962  messager.printMessage(Kind.ERROR, "Unable to process broadcast receiver", element);
1963  }
1964  }
1965 
1966  UsesServices service = element.getAnnotation(UsesServices.class);
1967  if (service != null) {
1968  try {
1969  Set<String> services = new HashSet<>();
1970  for (ServiceElement se : service.services()) {
1971  updateWithNonEmptyValue(services, serviceElementToString(se));
1972  }
1973  componentInfo.conditionalServices.put(blockName, services.toArray(new String[0]));
1974  } catch (Exception e) {
1975  messager.printMessage(Kind.ERROR, "Unable to process service", element);
1976  }
1977  }
1978 
1979  UsesContentProviders contentProvider = element.getAnnotation(UsesContentProviders.class);
1980  if (contentProvider != null) {
1981  try {
1982  Set<String> providers = new HashSet<>();
1983  for (ProviderElement pe : contentProvider.providers()) {
1984  updateWithNonEmptyValue(providers, providerElementToString(pe));
1985  }
1986  componentInfo.conditionalContentProviders.put(blockName, providers.toArray(new String[0]));
1987  } catch (Exception e) {
1988  messager.printMessage(Kind.ERROR, "Unable to process content provider", element);
1989  }
1990  }
1991  }
1992 
2002  protected abstract void outputResults() throws IOException;
2003 
2014  protected final String javaTypeToYailType(String type) {
2015  if (BOXED_TYPES.containsKey(type)) {
2016  throw new IllegalArgumentException(String.format(BOXED_TYPE_ERROR, type,
2017  BOXED_TYPES.get(type)));
2018  }
2019  // boolean -> boolean
2020  if (type.equals("boolean")) {
2021  return type;
2022  }
2023  // String -> text
2024  if (type.equals("java.lang.String")) {
2025  return "text";
2026  }
2027  // {float, double, int, short, long, byte} -> number
2028  if (type.equals("float") || type.equals("double") || type.equals("int") ||
2029  type.equals("short") || type.equals("long") || type.equals("byte")) {
2030  return "number";
2031  }
2032  // YailList -> list
2033  if (type.equals("com.google.appinventor.components.runtime.util.YailList")) {
2034  return "list";
2035  }
2036  // List<?> -> list
2037  if (type.startsWith("java.util.List")) {
2038  return "list";
2039  }
2040  if (type.equals("com.google.appinventor.components.runtime.util.YailDictionary")) {
2041  return "dictionary";
2042  }
2043  if (type.equals("com.google.appinventor.components.runtime.util.YailObject")) {
2044  return "yailobject";
2045  }
2046 
2047  // Calendar -> InstantInTime
2048  if (type.equals("java.util.Calendar")) {
2049  return "InstantInTime";
2050  }
2051 
2052  if (type.equals("java.lang.Object")) {
2053  return "any";
2054  }
2055 
2056  if (type.equals("com.google.appinventor.components.runtime.Component")) {
2057  return "component";
2058  }
2059 
2060  // Check if it's a component.
2061  if (componentTypes.contains(type)) {
2062  return "component";
2063  }
2064 
2065  throw new IllegalArgumentException("Cannot convert Java type '" + type + "' to Yail type");
2066  }
2067 
2075  protected FileObject createOutputFileObject(String fileName) throws IOException {
2076  return processingEnv.getFiler().
2077  createResource(StandardLocation.SOURCE_OUTPUT, OUTPUT_PACKAGE, fileName);
2078  }
2079 
2090  protected Writer getOutputWriter(String fileName) throws IOException {
2091  return createOutputFileObject(fileName).openWriter();
2092  }
2093 
2102  private void updateComponentTypes(TypeMirror type) {
2103  if (type.getKind() == TypeKind.DECLARED) {
2104  type.accept(new SimpleTypeVisitor7<Boolean, Set<String>>(false) {
2105  @Override
2106  public Boolean visitDeclared(DeclaredType t, Set<String> types) {
2107  final String typeName = t.asElement().toString();
2108  if ("com.google.appinventor.components.runtime.Component".equals(typeName)) {
2109  return true;
2110  }
2111  if (!types.contains(typeName)) {
2112  types.add(typeName);
2113  final TypeElement typeElement = (TypeElement) t.asElement();
2114  if (typeElement.getSuperclass().accept(this, types)) {
2115  componentTypes.add(typeName);
2116  return true;
2117  }
2118  for (TypeMirror iface : typeElement.getInterfaces()) {
2119  if (iface.accept(this, types)) {
2120  componentTypes.add(typeName);
2121  return true;
2122  }
2123  }
2124  }
2125  return componentTypes.contains(typeName);
2126  }
2127  }, visitedTypes);
2128  }
2129  }
2130 
2131  private void updateWithNonEmptyValue(Set<String> collection, String value) {
2132  String trimmedValue = value.trim();
2133  if (!trimmedValue.isEmpty()) {
2134  collection.add(trimmedValue);
2135  }
2136  }
2137 }
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.methods
final SortedMap< String, Method > methods
Definition: ComponentProcessor.java:746
com.google.appinventor.components.scripts.ComponentProcessor.Parameter.color
final boolean color
Definition: ComponentProcessor.java:234
com.google.appinventor.components.annotations.SimpleFunction
Definition: SimpleFunction.java:23
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.external
boolean external
Definition: ComponentProcessor.java:768
com.google.appinventor.components.scripts.ComponentProcessor.Event.compareTo
int compareTo(Event e)
Definition: ComponentProcessor.java:479
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.contentProviders
final Set< String > contentProviders
Definition: ComponentProcessor.java:719
com.google.appinventor.components.annotations.UsesLibraries
Definition: UsesLibraries.java:21
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.events
final SortedMap< String, Event > events
Definition: ComponentProcessor.java:751
com.google.appinventor.components.annotations.UsesServices
Definition: UsesServices.java:24
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.metadata
final Set< String > metadata
Definition: ComponentProcessor.java:699
com.google.appinventor.components.scripts.ComponentProcessor.Parameter.type
final String type
Definition: ComponentProcessor.java:232
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.permissions
final Set< String > permissions
Definition: ComponentProcessor.java:650
com.google.appinventor.components.scripts.ComponentProcessor.Parameter.parameterToYailType
String parameterToYailType(Parameter parameter)
Definition: ComponentProcessor.java:263
com.google.appinventor.components.annotations.DesignerProperty
Definition: DesignerProperty.java:25
com.google.appinventor.components.scripts.ComponentProcessor.ParameterizedFeature.toParameterString
String toParameterString()
Definition: ComponentProcessor.java:443
com.google.appinventor.components.scripts.ComponentProcessor.Event.Event
Event(String name, String description, String longDescription, boolean userVisible, boolean deprecated)
Definition: ComponentProcessor.java:465
com.google.appinventor.components.annotations.DesignerComponent.showOnPalette
boolean showOnPalette() default true
com.google.appinventor.components.common.ComponentCategory.getName
String getName()
Definition: ComponentCategory.java:99
com.google.appinventor.components.annotations.UsesNativeLibraries
Definition: UsesNativeLibraries.java:21
com.google.appinventor.components
com.google.appinventor.components.annotations.DesignerComponent.iconName
String iconName() default ""
com.google.appinventor.components.annotations.androidmanifest.MetaDataElement
Definition: MetaDataElement.java:44
com.google.appinventor.components.scripts.ComponentProcessor.Method
Definition: ComponentProcessor.java:488
com.google.appinventor.components.annotations.androidmanifest.ActionElement
Definition: ActionElement.java:31
com.google.appinventor.components.annotations.SimpleBroadcastReceiver
Definition: SimpleBroadcastReceiver.java:23
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.properties
final SortedMap< String, Property > properties
Definition: ComponentProcessor.java:741
com.google.appinventor.components.scripts.ComponentProcessor.Parameter
Definition: ComponentProcessor.java:223
com.google.appinventor.components.annotations.DesignerComponent
Definition: DesignerComponent.java:22
com.google.appinventor.components.annotations.SimpleEvent
Definition: SimpleEvent.java:20
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.conditionalBroadcastReceivers
final Map< String, String[]> conditionalBroadcastReceivers
Definition: ComponentProcessor.java:662
com.google.appinventor.components.annotations.DesignerComponent.androidMinSdk
int androidMinSdk() default ComponentConstants.APP_INVENTOR_MIN_SDK
com.google.appinventor.components.scripts.ComponentProcessor.Method.isColor
boolean isColor()
Definition: ComponentProcessor.java:504
com.google.appinventor.components.scripts.ComponentProcessor.Parameter.Parameter
Parameter(String name, String type)
Definition: ComponentProcessor.java:242
com.google.appinventor.components.annotations.androidmanifest.ReceiverElement
Definition: ReceiverElement.java:34
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.getCategoryString
String getCategoryString()
Definition: ComponentProcessor.java:928
com.google.appinventor.components.scripts.ComponentProcessor.Method.clone
Method clone()
Definition: ComponentProcessor.java:509
com.google.appinventor.components.annotations.DesignerComponent.version
int version()
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.getHelpDescription
String getHelpDescription()
Definition: ComponentProcessor.java:898
com.google.appinventor.components.annotations.androidmanifest.PathPermissionElement
Definition: PathPermissionElement.java:32
com.google.appinventor.components.scripts.ComponentProcessor.Parameter.name
final String name
Definition: ComponentProcessor.java:227
com.google.appinventor.components.annotations.androidmanifest.IntentFilterElement
Definition: IntentFilterElement.java:30
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.libraries
final Set< String > libraries
Definition: ComponentProcessor.java:679
com.google.appinventor.components.annotations.DesignerComponent.category
ComponentCategory category() default ComponentCategory.UNINITIALIZED
com.google.appinventor.components.annotations.DesignerComponent.helpUrl
String helpUrl() default ""
com.google.appinventor.components.annotations.UsesPermissions
Definition: UsesPermissions.java:21
com.google.appinventor.components.annotations.androidmanifest.DataElement
Definition: DataElement.java:38
com.google.appinventor.components.scripts.ComponentProcessor.Event
Definition: ComponentProcessor.java:461
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.conditionalPermissions
final Map< String, String[]> conditionalPermissions
Definition: ComponentProcessor.java:656
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.type
final String type
Definition: ComponentProcessor.java:767
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.assets
final Set< String > assets
Definition: ComponentProcessor.java:689
com.google.appinventor.components.annotations.androidmanifest
Definition: ActionElement.java:6
com.google.appinventor.components.scripts.ComponentProcessor.messager
Messager messager
Definition: ComponentProcessor.java:194
com.google.appinventor.components.annotations.UsesAssets
Definition: UsesAssets.java:21
com.google.appinventor.components.scripts.ComponentProcessor.ParameterizedFeature.parameters
final List< Parameter > parameters
Definition: ComponentProcessor.java:419
com.google.appinventor.components.scripts.ComponentProcessor.Method.getReturnType
String getReturnType()
Definition: ComponentProcessor.java:500
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.activityMetadata
final Set< String > activityMetadata
Definition: ComponentProcessor.java:704
com.google.appinventor.components.annotations.SimpleObject.external
boolean external() default false
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.conditionalContentProviders
final Map< String, String[]> conditionalContentProviders
Definition: ComponentProcessor.java:674
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.getHelpUrl
String getHelpUrl()
Definition: ComponentProcessor.java:907
com.google.appinventor.components.scripts.ComponentProcessor.Method.Method
Method(String name, String description, String longDescription, boolean userVisible, boolean deprecated)
Definition: ComponentProcessor.java:494
com.google.appinventor.components.annotations.UsesBroadcastReceivers
Definition: UsesBroadcastReceivers.java:24
com.google.appinventor.components.annotations.SimpleProperty
Definition: SimpleProperty.java:23
com.google.appinventor.components.annotations.DesignerComponent.nonVisible
boolean nonVisible() default false
com.google.appinventor.components.annotations.PropertyCategory
Definition: PropertyCategory.java:13
com.google.appinventor.components.scripts.ComponentProcessor.Method.compareTo
int compareTo(Method f)
Definition: ComponentProcessor.java:519
com.google.appinventor.components.annotations.DesignerComponent.description
String description() default ""
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.getVersion
int getVersion()
Definition: ComponentProcessor.java:938
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo
Definition: ComponentProcessor.java:644
com.google.appinventor.components.scripts.ComponentProcessor.ParameterizedFeature.addParameter
void addParameter(String name, String type)
Definition: ComponentProcessor.java:427
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.conditionalServices
final Map< String, String[]> conditionalServices
Definition: ComponentProcessor.java:668
com.google.appinventor.components.annotations.DesignerComponent.designerHelpDescription
String designerHelpDescription() default ""
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.ComponentInfo
ComponentInfo(Element element)
Definition: ComponentProcessor.java:784
com.google.appinventor.components.annotations.DesignerComponent.versionName
String versionName() default ""
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.getShowOnPalette
boolean getShowOnPalette()
Definition: ComponentProcessor.java:948
com.google.appinventor.components.scripts.ComponentProcessor.ParameterizedFeature.addParameter
void addParameter(String name, String type, boolean color)
Definition: ComponentProcessor.java:431
com.google.appinventor.components.common
Definition: ComponentCategory.java:7
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.designerProperties
final SortedMap< String, DesignerProperty > designerProperties
Definition: ComponentProcessor.java:734
com.google.appinventor.components.scripts.ComponentProcessor.components
final SortedMap< String, ComponentInfo > components
Definition: ComponentProcessor.java:207
com.google.appinventor.components.annotations.androidmanifest.ServiceElement
Definition: ServiceElement.java:35
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.services
final Set< String > services
Definition: ComponentProcessor.java:714
com.google.appinventor.components.annotations.SimpleObject
Definition: SimpleObject.java:23
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.activities
final Set< String > activities
Definition: ComponentProcessor.java:694
com.google.appinventor.components.scripts.ComponentProcessor.Event.clone
Event clone()
Definition: ComponentProcessor.java:470
com.google.appinventor.components.scripts.ComponentProcessor.ParameterizedFeature
Definition: ComponentProcessor.java:417
com.google
com.google.appinventor.components.annotations.UsesContentProviders
Definition: UsesContentProviders.java:24
com
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.abstractClass
final boolean abstractClass
Definition: ComponentProcessor.java:757
com.google.appinventor.components.scripts.ComponentProcessor.Parameter.Parameter
Parameter(String name, String type, boolean color)
Definition: ComponentProcessor.java:246
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.getCategory
String getCategory()
Definition: ComponentProcessor.java:917
com.google.appinventor.components.annotations.androidmanifest.CategoryElement
Definition: CategoryElement.java:34
com.google.appinventor.components.annotations.UsesApplicationMetadata
Definition: UsesApplicationMetadata.java:22
com.google.appinventor.components.annotations.androidmanifest.ActivityElement
Definition: ActivityElement.java:33
com.google.appinventor.components.annotations.androidmanifest.ProviderElement
Definition: ProviderElement.java:35
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.classNameAndActionsBR
final Set< String > classNameAndActionsBR
Definition: ComponentProcessor.java:728
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.broadcastReceivers
final Set< String > broadcastReceivers
Definition: ComponentProcessor.java:709
com.google.appinventor.components.scripts.ComponentProcessor
Definition: ComponentProcessor.java:124
com.google.appinventor.components.annotations.IsColor
Definition: IsColor.java:13
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.displayName
final String displayName
Definition: ComponentProcessor.java:765
com.google.appinventor.components.common.PropertyTypeConstants
Definition: PropertyTypeConstants.java:14
com.google.appinventor.components.annotations
com.google.appinventor.components.annotations.UsesActivities
Definition: UsesActivities.java:24
com.google.appinventor.components.annotations.androidmanifest.GrantUriPermissionElement
Definition: GrantUriPermissionElement.java:41
com.google.appinventor
com.google.appinventor.components.annotations.UsesActivityMetadata
Definition: UsesActivityMetadata.java:22
com.google.appinventor.components.scripts.ComponentProcessor.ComponentInfo.nativeLibraries
final Set< String > nativeLibraries
Definition: ComponentProcessor.java:684
com.google.appinventor.components.scripts.ComponentProcessor.ParameterizedFeature.ParameterizedFeature
ParameterizedFeature(String name, String description, String longDescription, String feature, boolean userVisible, boolean deprecated)
Definition: ComponentProcessor.java:421