Loading tools/aapt2/ResourceParser.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -81,6 +81,12 @@ struct ParsedResource { // Recursively adds resources to the ResourceTable. static bool addResourcesToTable(ResourceTable* table, IDiagnostics* diag, ParsedResource* res) { StringPiece16 trimmedComment = util::trimWhitespace(res->comment); if (trimmedComment.size() != res->comment.size()) { // Only if there was a change do we re-assign. res->comment = trimmedComment.toString(); } if (res->symbolState) { Symbol symbol; symbol.state = res->symbolState.value(); Loading tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml +5 −0 Original line number Diff line number Diff line Loading @@ -15,8 +15,13 @@ --> <resources> <!-- An attribute from StaticLibOne --> <attr name="StaticLibOne_attr" format="string" /> <string name="Foo">Foo</string> <string name="Foo" product="tablet">Bar</string> <declare-styleable name="Widget"> <attr name="StaticLibOne_attr" /> </declare-styleable> </resources> tools/aapt2/java/AnnotationProcessor.cpp +5 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ void AnnotationProcessor::appendCommentLine(const std::string& comment) { mComment << "/**"; } mComment << "\n" << " * " << std::move(comment); mComment << "\n * " << std::move(comment); } void AnnotationProcessor::appendComment(const StringPiece16& comment) { Loading @@ -60,6 +60,10 @@ void AnnotationProcessor::appendComment(const StringPiece& comment) { } } void AnnotationProcessor::appendNewLine() { mComment << "\n *"; } void AnnotationProcessor::writeToStream(std::ostream* out, const StringPiece& prefix) { if (mHasComments) { std::string result = mComment.str(); Loading tools/aapt2/java/AnnotationProcessor.h +2 −0 Original line number Diff line number Diff line Loading @@ -61,6 +61,8 @@ public: void appendComment(const StringPiece16& comment); void appendComment(const StringPiece& comment); void appendNewLine(); /** * Writes the comments and annotations to the stream, with the given prefix before each line. */ Loading tools/aapt2/java/JavaClassGenerator.cpp +161 −91 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include "java/AnnotationProcessor.h" #include "java/ClassDefinitionWriter.h" #include "java/JavaClassGenerator.h" #include "process/SymbolTable.h" #include "util/StringPiece.h" #include <algorithm> Loading @@ -33,8 +34,9 @@ namespace aapt { JavaClassGenerator::JavaClassGenerator(ResourceTable* table, JavaClassGeneratorOptions options) : mTable(table), mOptions(options) { JavaClassGenerator::JavaClassGenerator(IAaptContext* context, ResourceTable* table, const JavaClassGeneratorOptions& options) : mContext(context), mTable(table), mOptions(options) { } static void generateHeader(const StringPiece16& packageNameToGenerate, std::ostream* out) { Loading Loading @@ -103,6 +105,85 @@ static std::string transformNestedAttr(const ResourceNameRef& attrName, return output; } static void addAttributeFormatDoc(AnnotationProcessor* processor, Attribute* attr) { const uint32_t typeMask = attr->typeMask; if (typeMask & android::ResTable_map::TYPE_REFERENCE) { processor->appendComment( "<p>May be a reference to another resource, in the form\n" "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a theme\n" "attribute in the form\n" "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\"."); } if (typeMask & android::ResTable_map::TYPE_STRING) { processor->appendComment( "<p>May be a string value, using '\\\\;' to escape characters such as\n" "'\\\\n' or '\\\\uxxxx' for a unicode character;"); } if (typeMask & android::ResTable_map::TYPE_INTEGER) { processor->appendComment("<p>May be an integer value, such as \"<code>100</code>\"."); } if (typeMask & android::ResTable_map::TYPE_BOOLEAN) { processor->appendComment( "<p>May be a boolean value, such as \"<code>true</code>\" or\n" "\"<code>false</code>\"."); } if (typeMask & android::ResTable_map::TYPE_COLOR) { processor->appendComment( "<p>May be a color value, in the form of \"<code>#<i>rgb</i></code>\",\n" "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n" "\"<code>#<i>aarrggbb</i></code>\"."); } if (typeMask & android::ResTable_map::TYPE_FLOAT) { processor->appendComment( "<p>May be a floating point value, such as \"<code>1.2</code>\"."); } if (typeMask & android::ResTable_map::TYPE_DIMENSION) { processor->appendComment( "<p>May be a dimension value, which is a floating point number appended with a\n" "unit such as \"<code>14.5sp</code>\".\n" "Available units are: px (pixels), dp (density-independent pixels),\n" "sp (scaled pixels based on preferred font size), in (inches), and\n" "mm (millimeters)."); } if (typeMask & android::ResTable_map::TYPE_FRACTION) { processor->appendComment( "<p>May be a fractional value, which is a floating point number appended with\n" "either % or %p, such as \"<code>14.5%</code>\".\n" "The % suffix always means a percentage of the base size;\n" "the optional %p suffix provides a size relative to some parent container."); } if (typeMask & (android::ResTable_map::TYPE_FLAGS | android::ResTable_map::TYPE_ENUM)) { if (typeMask & android::ResTable_map::TYPE_FLAGS) { processor->appendComment( "<p>Must be one or more (separated by '|') of the following " "constant values.</p>"); } else { processor->appendComment("<p>Must be one of the following constant values.</p>"); } processor->appendComment("<table>\n<colgroup align=\"left\" />\n" "<colgroup align=\"left\" />\n" "<colgroup align=\"left\" />\n" "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n"); for (const Attribute::Symbol& symbol : attr->symbols) { std::stringstream line; line << "<tr><td>" << symbol.symbol.name.value().entry << "</td>" << "<td>" << std::hex << symbol.value << std::dec << "</td>" << "<td>" << util::trimWhitespace(symbol.symbol.getComment()) << "</td></tr>"; processor->appendComment(line.str()); } processor->appendComment("</table>"); } } bool JavaClassGenerator::skipSymbol(SymbolState state) { switch (mOptions.types) { case JavaClassGeneratorOptions::SymbolTypes::kAll: Loading @@ -117,6 +198,7 @@ bool JavaClassGenerator::skipSymbol(SymbolState state) { struct StyleableAttr { const Reference* attrRef; std::shared_ptr<Attribute> attribute; std::string fieldName; }; Loading Loading @@ -148,8 +230,29 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC assert((!mOptions.useFinal || attr.id) && "no ID set for Styleable entry"); assert(attr.name && "no name set for Styleable entry"); sortedAttributes.emplace_back(StyleableAttr{ &attr, transformNestedAttr(attr.name.value(), className, packageNameToGenerate) }); StyleableAttr styleableAttr = {}; styleableAttr.attrRef = &attr; styleableAttr.fieldName = transformNestedAttr(attr.name.value(), className, packageNameToGenerate); Reference mangledReference; mangledReference.id = attr.id; mangledReference.name = attr.name; if (mangledReference.name.value().package.empty()) { mangledReference.name.value().package = mContext->getCompilationPackage(); } if (Maybe<ResourceName> mangledName = mContext->getNameMangler()->mangleName(mangledReference.name.value())) { mangledReference.name = mangledName; } const SymbolTable::Symbol* symbol = mContext->getExternalSymbols()->findByReference( mangledReference); if (symbol) { styleableAttr.attribute = symbol->attribute; } sortedAttributes.push_back(std::move(styleableAttr)); } std::sort(sortedAttributes.begin(), sortedAttributes.end(), lessStyleableAttr); Loading @@ -159,16 +262,34 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC // Build the comment string for the Styleable. It includes details about the // child attributes. std::stringstream styleableComment; if (!styleable->getComment().empty()) { styleableComment << styleable->getComment() << "\n"; } else { styleableComment << "Attributes that can be used with a " << className << ".\n"; styleableComment << "<table>\n" } styleableComment << "<p>Includes the following attributes:</p>\n" "<table>\n" "<colgroup align=\"left\" />\n" "<colgroup align=\"left\" />\n" "<colgroup align=\"left\">\n" "<tr><th>Attribute</th><th>Description</th></tr>\n"; for (const auto& entry : sortedAttributes) { const ResourceName& attrName = entry.attrRef->name.value(); styleableComment << "<tr><td><code>{@link #" << entry.fieldName << " " << attrName.package << ":" << attrName.entry << "}</code></td><td></td></tr>\n"; styleableComment << "<tr><td>"; styleableComment << "<code>{@link #" << entry.fieldName << " " << (!attrName.package.empty() ? attrName.package : mContext->getCompilationPackage()) << ":" << attrName.entry << "}</code>"; styleableComment << "</td>"; styleableComment << "<td>"; if (entry.attribute) { styleableComment << entry.attribute->getComment(); } styleableComment << "</td></tr>\n"; } styleableComment << "</table>\n"; for (const auto& entry : sortedAttributes) { Loading @@ -189,96 +310,45 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC // Now we emit the indices into the array. for (size_t i = 0; i < attrCount; i++) { const ResourceName& attrName = sortedAttributes[i].attrRef->name.value(); AnnotationProcessor attrProcessor; std::stringstream doclavaComments; doclavaComments << "@attr name "; if (!attrName.package.empty()) { doclavaComments << attrName.package << ":"; } doclavaComments << attrName.entry; attrProcessor.appendComment(doclavaComments.str()); outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i); } } static void addAttributeFormatDoc(AnnotationProcessor* processor, Attribute* attr) { const uint32_t typeMask = attr->typeMask; if (typeMask & android::ResTable_map::TYPE_REFERENCE) { processor->appendComment( "<p>May be a reference to another resource, in the form\n" "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a theme\n" "attribute in the form\n" "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\"."); } const StyleableAttr& styleableAttr = sortedAttributes[i]; const ResourceName& attrName = styleableAttr.attrRef->name.value(); if (typeMask & android::ResTable_map::TYPE_STRING) { processor->appendComment( "<p>May be a string value, using '\\\\;' to escape characters such as\n" "'\\\\n' or '\\\\uxxxx' for a unicode character;"); } if (typeMask & android::ResTable_map::TYPE_INTEGER) { processor->appendComment("<p>May be an integer value, such as \"<code>100</code>\"."); StringPiece16 packageName = attrName.package; if (packageName.empty()) { packageName = mContext->getCompilationPackage(); } if (typeMask & android::ResTable_map::TYPE_BOOLEAN) { processor->appendComment( "<p>May be a boolean value, such as \"<code>true</code>\" or\n" "\"<code>false</code>\"."); } if (typeMask & android::ResTable_map::TYPE_COLOR) { processor->appendComment( "<p>May be a color value, in the form of \"<code>#<i>rgb</i></code>\",\n" "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n" "\"<code>#<i>aarrggbb</i></code>\"."); } AnnotationProcessor attrProcessor; if (typeMask & android::ResTable_map::TYPE_FLOAT) { processor->appendComment( "<p>May be a floating point value, such as \"<code>1.2</code>\"."); StringPiece16 comment = styleableAttr.attrRef->getComment(); if (styleableAttr.attribute && comment.empty()) { comment = styleableAttr.attribute->getComment(); } if (typeMask & android::ResTable_map::TYPE_DIMENSION) { processor->appendComment( "<p>May be a dimension value, which is a floating point number appended with a\n" "unit such as \"<code>14.5sp</code>\".\n" "Available units are: px (pixels), dp (density-independent pixels),\n" "sp (scaled pixels based on preferred font size), in (inches), and\n" "mm (millimeters)."); if (!comment.empty()) { attrProcessor.appendComment("<p>\n@attr description"); attrProcessor.appendComment(comment); } else { std::stringstream defaultComment; defaultComment << "<p>This symbol is the offset where the " << "{@link " << packageName << ".R.attr#" << transform(attrName.entry) << "}\n" << "attribute's value can be found in the " << "{@link #" << className << "} array."; attrProcessor.appendComment(defaultComment.str()); } if (typeMask & android::ResTable_map::TYPE_FRACTION) { processor->appendComment( "<p>May be a fractional value, which is a floating point number appended with\n" "either % or %p, such as \"<code>14.5%</code>\".\n" "The % suffix always means a percentage of the base size;\n" "the optional %p suffix provides a size relative to some parent container."); } attrProcessor.appendNewLine(); if (typeMask & (android::ResTable_map::TYPE_FLAGS | android::ResTable_map::TYPE_ENUM)) { if (typeMask & android::ResTable_map::TYPE_FLAGS) { processor->appendComment( "<p>Must be one or more (separated by '|') of the following " "constant values.</p>"); } else { processor->appendComment("<p>Must be one of the following constant values.</p>"); if (styleableAttr.attribute) { addAttributeFormatDoc(&attrProcessor, styleableAttr.attribute.get()); attrProcessor.appendNewLine(); } processor->appendComment("<table>\n<colgroup align=\"left\" />\n" "<colgroup align=\"left\" />\n" "<colgroup align=\"left\" />\n" "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n"); for (const Attribute::Symbol& symbol : attr->symbols) { std::stringstream line; line << "<tr><td>" << symbol.symbol.name.value().entry << "</td>" << "<td>" << std::hex << symbol.value << std::dec << "</td>" << "<td>" << util::trimWhitespace(symbol.symbol.getComment()) << "</td></tr>"; processor->appendComment(line.str()); } processor->appendComment("</table>"); std::stringstream doclavaName; doclavaName << "@attr name " << packageName << ":" << attrName.entry;; attrProcessor.appendComment(doclavaName.str()); outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i); } } Loading Loading
tools/aapt2/ResourceParser.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -81,6 +81,12 @@ struct ParsedResource { // Recursively adds resources to the ResourceTable. static bool addResourcesToTable(ResourceTable* table, IDiagnostics* diag, ParsedResource* res) { StringPiece16 trimmedComment = util::trimWhitespace(res->comment); if (trimmedComment.size() != res->comment.size()) { // Only if there was a change do we re-assign. res->comment = trimmedComment.toString(); } if (res->symbolState) { Symbol symbol; symbol.state = res->symbolState.value(); Loading
tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml +5 −0 Original line number Diff line number Diff line Loading @@ -15,8 +15,13 @@ --> <resources> <!-- An attribute from StaticLibOne --> <attr name="StaticLibOne_attr" format="string" /> <string name="Foo">Foo</string> <string name="Foo" product="tablet">Bar</string> <declare-styleable name="Widget"> <attr name="StaticLibOne_attr" /> </declare-styleable> </resources>
tools/aapt2/java/AnnotationProcessor.cpp +5 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ void AnnotationProcessor::appendCommentLine(const std::string& comment) { mComment << "/**"; } mComment << "\n" << " * " << std::move(comment); mComment << "\n * " << std::move(comment); } void AnnotationProcessor::appendComment(const StringPiece16& comment) { Loading @@ -60,6 +60,10 @@ void AnnotationProcessor::appendComment(const StringPiece& comment) { } } void AnnotationProcessor::appendNewLine() { mComment << "\n *"; } void AnnotationProcessor::writeToStream(std::ostream* out, const StringPiece& prefix) { if (mHasComments) { std::string result = mComment.str(); Loading
tools/aapt2/java/AnnotationProcessor.h +2 −0 Original line number Diff line number Diff line Loading @@ -61,6 +61,8 @@ public: void appendComment(const StringPiece16& comment); void appendComment(const StringPiece& comment); void appendNewLine(); /** * Writes the comments and annotations to the stream, with the given prefix before each line. */ Loading
tools/aapt2/java/JavaClassGenerator.cpp +161 −91 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include "java/AnnotationProcessor.h" #include "java/ClassDefinitionWriter.h" #include "java/JavaClassGenerator.h" #include "process/SymbolTable.h" #include "util/StringPiece.h" #include <algorithm> Loading @@ -33,8 +34,9 @@ namespace aapt { JavaClassGenerator::JavaClassGenerator(ResourceTable* table, JavaClassGeneratorOptions options) : mTable(table), mOptions(options) { JavaClassGenerator::JavaClassGenerator(IAaptContext* context, ResourceTable* table, const JavaClassGeneratorOptions& options) : mContext(context), mTable(table), mOptions(options) { } static void generateHeader(const StringPiece16& packageNameToGenerate, std::ostream* out) { Loading Loading @@ -103,6 +105,85 @@ static std::string transformNestedAttr(const ResourceNameRef& attrName, return output; } static void addAttributeFormatDoc(AnnotationProcessor* processor, Attribute* attr) { const uint32_t typeMask = attr->typeMask; if (typeMask & android::ResTable_map::TYPE_REFERENCE) { processor->appendComment( "<p>May be a reference to another resource, in the form\n" "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a theme\n" "attribute in the form\n" "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\"."); } if (typeMask & android::ResTable_map::TYPE_STRING) { processor->appendComment( "<p>May be a string value, using '\\\\;' to escape characters such as\n" "'\\\\n' or '\\\\uxxxx' for a unicode character;"); } if (typeMask & android::ResTable_map::TYPE_INTEGER) { processor->appendComment("<p>May be an integer value, such as \"<code>100</code>\"."); } if (typeMask & android::ResTable_map::TYPE_BOOLEAN) { processor->appendComment( "<p>May be a boolean value, such as \"<code>true</code>\" or\n" "\"<code>false</code>\"."); } if (typeMask & android::ResTable_map::TYPE_COLOR) { processor->appendComment( "<p>May be a color value, in the form of \"<code>#<i>rgb</i></code>\",\n" "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n" "\"<code>#<i>aarrggbb</i></code>\"."); } if (typeMask & android::ResTable_map::TYPE_FLOAT) { processor->appendComment( "<p>May be a floating point value, such as \"<code>1.2</code>\"."); } if (typeMask & android::ResTable_map::TYPE_DIMENSION) { processor->appendComment( "<p>May be a dimension value, which is a floating point number appended with a\n" "unit such as \"<code>14.5sp</code>\".\n" "Available units are: px (pixels), dp (density-independent pixels),\n" "sp (scaled pixels based on preferred font size), in (inches), and\n" "mm (millimeters)."); } if (typeMask & android::ResTable_map::TYPE_FRACTION) { processor->appendComment( "<p>May be a fractional value, which is a floating point number appended with\n" "either % or %p, such as \"<code>14.5%</code>\".\n" "The % suffix always means a percentage of the base size;\n" "the optional %p suffix provides a size relative to some parent container."); } if (typeMask & (android::ResTable_map::TYPE_FLAGS | android::ResTable_map::TYPE_ENUM)) { if (typeMask & android::ResTable_map::TYPE_FLAGS) { processor->appendComment( "<p>Must be one or more (separated by '|') of the following " "constant values.</p>"); } else { processor->appendComment("<p>Must be one of the following constant values.</p>"); } processor->appendComment("<table>\n<colgroup align=\"left\" />\n" "<colgroup align=\"left\" />\n" "<colgroup align=\"left\" />\n" "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n"); for (const Attribute::Symbol& symbol : attr->symbols) { std::stringstream line; line << "<tr><td>" << symbol.symbol.name.value().entry << "</td>" << "<td>" << std::hex << symbol.value << std::dec << "</td>" << "<td>" << util::trimWhitespace(symbol.symbol.getComment()) << "</td></tr>"; processor->appendComment(line.str()); } processor->appendComment("</table>"); } } bool JavaClassGenerator::skipSymbol(SymbolState state) { switch (mOptions.types) { case JavaClassGeneratorOptions::SymbolTypes::kAll: Loading @@ -117,6 +198,7 @@ bool JavaClassGenerator::skipSymbol(SymbolState state) { struct StyleableAttr { const Reference* attrRef; std::shared_ptr<Attribute> attribute; std::string fieldName; }; Loading Loading @@ -148,8 +230,29 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC assert((!mOptions.useFinal || attr.id) && "no ID set for Styleable entry"); assert(attr.name && "no name set for Styleable entry"); sortedAttributes.emplace_back(StyleableAttr{ &attr, transformNestedAttr(attr.name.value(), className, packageNameToGenerate) }); StyleableAttr styleableAttr = {}; styleableAttr.attrRef = &attr; styleableAttr.fieldName = transformNestedAttr(attr.name.value(), className, packageNameToGenerate); Reference mangledReference; mangledReference.id = attr.id; mangledReference.name = attr.name; if (mangledReference.name.value().package.empty()) { mangledReference.name.value().package = mContext->getCompilationPackage(); } if (Maybe<ResourceName> mangledName = mContext->getNameMangler()->mangleName(mangledReference.name.value())) { mangledReference.name = mangledName; } const SymbolTable::Symbol* symbol = mContext->getExternalSymbols()->findByReference( mangledReference); if (symbol) { styleableAttr.attribute = symbol->attribute; } sortedAttributes.push_back(std::move(styleableAttr)); } std::sort(sortedAttributes.begin(), sortedAttributes.end(), lessStyleableAttr); Loading @@ -159,16 +262,34 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC // Build the comment string for the Styleable. It includes details about the // child attributes. std::stringstream styleableComment; if (!styleable->getComment().empty()) { styleableComment << styleable->getComment() << "\n"; } else { styleableComment << "Attributes that can be used with a " << className << ".\n"; styleableComment << "<table>\n" } styleableComment << "<p>Includes the following attributes:</p>\n" "<table>\n" "<colgroup align=\"left\" />\n" "<colgroup align=\"left\" />\n" "<colgroup align=\"left\">\n" "<tr><th>Attribute</th><th>Description</th></tr>\n"; for (const auto& entry : sortedAttributes) { const ResourceName& attrName = entry.attrRef->name.value(); styleableComment << "<tr><td><code>{@link #" << entry.fieldName << " " << attrName.package << ":" << attrName.entry << "}</code></td><td></td></tr>\n"; styleableComment << "<tr><td>"; styleableComment << "<code>{@link #" << entry.fieldName << " " << (!attrName.package.empty() ? attrName.package : mContext->getCompilationPackage()) << ":" << attrName.entry << "}</code>"; styleableComment << "</td>"; styleableComment << "<td>"; if (entry.attribute) { styleableComment << entry.attribute->getComment(); } styleableComment << "</td></tr>\n"; } styleableComment << "</table>\n"; for (const auto& entry : sortedAttributes) { Loading @@ -189,96 +310,45 @@ void JavaClassGenerator::writeStyleableEntryForClass(ClassDefinitionWriter* outC // Now we emit the indices into the array. for (size_t i = 0; i < attrCount; i++) { const ResourceName& attrName = sortedAttributes[i].attrRef->name.value(); AnnotationProcessor attrProcessor; std::stringstream doclavaComments; doclavaComments << "@attr name "; if (!attrName.package.empty()) { doclavaComments << attrName.package << ":"; } doclavaComments << attrName.entry; attrProcessor.appendComment(doclavaComments.str()); outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i); } } static void addAttributeFormatDoc(AnnotationProcessor* processor, Attribute* attr) { const uint32_t typeMask = attr->typeMask; if (typeMask & android::ResTable_map::TYPE_REFERENCE) { processor->appendComment( "<p>May be a reference to another resource, in the form\n" "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a theme\n" "attribute in the form\n" "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\"."); } const StyleableAttr& styleableAttr = sortedAttributes[i]; const ResourceName& attrName = styleableAttr.attrRef->name.value(); if (typeMask & android::ResTable_map::TYPE_STRING) { processor->appendComment( "<p>May be a string value, using '\\\\;' to escape characters such as\n" "'\\\\n' or '\\\\uxxxx' for a unicode character;"); } if (typeMask & android::ResTable_map::TYPE_INTEGER) { processor->appendComment("<p>May be an integer value, such as \"<code>100</code>\"."); StringPiece16 packageName = attrName.package; if (packageName.empty()) { packageName = mContext->getCompilationPackage(); } if (typeMask & android::ResTable_map::TYPE_BOOLEAN) { processor->appendComment( "<p>May be a boolean value, such as \"<code>true</code>\" or\n" "\"<code>false</code>\"."); } if (typeMask & android::ResTable_map::TYPE_COLOR) { processor->appendComment( "<p>May be a color value, in the form of \"<code>#<i>rgb</i></code>\",\n" "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code\", or \n" "\"<code>#<i>aarrggbb</i></code>\"."); } AnnotationProcessor attrProcessor; if (typeMask & android::ResTable_map::TYPE_FLOAT) { processor->appendComment( "<p>May be a floating point value, such as \"<code>1.2</code>\"."); StringPiece16 comment = styleableAttr.attrRef->getComment(); if (styleableAttr.attribute && comment.empty()) { comment = styleableAttr.attribute->getComment(); } if (typeMask & android::ResTable_map::TYPE_DIMENSION) { processor->appendComment( "<p>May be a dimension value, which is a floating point number appended with a\n" "unit such as \"<code>14.5sp</code>\".\n" "Available units are: px (pixels), dp (density-independent pixels),\n" "sp (scaled pixels based on preferred font size), in (inches), and\n" "mm (millimeters)."); if (!comment.empty()) { attrProcessor.appendComment("<p>\n@attr description"); attrProcessor.appendComment(comment); } else { std::stringstream defaultComment; defaultComment << "<p>This symbol is the offset where the " << "{@link " << packageName << ".R.attr#" << transform(attrName.entry) << "}\n" << "attribute's value can be found in the " << "{@link #" << className << "} array."; attrProcessor.appendComment(defaultComment.str()); } if (typeMask & android::ResTable_map::TYPE_FRACTION) { processor->appendComment( "<p>May be a fractional value, which is a floating point number appended with\n" "either % or %p, such as \"<code>14.5%</code>\".\n" "The % suffix always means a percentage of the base size;\n" "the optional %p suffix provides a size relative to some parent container."); } attrProcessor.appendNewLine(); if (typeMask & (android::ResTable_map::TYPE_FLAGS | android::ResTable_map::TYPE_ENUM)) { if (typeMask & android::ResTable_map::TYPE_FLAGS) { processor->appendComment( "<p>Must be one or more (separated by '|') of the following " "constant values.</p>"); } else { processor->appendComment("<p>Must be one of the following constant values.</p>"); if (styleableAttr.attribute) { addAttributeFormatDoc(&attrProcessor, styleableAttr.attribute.get()); attrProcessor.appendNewLine(); } processor->appendComment("<table>\n<colgroup align=\"left\" />\n" "<colgroup align=\"left\" />\n" "<colgroup align=\"left\" />\n" "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n"); for (const Attribute::Symbol& symbol : attr->symbols) { std::stringstream line; line << "<tr><td>" << symbol.symbol.name.value().entry << "</td>" << "<td>" << std::hex << symbol.value << std::dec << "</td>" << "<td>" << util::trimWhitespace(symbol.symbol.getComment()) << "</td></tr>"; processor->appendComment(line.str()); } processor->appendComment("</table>"); std::stringstream doclavaName; doclavaName << "@attr name " << packageName << ":" << attrName.entry;; attrProcessor.appendComment(doclavaName.str()); outClassDef->addIntMember(sortedAttributes[i].fieldName, &attrProcessor, i); } } Loading