16f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/* 26f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 36f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 46f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 56f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * you may not use this file except in compliance with the License. 66f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * You may obtain a copy of the License at 76f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 86f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 96f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Unless required by applicable law or agreed to in writing, software 116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * See the License for the specific language governing permissions and 146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * limitations under the License. 156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 17ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "java/JavaClassGenerator.h" 18ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 19ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <algorithm> 20ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <ostream> 21ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <set> 22ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <sstream> 23ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <tuple> 24ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 25418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski#include "android-base/errors.h" 26ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "android-base/logging.h" 27ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski#include "android-base/stringprintf.h" 28d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski#include "androidfw/StringPiece.h" 29ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 30769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include "NameMangler.h" 316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "Resource.h" 326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceTable.h" 336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceValues.h" 341e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski#include "SdkConstants.h" 353b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski#include "ValueVisitor.h" 36ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski#include "java/AnnotationProcessor.h" 376cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski#include "java/ClassDefinition.h" 387656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski#include "process/SymbolTable.h" 39d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski 40a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinskiusing ::aapt::io::OutputStream; 41a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinskiusing ::aapt::text::Printer; 42a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinskiusing ::android::StringPiece; 43a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinskiusing ::android::base::StringPrintf; 446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt { 466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 47d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinskistatic const std::set<StringPiece> sJavaIdentifiers = { 48ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "abstract", "assert", "boolean", "break", "byte", 49ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "case", "catch", "char", "class", "const", 50ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "continue", "default", "do", "double", "else", 51ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "enum", "extends", "final", "finally", "float", 52ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "for", "goto", "if", "implements", "import", 53ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "instanceof", "int", "interface", "long", "native", 54ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "new", "package", "private", "protected", "public", 55ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "return", "short", "static", "strictfp", "super", 56ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "switch", "synchronized", "this", "throw", "throws", 57ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "transient", "try", "void", "volatile", "while", 58ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "true", "false", "null"}; 59ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 60ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool IsValidSymbol(const StringPiece& symbol) { 61ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return sJavaIdentifiers.find(symbol) == sJavaIdentifiers.end(); 626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 64ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski// Java symbols can not contain . or -, but those are valid in a resource name. 65ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski// Replace those with '_'. 66dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koskistd::string JavaClassGenerator::TransformToFieldName(const StringPiece& symbol) { 67d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski std::string output = symbol.to_string(); 68ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (char& c : output) { 69ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (c == '.' || c == '-') { 70ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski c = '_'; 716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 72ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 73ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return output; 746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 76ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski// Transforms an attribute in a styleable to the Java field name: 77ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski// 78ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski// <declare-styleable name="Foo"> 79ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski// <attr name="android:bar" /> 80ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski// <attr name="bar" /> 81ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski// </declare-styleable> 82ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski// 83ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski// Foo_android_bar 84ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski// Foo_bar 85ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskistatic std::string TransformNestedAttr(const ResourceNameRef& attr_name, 86ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const std::string& styleable_class_name, 87ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const StringPiece& package_name_to_generate) { 88ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string output = styleable_class_name; 89ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 90ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // We may reference IDs from other packages, so prefix the entry name with 91ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // the package. 92ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!attr_name.package.empty() && 93ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski package_name_to_generate != attr_name.package) { 94dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski output += "_" + JavaClassGenerator::TransformToFieldName(attr_name.package); 95ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 96dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski output += "_" + JavaClassGenerator::TransformToFieldName(attr_name.entry); 97ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return output; 9874605cd40256ca75b44cc3182eeeb886c92d737cAdam Lesinski} 9974605cd40256ca75b44cc3182eeeb886c92d737cAdam Lesinski 100ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskistatic void AddAttributeFormatDoc(AnnotationProcessor* processor, Attribute* attr) { 101ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const uint32_t type_mask = attr->type_mask; 102ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_mask & android::ResTable_map::TYPE_REFERENCE) { 103ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment( 104ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<p>May be a reference to another resource, in the form\n" 105ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "\"<code>@[+][<i>package</i>:]<i>type</i>/<i>name</i></code>\" or a " 106ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "theme\n" 107ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "attribute in the form\n" 108ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "\"<code>?[<i>package</i>:]<i>type</i>/<i>name</i></code>\"."); 109ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 110ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 111ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_mask & android::ResTable_map::TYPE_STRING) { 112ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment( 113ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<p>May be a string value, using '\\\\;' to escape characters such as\n" 114ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "'\\\\n' or '\\\\uxxxx' for a unicode character;"); 115ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 116ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 117ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_mask & android::ResTable_map::TYPE_INTEGER) { 118ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment( 119ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<p>May be an integer value, such as \"<code>100</code>\"."); 120ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 121ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 122ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_mask & android::ResTable_map::TYPE_BOOLEAN) { 123ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment( 124ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<p>May be a boolean value, such as \"<code>true</code>\" or\n" 125ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "\"<code>false</code>\"."); 126ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 127ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 128ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_mask & android::ResTable_map::TYPE_COLOR) { 129ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment( 130ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<p>May be a color value, in the form of " 131ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "\"<code>#<i>rgb</i></code>\",\n" 132ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski "\"<code>#<i>argb</i></code>\", \"<code>#<i>rrggbb</i></code>\", or \n" 133ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "\"<code>#<i>aarrggbb</i></code>\"."); 134ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 135ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 136ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_mask & android::ResTable_map::TYPE_FLOAT) { 137ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment( 138ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<p>May be a floating point value, such as \"<code>1.2</code>\"."); 139ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 140ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 141ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_mask & android::ResTable_map::TYPE_DIMENSION) { 142ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment( 143ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<p>May be a dimension value, which is a floating point number " 144ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "appended with a\n" 145ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "unit such as \"<code>14.5sp</code>\".\n" 146ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "Available units are: px (pixels), dp (density-independent pixels),\n" 147ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "sp (scaled pixels based on preferred font size), in (inches), and\n" 148ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "mm (millimeters)."); 149ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 150ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 151ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_mask & android::ResTable_map::TYPE_FRACTION) { 152ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment( 153ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<p>May be a fractional value, which is a floating point number " 154ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "appended with\n" 155ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "either % or %p, such as \"<code>14.5%</code>\".\n" 156ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "The % suffix always means a percentage of the base size;\n" 157ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "the optional %p suffix provides a size relative to some parent " 158ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "container."); 159ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 160ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 161ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_mask & 162ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski (android::ResTable_map::TYPE_FLAGS | android::ResTable_map::TYPE_ENUM)) { 163ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_mask & android::ResTable_map::TYPE_FLAGS) { 164ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment( 165ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<p>Must be one or more (separated by '|') of the following " 166ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "constant values.</p>"); 167ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else { 168ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment( 169ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<p>Must be one of the following constant values.</p>"); 1707656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski } 1717656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 172ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment( 173ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<table>\n<colgroup align=\"left\" />\n" 174ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<colgroup align=\"left\" />\n" 175ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<colgroup align=\"left\" />\n" 176ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\n"); 177ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (const Attribute::Symbol& symbol : attr->symbols) { 178ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream line; 179ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski line << "<tr><td>" << symbol.symbol.name.value().entry << "</td>" 180ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski << "<td>" << std::hex << symbol.value << std::dec << "</td>" 181ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski << "<td>" << util::TrimWhitespace(symbol.symbol.GetComment()) 182ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski << "</td></tr>"; 183ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment(line.str()); 1847656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski } 185ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment("</table>"); 186ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 187ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski} 1887656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 189ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiJavaClassGenerator::JavaClassGenerator(IAaptContext* context, 190ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTable* table, 191ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const JavaClassGeneratorOptions& options) 192ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski : context_(context), table_(table), options_(options) {} 1937656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 19471be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinskibool JavaClassGenerator::SkipSymbol(Visibility::Level level) { 195ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski switch (options_.types) { 196ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski case JavaClassGeneratorOptions::SymbolTypes::kAll: 197ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return false; 198ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski case JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate: 19971be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski return level == Visibility::Level::kUndefined; 200ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski case JavaClassGeneratorOptions::SymbolTypes::kPublic: 20171be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski return level != Visibility::Level::kPublic; 202ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 203ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return true; 204ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski} 2057656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 206ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski// Whether or not to skip writing this symbol. 207ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskibool JavaClassGenerator::SkipSymbol(const Maybe<SymbolTable::Symbol>& symbol) { 208ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski return !symbol || (options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic && 209ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski !symbol.value().is_public); 210ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski} 211ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski 212ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistruct StyleableAttr { 213ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const Reference* attr_ref = nullptr; 214ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string field_name; 215ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski Maybe<SymbolTable::Symbol> symbol; 216ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski}; 2177656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 218ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskistatic bool operator<(const StyleableAttr& lhs, const StyleableAttr& rhs) { 219ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const ResourceId lhs_id = lhs.attr_ref->id.value_or_default(ResourceId(0)); 220ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const ResourceId rhs_id = rhs.attr_ref->id.value_or_default(ResourceId(0)); 221ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (lhs_id < rhs_id) { 222ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return true; 223ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else if (lhs_id > rhs_id) { 224ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return false; 225ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else { 226ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return lhs.attr_ref->name.value() < rhs.attr_ref->name.value(); 227ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 228ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski} 2297656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 230ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskivoid JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const ResourceId& id, 231ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const Styleable& styleable, 232ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const StringPiece& package_name_to_generate, 233ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski ClassDefinition* out_class_def, 234418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski MethodDefinition* out_rewrite_method, 235a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski Printer* r_txt_printer) { 236ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const std::string array_field_name = TransformToFieldName(name.entry); 237ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski std::unique_ptr<ResourceArrayMember> array_def = 238ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski util::make_unique<ResourceArrayMember>(array_field_name); 239ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 240ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // The array must be sorted by resource ID. 241ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::vector<StyleableAttr> sorted_attributes; 242ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski sorted_attributes.reserve(styleable.entries.size()); 243ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski for (const auto& attr : styleable.entries) { 244ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // If we are not encoding final attributes, the styleable entry may have no 245ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // ID if we are building a static library. 246ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CHECK(!options_.use_final || attr.id) << "no ID set for Styleable entry"; 247ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CHECK(bool(attr.name)) << "no name set for Styleable entry"; 248ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 249ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // We will need the unmangled, transformed name in the comments and the field, 250ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // so create it once and cache it in this StyleableAttr data structure. 251ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski StyleableAttr styleable_attr; 252ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski styleable_attr.attr_ref = &attr; 2537656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 254ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // The field name for this attribute is prefixed by the name of this styleable and 255ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // the package it comes from. 256ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski styleable_attr.field_name = 257ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski TransformNestedAttr(attr.name.value(), array_field_name, package_name_to_generate); 2587656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 259ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // Look up the symbol so that we can write out in the comments what are possible legal values 260ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // for this attribute. 261ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const SymbolTable::Symbol* symbol = context_->GetExternalSymbols()->FindByReference(attr); 262ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (symbol && symbol->attribute) { 263ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // Copy the symbol data structure because the returned instance can be destroyed. 264ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski styleable_attr.symbol = *symbol; 2657656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski } 266ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski sorted_attributes.push_back(std::move(styleable_attr)); 267ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 268ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 269ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // Sort the attributes by ID. 270ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski std::sort(sorted_attributes.begin(), sorted_attributes.end()); 271ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 272ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // Build the JavaDoc comment for the Styleable array. This has references to child attributes 273ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // and what possible values can be used for them. 274ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const size_t attr_count = sorted_attributes.size(); 27523a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (out_class_def != nullptr && attr_count > 0) { 276ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream styleable_comment; 277ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (!styleable.GetComment().empty()) { 278ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski styleable_comment << styleable.GetComment() << "\n"; 279ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else { 280ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // Apply a default intro comment if the styleable has no comments of its own. 281ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski styleable_comment << "Attributes that can be used with a " << array_field_name << ".\n"; 2829e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski } 28374605cd40256ca75b44cc3182eeeb886c92d737cAdam Lesinski 284ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski styleable_comment << "<p>Includes the following attributes:</p>\n" 285ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<table>\n" 286ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<colgroup align=\"left\" />\n" 287ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<colgroup align=\"left\" />\n" 288ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski "<tr><th>Attribute</th><th>Description</th></tr>\n"; 289ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 290ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // Build the table of attributes with their links and names. 291ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (const StyleableAttr& entry : sorted_attributes) { 292ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (SkipSymbol(entry.symbol)) { 293ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski continue; 294ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 295ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 296ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski StringPiece attr_comment_line = entry.symbol.value().attribute->GetComment(); 297ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (attr_comment_line.contains("@removed")) { 298ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // Removed attributes are public but hidden from the documentation, so 299ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // don't emit them as part of the class documentation. 300ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski continue; 301ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 302ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 303ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const ResourceName& attr_name = entry.attr_ref->name.value(); 304e967d3f6ac2e1e1f612f99b9c76abcb9e13bb7a2Adam Lesinski styleable_comment << "<tr><td><code>{@link #" << entry.field_name << " " 305e967d3f6ac2e1e1f612f99b9c76abcb9e13bb7a2Adam Lesinski << (!attr_name.package.empty() ? attr_name.package 306e967d3f6ac2e1e1f612f99b9c76abcb9e13bb7a2Adam Lesinski : context_->GetCompilationPackage()) 307e967d3f6ac2e1e1f612f99b9c76abcb9e13bb7a2Adam Lesinski << ":" << attr_name.entry << "}</code></td>"; 308ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 309ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // Only use the comment up until the first '.'. This is to stay compatible with 310ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // the way old AAPT did it (presumably to keep it short and to avoid including 311ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // annotations like @hide which would affect this Styleable). 312e967d3f6ac2e1e1f612f99b9c76abcb9e13bb7a2Adam Lesinski styleable_comment << "<td>" << AnnotationProcessor::ExtractFirstSentence(attr_comment_line) 313e967d3f6ac2e1e1f612f99b9c76abcb9e13bb7a2Adam Lesinski << "</td></tr>\n"; 314ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 315ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski styleable_comment << "</table>\n"; 316ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 317ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // Generate the @see lines for each attribute. 318ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (const StyleableAttr& entry : sorted_attributes) { 319ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (SkipSymbol(entry.symbol)) { 320ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski continue; 321ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 322ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski styleable_comment << "@see #" << entry.field_name << "\n"; 32374605cd40256ca75b44cc3182eeeb886c92d737cAdam Lesinski } 32474605cd40256ca75b44cc3182eeeb886c92d737cAdam Lesinski 325ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski array_def->GetCommentBuilder()->AppendComment(styleable_comment.str()); 326ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 3277656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 328a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski if (r_txt_printer != nullptr) { 329a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski r_txt_printer->Print("int[] styleable ").Print(array_field_name).Print(" {"); 330418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski } 331418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski 332ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // Add the ResourceIds to the array member. 333418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski for (size_t i = 0; i < attr_count; i++) { 334418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski const ResourceId id = sorted_attributes[i].attr_ref->id.value_or_default(ResourceId(0)); 335ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski array_def->AddElement(id); 336418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski 337a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski if (r_txt_printer != nullptr) { 338418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski if (i != 0) { 339a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski r_txt_printer->Print(","); 340418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski } 341a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski r_txt_printer->Print(" ").Print(id.to_string()); 342418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski } 343418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski } 344418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski 345a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski if (r_txt_printer != nullptr) { 346a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski r_txt_printer->Println(" }"); 347ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 3487656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 349ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // Add the Styleable array to the Styleable class. 350ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski out_class_def->AddMember(std::move(array_def)); 3516cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski 352ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // Now we emit the indices into the array. 353ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (size_t i = 0; i < attr_count; i++) { 354ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const StyleableAttr& styleable_attr = sorted_attributes[i]; 355ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (SkipSymbol(styleable_attr.symbol)) { 356ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski continue; 3576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 3586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 35923a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (out_class_def != nullptr) { 36023a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska StringPiece comment = styleable_attr.attr_ref->GetComment(); 36123a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (styleable_attr.symbol.value().attribute && comment.empty()) { 36223a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska comment = styleable_attr.symbol.value().attribute->GetComment(); 36323a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska } 3646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 36523a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (comment.contains("@removed")) { 36623a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska // Removed attributes are public but hidden from the documentation, so 36723a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska // don't emit them as part of the class documentation. 36823a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska continue; 36923a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska } 3706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 37123a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska const ResourceName& attr_name = styleable_attr.attr_ref->name.value(); 372626b3dbf74f02ae630ae0089632f5962340694dcAdam Lesinski 37323a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska StringPiece package_name = attr_name.package; 37423a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (package_name.empty()) { 37523a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska package_name = context_->GetCompilationPackage(); 37623a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska } 377626b3dbf74f02ae630ae0089632f5962340694dcAdam Lesinski 37823a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska std::unique_ptr<IntMember> index_member = 37923a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska util::make_unique<IntMember>(sorted_attributes[i].field_name, static_cast<uint32_t>(i)); 38023a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska 38123a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska AnnotationProcessor* attr_processor = index_member->GetCommentBuilder(); 38223a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska 38323a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (!comment.empty()) { 38423a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska attr_processor->AppendComment("<p>\n@attr description"); 38523a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska attr_processor->AppendComment(comment); 38623a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska } else { 38723a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska std::stringstream default_comment; 38823a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska default_comment << "<p>This symbol is the offset where the " 38923a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska << "{@link " << package_name << ".R.attr#" 39023a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska << TransformToFieldName(attr_name.entry) << "}\n" 39123a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska << "attribute's value can be found in the " 39223a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska << "{@link #" << array_field_name << "} array."; 39323a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska attr_processor->AppendComment(default_comment.str()); 39423a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska } 395626b3dbf74f02ae630ae0089632f5962340694dcAdam Lesinski 39623a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska attr_processor->AppendNewLine(); 39723a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska AddAttributeFormatDoc(attr_processor, styleable_attr.symbol.value().attribute.get()); 39823a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska attr_processor->AppendNewLine(); 39923a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska attr_processor->AppendComment( 40023a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska StringPrintf("@attr name %s:%s", package_name.data(), attr_name.entry.data())); 401feaf99fa1b7563f15dbd4211718a6cfb7a3cc3c8Michael Wright 40223a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska out_class_def->AddMember(std::move(index_member)); 403ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 404feaf99fa1b7563f15dbd4211718a6cfb7a3cc3c8Michael Wright 405a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski if (r_txt_printer != nullptr) { 406a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski r_txt_printer->Println( 407a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski StringPrintf("int styleable %s %zd", sorted_attributes[i].field_name.c_str(), i)); 408418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski } 409ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski } 410ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski 411ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // If there is a rewrite method to generate, add the statements that rewrite package IDs 412ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // for this styleable. 413ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (out_rewrite_method != nullptr) { 414ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski out_rewrite_method->AppendStatement( 415ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski StringPrintf("for (int i = 0; i < styleable.%s.length; i++) {", array_field_name.data())); 416ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski out_rewrite_method->AppendStatement( 417ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski StringPrintf(" if ((styleable.%s[i] & 0xff000000) == 0) {", array_field_name.data())); 418ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski out_rewrite_method->AppendStatement( 419ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski StringPrintf(" styleable.%s[i] = (styleable.%s[i] & 0x00ffffff) | (p << 24);", 420ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski array_field_name.data(), array_field_name.data())); 421ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski out_rewrite_method->AppendStatement(" }"); 422ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski out_rewrite_method->AppendStatement("}"); 423ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski } 424ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski} 425ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski 426ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskivoid JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const ResourceId& id, 427ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const ResourceEntry& entry, ClassDefinition* out_class_def, 428418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski MethodDefinition* out_rewrite_method, 429a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski text::Printer* r_txt_printer) { 4301e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski ResourceId real_id = id; 4311e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski if (context_->GetMinSdkVersion() < SDK_O && name.type == ResourceType::kId && 4321e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski id.package_id() > kAppPackageId) { 433a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski // Workaround for feature splits using package IDs > 0x7F. 434a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski // See b/37498913. 4351e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski real_id = ResourceId(kAppPackageId, id.package_id(), id.entry_id()); 4361e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski } 4371e4b0e54a3db31bdbcb9385bf22bab4b96096d1fAdam Lesinski 438ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const std::string field_name = TransformToFieldName(name.entry); 43923a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (out_class_def != nullptr) { 44023a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska std::unique_ptr<ResourceMember> resource_member = 44123a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska util::make_unique<ResourceMember>(field_name, real_id); 442ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski 44323a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska // Build the comments and annotations for this entry. 44423a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska AnnotationProcessor* processor = resource_member->GetCommentBuilder(); 445ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski 44623a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska // Add the comments from any <public> tags. 44771be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski if (entry.visibility.level != Visibility::Level::kUndefined) { 44871be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski processor->AppendComment(entry.visibility.comment); 44923a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska } 4503b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski 45123a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska // Add the comments from all configurations of this entry. 45223a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska for (const auto& config_value : entry.values) { 45323a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska processor->AppendComment(config_value->value->GetComment()); 45423a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska } 455ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski 45623a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska // If this is an Attribute, append the format Javadoc. 45723a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (!entry.values.empty()) { 45823a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (Attribute* attr = ValueCast<Attribute>(entry.values.front()->value.get())) { 45923a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska // We list out the available values for the given attribute. 46023a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska AddAttributeFormatDoc(processor, attr); 46123a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska } 462ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski } 4633b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski 46423a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska out_class_def->AddMember(std::move(resource_member)); 46523a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska } 4667656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 467a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski if (r_txt_printer != nullptr) { 468a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski r_txt_printer->Print("int ") 469a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski .Print(to_string(name.type)) 470a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski .Print(" ") 471a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski .Print(field_name) 472a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski .Print(" ") 473a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski .Println(real_id.to_string()); 474418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski } 475418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski 476ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (out_rewrite_method != nullptr) { 47793190b79d11d874199cfe7258526a48cfc8399fcAdam Lesinski const StringPiece& type_str = to_string(name.type); 478ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski out_rewrite_method->AppendStatement(StringPrintf("%s.%s = (%s.%s & 0x00ffffff) | (p << 24);", 479ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski type_str.data(), field_name.data(), 480ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski type_str.data(), field_name.data())); 481ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 482ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski} 4837656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 484ceb9b2f80f853059233cdd29057f39a5960a74aeAdam LesinskiMaybe<std::string> JavaClassGenerator::UnmangleResource(const StringPiece& package_name, 485ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const StringPiece& package_name_to_generate, 486ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const ResourceEntry& entry) { 48771be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski if (SkipSymbol(entry.visibility.level)) { 488ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski return {}; 489ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski } 490ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski 491ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski std::string unmangled_package; 492ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski std::string unmangled_name = entry.name; 493ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (NameMangler::Unmangle(&unmangled_name, &unmangled_package)) { 494ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // The entry name was mangled, and we successfully unmangled it. 495ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // Check that we want to emit this symbol. 4961ef0fa9d7242b1926543bc49e35905d1be02a781Adam Lesinski if (package_name_to_generate != unmangled_package) { 497ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // Skip the entry if it doesn't belong to the package we're writing. 498ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski return {}; 499ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski } 500ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski } else if (package_name_to_generate != package_name) { 501ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // We are processing a mangled package name, 502ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // but this is a non-mangled resource. 503ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski return {}; 504ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski } 505ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski return {std::move(unmangled_name)}; 506ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski} 507ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski 508ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskibool JavaClassGenerator::ProcessType(const StringPiece& package_name_to_generate, 509ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const ResourceTablePackage& package, 510ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const ResourceTableType& type, 511ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski ClassDefinition* out_type_class_def, 512418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski MethodDefinition* out_rewrite_method_def, 513a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski Printer* r_txt_printer) { 514ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski for (const auto& entry : type.entries) { 515ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const Maybe<std::string> unmangled_name = 516ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski UnmangleResource(package.name, package_name_to_generate, *entry); 517ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (!unmangled_name) { 518ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski continue; 519ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 5206cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski 521ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // Create an ID if there is one (static libraries don't need one). 522ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceId id; 523ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (package.id && type.id && entry->id) { 524ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski id = ResourceId(package.id.value(), type.id.value(), entry->id.value()); 5253b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski } 5263b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski 527ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // We need to make sure we hide the fact that we are generating kAttrPrivate attributes. 528ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const ResourceNameRef resource_name( 529ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski package_name_to_generate, 530ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski type.type == ResourceType::kAttrPrivate ? ResourceType::kAttr : type.type, 531ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski unmangled_name.value()); 5326cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski 533ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // Check to see if the unmangled name is a valid Java name (not a keyword). 534ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (!IsValidSymbol(unmangled_name.value())) { 535ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream err; 536ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski err << "invalid symbol name '" << resource_name << "'"; 537ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski error_ = err.str(); 538ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return false; 539ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 5409e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski 541ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (resource_name.type == ResourceType::kStyleable) { 542ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CHECK(!entry->values.empty()); 543769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 544ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const Styleable* styleable = 545ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski static_cast<const Styleable*>(entry->values.front()->value.get()); 546769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 547ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski ProcessStyleable(resource_name, id, *styleable, package_name_to_generate, out_type_class_def, 548a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski out_rewrite_method_def, r_txt_printer); 549ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else { 550418763ff54170484c527bf618ef2fad34fe63f97Adam Lesinski ProcessResource(resource_name, id, *entry, out_type_class_def, out_rewrite_method_def, 551a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski r_txt_printer); 552769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski } 553ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 554ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return true; 555769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski} 556769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 557a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinskibool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, OutputStream* out, 558a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski OutputStream* out_r_txt) { 559a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski return Generate(package_name_to_generate, package_name_to_generate, out, out_r_txt); 5609e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski} 5619e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski 562ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinskistatic void AppendJavaDocAnnotations(const std::vector<std::string>& annotations, 563ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski AnnotationProcessor* processor) { 564ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (const std::string& annotation : annotations) { 565ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string proper_annotation = "@"; 566ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski proper_annotation += annotation; 567ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski processor->AppendComment(proper_annotation); 568ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 5693524a23edb88f0e67352d55ac6a2919f1edf7b30Adam Lesinski} 5703524a23edb88f0e67352d55ac6a2919f1edf7b30Adam Lesinski 571ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, 572a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski const StringPiece& out_package_name, OutputStream* out, 573a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski OutputStream* out_r_txt) { 574ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski ClassDefinition r_class("R", ClassQualifier::kNone, true); 575ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski std::unique_ptr<MethodDefinition> rewrite_method; 576ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski 577a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski std::unique_ptr<Printer> r_txt_printer; 578a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski if (out_r_txt != nullptr) { 579a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski r_txt_printer = util::make_unique<Printer>(out_r_txt); 580a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski } 581a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski 582ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // Generate an onResourcesLoaded() callback if requested. 58323a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (out != nullptr && options_.rewrite_callback_options) { 584ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski rewrite_method = 585ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski util::make_unique<MethodDefinition>("public static void onResourcesLoaded(int p)"); 586b5dc4bd49a036e3403ca17e961d2c8e13e038295Adam Lesinski for (const std::string& package_to_callback : 587b5dc4bd49a036e3403ca17e961d2c8e13e038295Adam Lesinski options_.rewrite_callback_options.value().packages_to_callback) { 588b5dc4bd49a036e3403ca17e961d2c8e13e038295Adam Lesinski rewrite_method->AppendStatement( 589b5dc4bd49a036e3403ca17e961d2c8e13e038295Adam Lesinski StringPrintf("%s.R.onResourcesLoaded(p);", package_to_callback.data())); 590b5dc4bd49a036e3403ca17e961d2c8e13e038295Adam Lesinski } 591ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski } 592ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 593ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (const auto& package : table_->packages) { 594ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (const auto& type : package->types) { 595ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type->type == ResourceType::kAttrPrivate) { 596ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // We generate these as part of the kAttr type, so skip them here. 597ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski continue; 598ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 5996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 6001ef0fa9d7242b1926543bc49e35905d1be02a781Adam Lesinski // Stay consistent with AAPT and generate an empty type class if the R class is public. 601ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const bool force_creation_if_empty = 602ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski (options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic); 6033524a23edb88f0e67352d55ac6a2919f1edf7b30Adam Lesinski 60423a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska std::unique_ptr<ClassDefinition> class_def; 60523a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (out != nullptr) { 60623a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska class_def = util::make_unique<ClassDefinition>( 60723a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska to_string(type->type), ClassQualifier::kStatic, force_creation_if_empty); 60823a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska } 60923a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska 610ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (!ProcessType(package_name_to_generate, *package, *type, class_def.get(), 611a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski rewrite_method.get(), r_txt_printer.get())) { 6126cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski return false; 613ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 614ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 615ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type->type == ResourceType::kAttr) { 616ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // Also include private attributes in this same class. 617ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate); 618ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (priv_type) { 619ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (!ProcessType(package_name_to_generate, *package, *priv_type, class_def.get(), 620a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski rewrite_method.get(), r_txt_printer.get())) { 621ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return false; 622ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 623ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 624ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 625ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 62623a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (out != nullptr && type->type == ResourceType::kStyleable && 627ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic) { 628ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // When generating a public R class, we don't want Styleable to be part 629ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski // of the API. It is only emitted for documentation purposes. 630ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski class_def->GetCommentBuilder()->AppendComment("@doconly"); 631ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 632ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 63323a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (out != nullptr) { 63423a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska AppendJavaDocAnnotations(options_.javadoc_annotations, class_def->GetCommentBuilder()); 63523a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska r_class.AddMember(std::move(class_def)); 63623a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska } 6376cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski } 638ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } 6396cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski 640ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (rewrite_method != nullptr) { 641ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski r_class.AddMember(std::move(rewrite_method)); 642ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski } 643ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski 64423a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska if (out != nullptr) { 64523a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska AppendJavaDocAnnotations(options_.javadoc_annotations, r_class.GetCommentBuilder()); 64623a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska ClassDefinition::WriteJavaFile(&r_class, out_package_name, options_.use_final, out); 64723a6e1e3901e1ef1e2bd5ebb2aff08b767d19c49Izabela Orlowska } 648ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return true; 6496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 6506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 651ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski} // namespace aapt 652