Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f1c54e6e authored by Adam Lesinski's avatar Adam Lesinski Committed by Android (Google) Code Review
Browse files

Merge "AAPT2: Fix small issue with detecting translatable resources"

parents f386e9da 9f22204c
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -446,11 +446,11 @@ bool ResourceParser::parseString(XmlPullParser* parser, ParsedResource* outResou
        }
    }

    bool untranslateable = false;
    if (Maybe<StringPiece16> untranslateableAttr = findAttribute(parser, u"untranslateable")) {
        if (!ResourceUtils::tryParseBool(untranslateableAttr.value(), &untranslateable)) {
    bool translateable = mOptions.translatable;
    if (Maybe<StringPiece16> translateableAttr = findAttribute(parser, u"translatable")) {
        if (!ResourceUtils::tryParseBool(translateableAttr.value(), &translateable)) {
            mDiag->error(DiagMessage(source)
                         << "invalid value for 'untranslateable'. Must be a boolean");
                         << "invalid value for 'translatable'. Must be a boolean");
            return false;
        }
    }
@@ -461,10 +461,10 @@ bool ResourceParser::parseString(XmlPullParser* parser, ParsedResource* outResou
        return false;
    }

    if (formatted || untranslateable) {
    if (formatted && translateable) {
        if (String* stringValue = valueCast<String>(outResource->value.get())) {
            if (!util::verifyJavaStringFormat(*stringValue->value)) {
                mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
                mDiag->error(DiagMessage(source)
                             << "multiple substitutions specified in non-positional format; "
                                "did you mean to add the formatted=\"false\" attribute?");
                return false;
@@ -973,6 +973,9 @@ bool ResourceParser::parseDeclareStyleable(XmlPullParser* parser, ParsedResource
    const Source source = mSource.withLine(parser->getLineNumber());
    std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();

    // Declare-styleable is always public, because it technically only exists in R.java.
    outResource->symbolState = SymbolState::kPublic;

    std::u16string comment;
    bool error = false;
    const size_t depth = parser->getDepth();
+5 −0
Original line number Diff line number Diff line
@@ -40,6 +40,11 @@ struct ResourceParserOptions {
     * that don't match before we compile them.
     */
    Maybe<std::u16string> product;

    /**
     * Whether the default setting for this parser is to allow translation.
     */
    bool translatable = true;
};

/*
+16 −1
Original line number Diff line number Diff line
@@ -52,8 +52,10 @@ struct ResourceParserTest : public ::testing::Test {
                                         Maybe<std::u16string> product = {}) {
        std::stringstream input(kXmlPreamble);
        input << "<resources>\n" << str << "\n</resources>" << std::endl;
        ResourceParserOptions parserOptions;
        parserOptions.product = product;
        ResourceParser parser(mContext->getDiagnostics(), &mTable, Source{ "test" }, {},
                              ResourceParserOptions{ product });
                              parserOptions);
        XmlPullParser xmlParser(input);
        if (parser.parse(&xmlParser)) {
            return ::testing::AssertionSuccess();
@@ -80,6 +82,14 @@ TEST_F(ResourceParserTest, ParseEscapedString) {
    EXPECT_EQ(std::u16string(u"?123"), *str->value);
}

TEST_F(ResourceParserTest, ParseFormattedString) {
    std::string input = "<string name=\"foo\">%d %s</string>";
    ASSERT_FALSE(testParse(input));

    input = "<string name=\"foo\">%1$d %2$s</string>";
    ASSERT_TRUE(testParse(input));
}

TEST_F(ResourceParserTest, IgnoreXliffTags) {
    std::string input = "<string name=\"foo\" \n"
                        "        xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n"
@@ -322,6 +332,11 @@ TEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) {
                        "</declare-styleable>";
    ASSERT_TRUE(testParse(input));

    Maybe<ResourceTable::SearchResult> result =
            mTable.findResource(test::parseNameOrDie(u"@styleable/foo"));
    AAPT_ASSERT_TRUE(result);
    EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbolStatus.state);

    Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/bar");
    ASSERT_NE(attr, nullptr);
    EXPECT_TRUE(attr->isWeak());
+8 −1
Original line number Diff line number Diff line
@@ -132,8 +132,15 @@ static bool compileTable(IAaptContext* context, const CompileOptions& options,

        // Parse the values file from XML.
        XmlPullParser xmlParser(fin);

        ResourceParserOptions parserOptions;
        parserOptions.product = options.product;

        // If the filename includes donottranslate, then the default translatable is false.
        parserOptions.translatable = pathData.name.find(u"donottranslate") == std::string::npos;

        ResourceParser resParser(context->getDiagnostics(), &table, pathData.source,
                                 pathData.config, ResourceParserOptions{ options.product });
                                 pathData.config, parserOptions);
        if (!resParser.parse(&xmlParser)) {
            return false;
        }
+41 −6
Original line number Diff line number Diff line
@@ -38,26 +38,61 @@ struct AutoVersioner : public IResourceTableConsumer {
    bool consume(IAaptContext* context, ResourceTable* table) override;
};

struct PrivateAttributeMover : public IResourceTableConsumer {
    bool consume(IAaptContext* context, ResourceTable* table) override;
};

struct XmlAutoVersioner : public IXmlResourceConsumer {
    bool consume(IAaptContext* context, XmlResource* resource) override;
};

/**
 * If any attribute resource values are defined as public, this consumer will move all private
 * attribute resource values to a private ^private-attr type, avoiding backwards compatibility
 * issues with new apps running on old platforms.
 *
 * The Android platform ignores resource attributes it doesn't recognize, so an app developer can
 * use new attributes in their layout XML files without worrying about versioning. This assumption
 * actually breaks on older platforms. OEMs may add private attributes that are used internally.
 * AAPT originally assigned all private attributes IDs immediately proceeding the public attributes'
 * IDs.
 *
 * This means that on a newer Android platform, an ID previously assigned to a private attribute
 * may end up assigned to a public attribute.
 *
 * App developers assume using the newer attribute is safe on older platforms because it will
 * be ignored. Instead, the platform thinks the new attribute is an older, private attribute and
 * will interpret it as such. This leads to unintended styling and exceptions thrown due to
 * unexpected types.
 *
 * By moving the private attributes to a completely different type, this ID conflict will never
 * occur.
 */
struct PrivateAttributeMover : public IResourceTableConsumer {
    bool consume(IAaptContext* context, ResourceTable* table) override;
};

/**
 * Resolves all references to resources in the ResourceTable and assigns them IDs.
 * The ResourceTable must already have IDs assigned to each resource.
 * Once the ResourceTable is processed by this linker, it is ready to be flattened.
 */
struct ReferenceLinker : public IResourceTableConsumer {
    bool consume(IAaptContext* context, ResourceTable* table) override;
};

class XmlReferenceLinker : IXmlResourceConsumer {
/**
 * Resolves attributes in the XmlResource and compiles string values to resource values.
 * Once an XmlResource is processed by this linker, it is ready to be flattened.
 */
class XmlReferenceLinker : public IXmlResourceConsumer {
private:
    std::set<int> mSdkLevelsFound;

public:
    bool consume(IAaptContext* context, XmlResource* resource) override;

    const std::set<int>& getSdkLevels() const {
    /**
     * Once the XmlResource has been consumed, this returns the various SDK levels in which
     * framework attributes used within the XML document were defined.
     */
    inline const std::set<int>& getSdkLevels() const {
        return mSdkLevelsFound;
    }
};