1// Copyright 2015 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package java 16 17// This file contains the module types for compiling Android apps. 18 19import ( 20 "path/filepath" 21 "strings" 22 23 "github.com/google/blueprint" 24 25 "android/soong/common" 26) 27 28// AAR prebuilts 29// AndroidManifest.xml merging 30// package splits 31 32type androidAppProperties struct { 33 // path to a certificate, or the name of a certificate in the default 34 // certificate directory, or blank to use the default product certificate 35 Certificate string 36 37 // paths to extra certificates to sign the apk with 38 Additional_certificates []string 39 40 // If set, create package-export.apk, which other packages can 41 // use to get PRODUCT-agnostic resource data like IDs and type definitions. 42 Export_package_resources bool 43 44 // flags passed to aapt when creating the apk 45 Aaptflags []string 46 47 // list of resource labels to generate individual resource packages 48 Package_splits []string 49 50 // list of directories relative to the Blueprints file containing assets. 51 // Defaults to "assets" 52 Asset_dirs []string 53 54 // list of directories relative to the Blueprints file containing 55 // Java resources 56 Android_resource_dirs []string 57} 58 59type AndroidApp struct { 60 javaBase 61 62 appProperties androidAppProperties 63 64 aaptJavaFileList common.Path 65 exportPackage common.Path 66} 67 68func (a *AndroidApp) JavaDependencies(ctx AndroidJavaModuleContext) []string { 69 deps := a.javaBase.JavaDependencies(ctx) 70 71 if !a.properties.No_standard_libraries { 72 switch a.properties.Sdk_version { // TODO: Res_sdk_version? 73 case "current", "system_current", "": 74 deps = append(deps, "framework-res") 75 default: 76 // We'll already have a dependency on an sdk prebuilt android.jar 77 } 78 } 79 80 return deps 81} 82 83func (a *AndroidApp) GenerateJavaBuildActions(ctx common.AndroidModuleContext) { 84 aaptFlags, aaptDeps, hasResources := a.aaptFlags(ctx) 85 86 if hasResources { 87 // First generate R.java so we can build the .class files 88 aaptRJavaFlags := append([]string(nil), aaptFlags...) 89 90 publicResourcesFile, proguardOptionsFile, aaptJavaFileList := 91 CreateResourceJavaFiles(ctx, aaptRJavaFlags, aaptDeps) 92 a.aaptJavaFileList = aaptJavaFileList 93 a.ExtraSrcLists = append(a.ExtraSrcLists, aaptJavaFileList) 94 95 if a.appProperties.Export_package_resources { 96 aaptPackageFlags := append([]string(nil), aaptFlags...) 97 var hasProduct bool 98 for _, f := range aaptPackageFlags { 99 if strings.HasPrefix(f, "--product") { 100 hasProduct = true 101 break 102 } 103 } 104 105 if !hasProduct { 106 aaptPackageFlags = append(aaptPackageFlags, 107 "--product "+ctx.AConfig().ProductAaptCharacteristics()) 108 } 109 a.exportPackage = CreateExportPackage(ctx, aaptPackageFlags, aaptDeps) 110 ctx.CheckbuildFile(a.exportPackage) 111 } 112 ctx.CheckbuildFile(publicResourcesFile) 113 ctx.CheckbuildFile(proguardOptionsFile) 114 ctx.CheckbuildFile(aaptJavaFileList) 115 } 116 117 // apps manifests are handled by aapt, don't let javaBase see them 118 a.properties.Manifest = nil 119 120 //if !ctx.ContainsProperty("proguard.enabled") { 121 // a.properties.Proguard.Enabled = true 122 //} 123 124 a.javaBase.GenerateJavaBuildActions(ctx) 125 126 aaptPackageFlags := append([]string(nil), aaptFlags...) 127 var hasProduct bool 128 for _, f := range aaptPackageFlags { 129 if strings.HasPrefix(f, "--product") { 130 hasProduct = true 131 break 132 } 133 } 134 135 if !hasProduct { 136 aaptPackageFlags = append(aaptPackageFlags, 137 "--product "+ctx.AConfig().ProductAaptCharacteristics()) 138 } 139 140 certificate := a.appProperties.Certificate 141 if certificate == "" { 142 certificate = ctx.AConfig().DefaultAppCertificate(ctx).String() 143 } else if dir, _ := filepath.Split(certificate); dir == "" { 144 certificate = filepath.Join(ctx.AConfig().DefaultAppCertificateDir(ctx).String(), certificate) 145 } else { 146 certificate = filepath.Join(common.PathForSource(ctx).String(), certificate) 147 } 148 149 certificates := []string{certificate} 150 for _, c := range a.appProperties.Additional_certificates { 151 certificates = append(certificates, filepath.Join(common.PathForSource(ctx).String(), c)) 152 } 153 154 a.outputFile = CreateAppPackage(ctx, aaptPackageFlags, a.outputFile, certificates) 155 ctx.InstallFileName(common.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile) 156} 157 158var aaptIgnoreFilenames = []string{ 159 ".svn", 160 ".git", 161 ".ds_store", 162 "*.scc", 163 ".*", 164 "CVS", 165 "thumbs.db", 166 "picasa.ini", 167 "*~", 168} 169 170func (a *AndroidApp) aaptFlags(ctx common.AndroidModuleContext) ([]string, common.Paths, bool) { 171 aaptFlags := a.appProperties.Aaptflags 172 hasVersionCode := false 173 hasVersionName := false 174 for _, f := range aaptFlags { 175 if strings.HasPrefix(f, "--version-code") { 176 hasVersionCode = true 177 } else if strings.HasPrefix(f, "--version-name") { 178 hasVersionName = true 179 } 180 } 181 182 if true /* is not a test */ { 183 aaptFlags = append(aaptFlags, "-z") 184 } 185 186 assetDirs := common.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Asset_dirs, "assets") 187 resourceDirs := common.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Android_resource_dirs, "res") 188 189 var overlayResourceDirs common.Paths 190 // For every resource directory, check if there is an overlay directory with the same path. 191 // If found, it will be prepended to the list of resource directories. 192 for _, overlayDir := range ctx.AConfig().ResourceOverlays() { 193 for _, resourceDir := range resourceDirs { 194 overlay := overlayDir.OverlayPath(ctx, resourceDir) 195 if overlay.Valid() { 196 overlayResourceDirs = append(overlayResourceDirs, overlay.Path()) 197 } 198 } 199 } 200 201 if len(overlayResourceDirs) > 0 { 202 resourceDirs = append(overlayResourceDirs, resourceDirs...) 203 } 204 205 // aapt needs to rerun if any files are added or modified in the assets or resource directories, 206 // use glob to create a filelist. 207 var aaptDeps common.Paths 208 var hasResources bool 209 for _, d := range resourceDirs { 210 newDeps := ctx.Glob("app_resources", filepath.Join(d.String(), "**/*"), aaptIgnoreFilenames) 211 aaptDeps = append(aaptDeps, newDeps...) 212 if len(newDeps) > 0 { 213 hasResources = true 214 } 215 } 216 for _, d := range assetDirs { 217 newDeps := ctx.Glob("app_assets", filepath.Join(d.String(), "**/*"), aaptIgnoreFilenames) 218 aaptDeps = append(aaptDeps, newDeps...) 219 } 220 221 var manifestFile string 222 if a.properties.Manifest == nil { 223 manifestFile = "AndroidManifest.xml" 224 } else { 225 manifestFile = *a.properties.Manifest 226 } 227 228 manifestPath := common.PathForModuleSrc(ctx, manifestFile) 229 aaptDeps = append(aaptDeps, manifestPath) 230 231 aaptFlags = append(aaptFlags, "-M "+manifestPath.String()) 232 aaptFlags = append(aaptFlags, common.JoinWithPrefix(assetDirs.Strings(), "-A ")) 233 aaptFlags = append(aaptFlags, common.JoinWithPrefix(resourceDirs.Strings(), "-S ")) 234 235 ctx.VisitDirectDeps(func(module blueprint.Module) { 236 var depFile common.OptionalPath 237 if sdkDep, ok := module.(sdkDependency); ok { 238 depFile = common.OptionalPathForPath(sdkDep.ClasspathFile()) 239 } else if javaDep, ok := module.(JavaDependency); ok { 240 if ctx.OtherModuleName(module) == "framework-res" { 241 depFile = common.OptionalPathForPath(javaDep.(*javaBase).module.(*AndroidApp).exportPackage) 242 } 243 } 244 if depFile.Valid() { 245 aaptFlags = append(aaptFlags, "-I "+depFile.String()) 246 aaptDeps = append(aaptDeps, depFile.Path()) 247 } 248 }) 249 250 sdkVersion := a.properties.Sdk_version 251 if sdkVersion == "" { 252 sdkVersion = ctx.AConfig().PlatformSdkVersion() 253 } 254 255 aaptFlags = append(aaptFlags, "--min-sdk-version "+sdkVersion) 256 aaptFlags = append(aaptFlags, "--target-sdk-version "+sdkVersion) 257 258 if !hasVersionCode { 259 aaptFlags = append(aaptFlags, "--version-code "+ctx.AConfig().PlatformSdkVersion()) 260 } 261 262 if !hasVersionName { 263 aaptFlags = append(aaptFlags, 264 "--version-name "+ctx.AConfig().PlatformVersion()+"-"+ctx.AConfig().BuildNumber()) 265 } 266 267 // TODO: LOCAL_PACKAGE_OVERRIDES 268 // $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \ 269 270 // TODO: LOCAL_INSTRUMENTATION_FOR 271 // $(addprefix --rename-instrumentation-target-package , $(PRIVATE_MANIFEST_INSTRUMENTATION_FOR)) 272 273 return aaptFlags, aaptDeps, hasResources 274} 275 276func AndroidAppFactory() (blueprint.Module, []interface{}) { 277 module := &AndroidApp{} 278 279 module.properties.Dex = true 280 281 return NewJavaBase(&module.javaBase, module, common.DeviceSupported, &module.appProperties) 282} 283