diff options
-rw-r--r-- | android/prebuilt.go | 5 | ||||
-rw-r--r-- | java/app.go | 84 | ||||
-rw-r--r-- | java/app_test.go | 85 | ||||
-rw-r--r-- | java/java_test.go | 4 |
4 files changed, 169 insertions, 9 deletions
diff --git a/android/prebuilt.go b/android/prebuilt.go index 3be10f72..3d9804ce 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -50,6 +50,11 @@ func (p *Prebuilt) Name(name string) string { return "prebuilt_" + name } +// The below source-related functions and the srcs, src fields are based on an assumption that +// prebuilt modules have a static source property at the moment. Currently there is only one +// exception, android_app_import, which chooses a source file depending on the product's DPI +// preference configs. We'll want to add native support for dynamic source cases if we end up having +// more modules like this. func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path { if p.srcs != nil { if len(*p.srcs) == 0 { diff --git a/java/app.go b/java/app.go index 157487fe..44841d84 100644 --- a/java/app.go +++ b/java/app.go @@ -17,18 +17,21 @@ package java // This file contains the module types for compiling Android apps. import ( + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" "path/filepath" + "reflect" "sort" "strings" - "github.com/google/blueprint" - "github.com/google/blueprint/proptools" - "android/soong/android" "android/soong/cc" "android/soong/tradefed" ) +var supportedDpis = [...]string{"Ldpi", "Mdpi", "Hdpi", "Xhdpi", "Xxhdpi", "Xxxhdpi"} +var dpiVariantsStruct reflect.Type + func init() { android.RegisterModuleType("android_app", AndroidAppFactory) android.RegisterModuleType("android_test", AndroidTestFactory) @@ -36,6 +39,22 @@ func init() { android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory) android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory) android.RegisterModuleType("android_app_import", AndroidAppImportFactory) + + // Dynamically construct a struct for the dpi_variants property in android_app_import. + perDpiStruct := reflect.StructOf([]reflect.StructField{ + { + Name: "Apk", + Type: reflect.TypeOf((*string)(nil)), + }, + }) + dpiVariantsFields := make([]reflect.StructField, len(supportedDpis)) + for i, dpi := range supportedDpis { + dpiVariantsFields[i] = reflect.StructField{ + Name: string(dpi), + Type: perDpiStruct, + } + } + dpiVariantsStruct = reflect.StructOf(dpiVariantsFields) } // AndroidManifest.xml merging @@ -695,6 +714,26 @@ type AndroidAppImportProperties struct { // A prebuilt apk to import Apk string + // Per-DPI settings. This property makes it possible to specify a different source apk path for + // each DPI. + // + // Example: + // + // android_app_import { + // name: "example_import", + // apk: "prebuilts/example.apk", + // dpi_variants: { + // mdpi: { + // apk: "prebuilts/example_mdpi.apk", + // }, + // xhdpi: { + // apk: "prebuilts/example_xhdpi.apk", + // }, + // }, + // certificate: "PRESIGNED", + // } + Dpi_variants interface{} + // The name of a certificate in the default certificate directory, blank to use the default // product certificate, or an android_app_certificate module name in the form ":module". Certificate *string @@ -716,6 +755,41 @@ type AndroidAppImportProperties struct { Overrides []string } +func getApkPathForDpi(dpiVariantsValue reflect.Value, dpi string) string { + dpiField := dpiVariantsValue.FieldByName(proptools.FieldNameForProperty(dpi)) + if !dpiField.IsValid() { + return "" + } + apkValue := dpiField.FieldByName("Apk").Elem() + if apkValue.IsValid() { + return apkValue.String() + } + return "" +} + +// Chooses a source APK path to use based on the module's per-DPI settings and the product config. +func (a *AndroidAppImport) getSrcApkPath(ctx android.ModuleContext) string { + config := ctx.Config() + dpiVariantsValue := reflect.ValueOf(a.properties.Dpi_variants).Elem() + if !dpiVariantsValue.IsValid() { + return a.properties.Apk + } + // Match PRODUCT_AAPT_PREF_CONFIG first and then PRODUCT_AAPT_PREBUILT_DPI. + if config.ProductAAPTPreferredConfig() != "" { + if apk := getApkPathForDpi(dpiVariantsValue, config.ProductAAPTPreferredConfig()); apk != "" { + return apk + } + } + for _, dpi := range config.ProductAAPTPrebuiltDPI() { + if apk := getApkPathForDpi(dpiVariantsValue, dpi); apk != "" { + return apk + } + } + + // No match. Use the generic one. + return a.properties.Apk +} + func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) { cert := android.SrcIsModule(String(a.properties.Certificate)) if cert != "" { @@ -774,10 +848,9 @@ func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext _, certificates := collectAppDeps(ctx) // TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK - // TODO: LOCAL_DPI_VARIANTS // TODO: LOCAL_PACKAGE_SPLITS - srcApk := a.prebuilt.SingleSourcePath(ctx) + srcApk := android.PathForModuleSrc(ctx, a.getSrcApkPath(ctx)) // TODO: Install or embed JNI libraries @@ -832,6 +905,7 @@ func (a *AndroidAppImport) Name() string { // android_app_import imports a prebuilt apk with additional processing specified in the module. func AndroidAppImportFactory() android.Module { module := &AndroidAppImport{} + module.properties.Dpi_variants = reflect.New(dpiVariantsStruct).Interface() module.AddProperties(&module.properties) module.AddProperties(&module.dexpreoptProperties) diff --git a/java/app_test.go b/java/app_test.go index 66f993dc..723cde3e 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -15,17 +15,18 @@ package java import ( - "android/soong/android" - "android/soong/cc" - "fmt" "path/filepath" "reflect" + "regexp" "sort" "strings" "testing" "github.com/google/blueprint/proptools" + + "android/soong/android" + "android/soong/cc" ) var ( @@ -1235,3 +1236,81 @@ func TestAndroidAppImport_Presigned(t *testing.T) { t.Errorf("can't find aligning rule") } } + +func TestAndroidAppImport_DpiVariants(t *testing.T) { + bp := ` + android_app_import { + name: "foo", + apk: "prebuilts/apk/app.apk", + dpi_variants: { + xhdpi: { + apk: "prebuilts/apk/app_xhdpi.apk", + }, + xxhdpi: { + apk: "prebuilts/apk/app_xxhdpi.apk", + }, + }, + certificate: "PRESIGNED", + dex_preopt: { + enabled: true, + }, + } + ` + testCases := []struct { + name string + aaptPreferredConfig *string + aaptPrebuiltDPI []string + expected string + }{ + { + name: "no preferred", + aaptPreferredConfig: nil, + aaptPrebuiltDPI: []string{}, + expected: "prebuilts/apk/app.apk", + }, + { + name: "AAPTPreferredConfig matches", + aaptPreferredConfig: proptools.StringPtr("xhdpi"), + aaptPrebuiltDPI: []string{"xxhdpi", "lhdpi"}, + expected: "prebuilts/apk/app_xhdpi.apk", + }, + { + name: "AAPTPrebuiltDPI matches", + aaptPreferredConfig: proptools.StringPtr("mdpi"), + aaptPrebuiltDPI: []string{"xxhdpi", "xhdpi"}, + expected: "prebuilts/apk/app_xxhdpi.apk", + }, + { + name: "non-first AAPTPrebuiltDPI matches", + aaptPreferredConfig: proptools.StringPtr("mdpi"), + aaptPrebuiltDPI: []string{"ldpi", "xhdpi"}, + expected: "prebuilts/apk/app_xhdpi.apk", + }, + { + name: "no matches", + aaptPreferredConfig: proptools.StringPtr("mdpi"), + aaptPrebuiltDPI: []string{"ldpi", "xxxhdpi"}, + expected: "prebuilts/apk/app.apk", + }, + } + + jniRuleRe := regexp.MustCompile("^if \\(zipinfo (\\S+)") + for _, test := range testCases { + config := testConfig(nil) + config.TestProductVariables.AAPTPreferredConfig = test.aaptPreferredConfig + config.TestProductVariables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI + ctx := testAppContext(config, bp, nil) + + run(t, ctx, config) + + variant := ctx.ModuleForTests("foo", "android_common") + jniRuleCommand := variant.Output("jnis-uncompressed/foo.apk").RuleParams.Command + matches := jniRuleRe.FindStringSubmatch(jniRuleCommand) + if len(matches) != 2 { + t.Errorf("failed to extract the src apk path from %q", jniRuleCommand) + } + if test.expected != matches[1] { + t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1]) + } + } +} diff --git a/java/java_test.go b/java/java_test.go index 60ea37ce..96ef7e00 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -168,7 +168,9 @@ func testContext(config android.Config, bp string, "prebuilts/sdk/tools/core-lambda-stubs.jar": nil, "prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "current"],}`), - "prebuilts/apk/app.apk": nil, + "prebuilts/apk/app.apk": nil, + "prebuilts/apk/app_xhdpi.apk": nil, + "prebuilts/apk/app_xxhdpi.apk": nil, // For framework-res, which is an implicit dependency for framework "AndroidManifest.xml": nil, |