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

Commit 90964040 authored by Eric Fischer's avatar Eric Fischer
Browse files

Add an aapt option to allow string variations for different devices.

The --product option to aapt is a comma-separated list of characteristics
of the device being built for.  For example, --product nosdcard,grayscale
for a device with no SD card and a grayscale screen.

Strings can specify a product="characteristic" option to cause that version
of the string to be used only for that type of device.  All such strings
should also specify, at the end of the block, product="default", which
will be used if none of the variations match.  For example:

<string name="choose" product="bw">Choose black or white</string>
<string name="choose" product="grayscale">Choose a shade of gray</string>
<string name="choose" product="default">Choose a color</string>

The default characteristic will also be used when no --product option
is specified.

Change-Id: Ie6c1505599e02e15b7818e8be6ec47bc6ce71aaa
parent 89647b11
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ public:
          mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL),
          mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
          mVersionCode(NULL), mVersionName(NULL), mCustomPackage(NULL),
          mMaxResVersion(NULL), mDebugMode(false),
          mMaxResVersion(NULL), mDebugMode(false), mProduct(NULL),
          mArgc(0), mArgv(NULL)
        {}
    ~Bundle(void) {}
@@ -139,6 +139,8 @@ public:
    void setMaxResVersion(const char * val) { mMaxResVersion = val; }
    bool getDebugMode() { return mDebugMode; }
    void setDebugMode(bool val) { mDebugMode = val; }
    const char* getProduct() const { return mProduct; }
    void setProduct(const char * val) { mProduct = val; }

    /*
     * Set and get the file specification.
@@ -237,6 +239,7 @@ private:
    const char* mCustomPackage;
    const char* mMaxResVersion;
    bool        mDebugMode;
    const char* mProduct;

    /* file specification */
    int         mArgc;
+13 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ void usage(void)
        "        [-A asset-source-dir]  [-G class-list-file] [-P public-definitions-file] \\\n"
        "        [-S resource-sources [-S resource-sources ...]] "
        "        [-F apk-file] [-J R-file-dir] \\\n"
        "        [--product product1,product2,...] \\\n"
        "        [raw-files-dir [raw-files-dir] ...]\n"
        "\n"
        "   Package the android resources.  It will read assets and resources that are\n"
@@ -154,6 +155,9 @@ void usage(void)
        "       components target the given package.  Useful when used in\n"
        "       conjunction with --rename-manifest-package to fix tests against\n"
        "       a package that has been renamed.\n"
        "   --product\n"
        "       Specifies which variant to choose for strings that have\n"
        "       product variants\n"
        "   --utf16\n"
        "       changes default encoding for resources to UTF-16.  Only useful when API\n"
        "       level is set to 7 or higher where the default encoding is UTF-8.\n");
@@ -484,6 +488,15 @@ int main(int argc, char* const argv[])
                    bundle.setInstrumentationPackageNameOverride(argv[0]);
                } else if (strcmp(cp, "-auto-add-overlay") == 0) {
                    bundle.setAutoAddOverlay(true);
                } else if (strcmp(cp, "-product") == 0) {
                    argc--;
                    argv++;
                    if (!argc) {
                        fprintf(stderr, "ERROR: No argument supplied for '--product' option\n");
                        wantUsage = true;
                        goto bail;
                    }
                    bundle.setProduct(argv[0]);
                } else {
                    fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
                    wantUsage = true;
+78 −4
Original line number Diff line number Diff line
@@ -574,6 +574,7 @@ status_t parseAndAddBag(Bundle* bundle,
                        const String16& itemIdent,
                        int32_t curFormat,
                        bool isFormatted,
                        const String16& product,
                        bool pseudolocalize,
                        const bool overwrite,
                        ResourceTable* outTable)
@@ -606,6 +607,32 @@ status_t parseAndAddBag(Bundle* bundle,
    return err;
}

/*
 * Returns true if needle is one of the elements in the comma-separated list
 * haystack, false otherwise.
 */
bool isInProductList(const String16& needle, const String16& haystack) {
    const char16_t *needle2 = needle.string();
    const char16_t *haystack2 = haystack.string();
    size_t needlesize = needle.size();

    while (*haystack2 != '\0') {
        if (strncmp16(haystack2, needle2, needlesize) == 0) {
            if (haystack2[needlesize] == '\0' || haystack2[needlesize] == ',') {
                return true;
            }
        }

        while (*haystack2 != '\0' && *haystack2 != ',') {
            haystack2++;
        }
        if (*haystack2 == ',') {
            haystack2++;
        }
    }

    return false;
}

status_t parseAndAddEntry(Bundle* bundle,
                        const sp<AaptFile>& in,
@@ -618,6 +645,7 @@ status_t parseAndAddEntry(Bundle* bundle,
                        bool curIsStyled,
                        int32_t curFormat,
                        bool isFormatted,
                        const String16& product,
                        bool pseudolocalize,
                        const bool overwrite,
                        ResourceTable* outTable)
@@ -634,6 +662,47 @@ status_t parseAndAddEntry(Bundle* bundle,
        return err;
    }

    /*
     * If a product type was specified on the command line
     * and also in the string, and the two are not the same,
     * return without adding the string.
     */

    const char *bundleProduct = bundle->getProduct();
    if (bundleProduct == NULL) {
        bundleProduct = "";
    }

    if (product.size() != 0) {
        /*
         * If the command-line-specified product is empty, only "default"
         * matches.  Other variants are skipped.  This is so generation
         * of the R.java file when the product is not known is predictable.
         */

        if (bundleProduct[0] == '\0') {
            if (strcmp16(String16("default").string(), product.string()) != 0) {
                return NO_ERROR;
            }
        } else {
            /*
             * The command-line product is not empty.
             * If the product for this string is on the command-line list,
             * it matches.  "default" also matches, but only if nothing
             * else has matched already.
             */

            if (isInProductList(product, String16(bundleProduct))) {
                ;
            } else if (strcmp16(String16("default").string(), product.string()) == 0 &&
                       !outTable->hasBagOrEntry(myPackage, curType, ident)) {
                ;
            } else {
                return NO_ERROR;
            }
        }
    }

    NOISY(printf("Adding resource entry l=%c%c c=%c%c orien=%d d=%d id=%s: %s\n",
                 config.language[0], config.language[1],
                 config.country[0], config.country[1],
@@ -713,6 +782,7 @@ status_t compileResourceFile(Bundle* bundle,
    const String16 translatable16("translatable");
    const String16 formatted16("formatted");
    const String16 false16("false");
    const String16 product16("product");

    const String16 myPackage(assets->getPackage());

@@ -760,6 +830,7 @@ status_t compileResourceFile(Bundle* bundle,
            bool curIsStyled = false;
            bool curIsPseudolocalizable = false;
            bool curIsFormatted = fileIsTranslatable;
            String16 curProduct;
            bool localHasErrors = false;

            if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
@@ -1157,6 +1228,8 @@ status_t compileResourceFile(Bundle* bundle,
                        translatable.setTo(block.getAttributeStringValue(i, &length));
                    } else if (strcmp16(attr, formatted16.string()) == 0) {
                        formatted.setTo(block.getAttributeStringValue(i, &length));
                    } else if (strcmp16(attr, product16.string()) == 0) {
                        curProduct.setTo(block.getAttributeStringValue(i, &length));
                    }
                }
                
@@ -1374,7 +1447,7 @@ status_t compileResourceFile(Bundle* bundle,

                        err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType,
                                ident, parentIdent, itemIdent, curFormat, curIsFormatted,
                                false, overwrite, outTable);
                                curProduct, false, overwrite, outTable);
                        if (err == NO_ERROR) {
                            if (curIsPseudolocalizable && localeIsDefined(curParams)
                                    && bundle->getPseudolocalize()) {
@@ -1383,7 +1456,7 @@ status_t compileResourceFile(Bundle* bundle,
                                block.setPosition(parserPosition);
                                err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage,
                                        curType, ident, parentIdent, itemIdent, curFormat,
                                        curIsFormatted, true, overwrite, outTable);
                                        curIsFormatted, curProduct, true, overwrite, outTable);
#endif
                            }
                        } 
@@ -1407,7 +1480,7 @@ status_t compileResourceFile(Bundle* bundle,

                err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident,
                        *curTag, curIsStyled, curFormat, curIsFormatted,
                        false, overwrite, outTable);
                        curProduct, false, overwrite, outTable);

                if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR?
                    hasErrors = localHasErrors = true;
@@ -1419,7 +1492,8 @@ status_t compileResourceFile(Bundle* bundle,
                        block.setPosition(parserPosition);
                        err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType,
                                ident, *curTag, curIsStyled, curFormat,
                                curIsFormatted, true, overwrite, outTable);
                                curIsFormatted, curProduct,
                                true, overwrite, outTable);
                        if (err != NO_ERROR) {
                            hasErrors = localHasErrors = true;
                        }