1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 import android.support.build.ApiModule 17 import java.nio.file.Path; 18 import java.nio.file.Paths; 19 20 /** 21 * To add platform specific code to a library: 22 * 1) add the related source set into the studioCompat map (defined below) 23 * 2) In your build gradle file, call: 24 * * createApiSourceSets(project, gradle.ext.studioCompat.modules.<PROJECT>.apiTargets) 25 * * setApiModuleDependencies(project, dependencies, gradle.ext.studioCompat.modules.<PROJECT>.dependencies) 26 */ 27 28 def studioCompat = [ 29 enableApiModules : hasProperty('android.injected.invoked.from.ide'), 30 modules : [ 31 compat : [ 32 apiTargets : [ 33 new ApiModule("gingerbread",9), 34 new ApiModule("honeycomb",11), 35 new ApiModule("honeycomb_mr1",12), 36 new ApiModule("honeycomb_mr2",13), 37 new ApiModule("ics",14), 38 new ApiModule("ics-mr1",15), 39 new ApiModule("jellybean", 16), 40 new ApiModule("jellybean-mr1",17), 41 new ApiModule("jellybean-mr2",18), 42 new ApiModule("kitkat",19), 43 new ApiModule("api20",20), 44 new ApiModule("api21",21), 45 new ApiModule("api22",22), 46 new ApiModule("api23",23), 47 new ApiModule("api24", ApiModule.CURRENT) 48 ], 49 dependencies : [":support-annotations"], 50 folder : "compat", 51 moduleName : "support-compat" 52 ], 53 mediacompat : [ 54 apiTargets : [ 55 new ApiModule("ics",14), 56 new ApiModule("jellybean-mr2",18), 57 new ApiModule("kitkat",19), 58 new ApiModule("api21",21), 59 new ApiModule("api22",22), 60 new ApiModule("api23",23), 61 new ApiModule("api24", ApiModule.CURRENT) 62 ], 63 dependencies : [":support-compat"], 64 folder : "media-compat", 65 moduleName : "support-media-compat" 66 ], 67 coreutils : [ 68 apiTargets : [ 69 new ApiModule("gingerbread",9), 70 new ApiModule("honeycomb",11), 71 new ApiModule("jellybean", 16), 72 new ApiModule("kitkat",19), 73 new ApiModule("api20",20), 74 new ApiModule("api21",21), 75 new ApiModule("api23",23), 76 new ApiModule("api24", ApiModule.CURRENT) 77 ], 78 dependencies : [":support-compat"], 79 folder : "core-utils", 80 moduleName : "support-core-utils" 81 ], 82 coreui : [ 83 apiTargets : [ 84 new ApiModule("honeycomb",11), 85 new ApiModule("ics",14), 86 new ApiModule("jellybean-mr2",18), 87 new ApiModule("api21",21) 88 ], 89 dependencies : [":support-compat"], 90 folder : "core-ui", 91 moduleName : "support-core-ui" 92 ], 93 fragment : [ 94 apiTargets : [ 95 new ApiModule("gingerbread",9), 96 new ApiModule("honeycomb",11), 97 new ApiModule("jellybean", 16), 98 new ApiModule("api21",21) 99 ], 100 dependencies : [":support-media-compat", ":support-core-ui", ":support-core-utils"], 101 folder : "fragment", 102 moduleName : "support-fragment" 103 ], 104 v13 : [ 105 apiTargets : [ 106 new ApiModule("ics", 14), 107 new ApiModule("ics-mr1", 15), 108 new ApiModule("api23", 23), 109 new ApiModule("api24", 24), 110 new ApiModule("api25", ApiModule.CURRENT) 111 ], 112 dependencies : [":support-v4"], 113 folder : "v13", 114 moduleName : "support-v13" 115 ], 116 mediaRouter : [ 117 apiTargets : [ 118 new ApiModule("jellybean", 16), 119 new ApiModule("jellybean-mr1", 17), 120 new ApiModule("jellybean-mr2", 18), 121 new ApiModule("api24", ApiModule.CURRENT) 122 ], 123 folder : "v7/mediarouter", 124 moduleName : "support-mediarouter-v7" 125 ] 126 ] 127 ] 128 129 /** 130 * Adds a link to the previous ApiModule for each module. This information is later used when 131 * setting dependencies. 132 */ 133 def setupDependencies(projectConfig) { 134 projectConfig.apiTargets.eachWithIndex { entry, index -> 135 entry.parentModuleName = projectConfig.moduleName 136 entry.prev = index == 0 ? null : projectConfig.apiTargets[index - 1] 137 } 138 } 139 gradle.ext.currentSdk = studioCompat.enableApiModules ? ApiModule.CURRENT : 'current' 140 141 // the hashmap from apiModuleProjectFolder -> ApiModule 142 gradle.ext.folderToApiModuleMapping = new HashMap() 143 144 /** 145 * For each APIModule in the given projectConfig, creates a gradle module. These modules use the 146 * common `apiModule.gradle` build file. 147 */ 148 def createModules(projectConfig) { 149 Path buildFile = Paths.get(file("apiModule.gradle").toURI()) 150 projectConfig.apiTargets.each { ApiModule module -> 151 logger.info "creating ${module.moduleName}" 152 module.setParentModuleDependencies(projectConfig.dependencies) 153 include "${module.moduleName}" 154 def folder = new File(rootDir, "${projectConfig.folder}/${module.folderName}") 155 project("${module.moduleName}").projectDir = folder 156 project("${module.moduleName}").buildFileName = Paths.get(folder.toURI()).relativize(buildFile) 157 gradle.ext.folderToApiModuleMapping[folder.canonicalPath] = module 158 } 159 } 160 161 /** 162 * returns the APIModule for the given project. 163 */ 164 ApiModule getApiModule(Project project) { 165 return gradle.ext.folderToApiModuleMapping[project.projectDir.canonicalPath] 166 } 167 168 studioCompat.modules.each { k, v -> 169 setupDependencies(v) 170 } 171 // create these fake modules only if Studio opens the project. 172 if (studioCompat.enableApiModules) { 173 // validate we have the 99 folder, otherwise it wont work 174 def currentSdkPrebuilt = file("${rootProject.projectDir}/../../prebuilts/sdk/" + 175 "${ApiModule.CURRENT}/") 176 if (!currentSdkPrebuilt.exists()) { 177 throw new GradleScriptException( 178 "You need a symlink in prebuilts/sdk/${ApiModule.CURRENT} that points to" 179 + " prebuilts/sdk/current." 180 + "Without it, studio cannot understand current SDK.\n" 181 + "> ln -s ../../prebuilts/sdk/current " 182 + "../../prebuilts/sdk/${ApiModule.CURRENT}\n" 183 , new Exception()) 184 } 185 Properties localProps = new Properties() 186 def localPropsStream = new FileInputStream(file("${rootProject.projectDir}/local.properties")) 187 try { 188 localProps.load(localPropsStream) 189 def sdkDir = localProps.get("sdk.dir") 190 if (sdkDir != null && sdkDir != "") { 191 throw new GradleScriptException("You should not have sdk.dir in local.properties because" 192 + " it overrides android.dir and prevents studio from seeing current sdk. " 193 + " Studio may add it by mistake, just remove it and it will work fine.", 194 new Exception()) 195 } 196 } finally { 197 localPropsStream.close() 198 } 199 studioCompat.modules.each { k, v -> 200 createModules(v) 201 } 202 } 203 gradle.ext.studioCompat = studioCompat 204 gradle.ext.getApiModule = this.&getApiModule 205