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 */ 16import android.support.build.ApiModule 17import java.nio.file.Path; 18import 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 28def studioCompat = [ 29 enableApiModules : hasProperty('android.injected.invoked.from.ide'), 30 modules : [ 31 v4 : [ 32 apiTargets : [ 33 new ApiModule("donut",4), 34 new ApiModule("eclair",5), 35 new ApiModule("eclair-mr1", 7), 36 new ApiModule("froyo",8), 37 new ApiModule("gingerbread",9), 38 new ApiModule("honeycomb",11), 39 new ApiModule("honeycomb_mr1",12), 40 new ApiModule("honeycomb_mr2",13), 41 new ApiModule("ics",14), 42 new ApiModule("ics-mr1",15), 43 new ApiModule("jellybean", 16), 44 new ApiModule("jellybean-mr1",17), 45 new ApiModule("jellybean-mr2",18), 46 new ApiModule("kitkat",19), 47 new ApiModule("api20",20), 48 new ApiModule("api21",21), 49 new ApiModule("api22",22), 50 new ApiModule("api23",23), 51 new ApiModule("api24", ApiModule.CURRENT) 52 ], 53 dependencies : [":support-annotations"], 54 folder : "v4", 55 moduleName : "support-v4" 56 ], 57 v13 : [ 58 apiTargets : [ 59 new ApiModule("ics", 14), 60 new ApiModule("ics-mr1", 15), 61 new ApiModule("api23", 23), 62 new ApiModule("api24", ApiModule.CURRENT) 63 ], 64 dependencies : [":support-v4"], 65 folder : "v13", 66 moduleName : "support-v13" 67 ], 68 mediaRouter : [ 69 apiTargets : [ 70 new ApiModule("jellybean", 16), 71 new ApiModule("jellybean-mr1", 17), 72 new ApiModule("jellybean-mr2", 18), 73 new ApiModule("api24", ApiModule.CURRENT) 74 ], 75 dependencies : [':support-appcompat-v7', ':support-palette-v7'], 76 folder : "v7/mediarouter", 77 moduleName : "support-mediarouter-v7" 78 ] 79 ] 80] 81 82/** 83 * Adds a link to the previous ApiModule for each module. This information is later used when 84 * setting dependencies. 85 */ 86def setupDependencies(projectConfig) { 87 projectConfig.apiTargets.eachWithIndex { entry, index -> 88 entry.parentModuleName = projectConfig.moduleName 89 entry.prev = index == 0 ? null : projectConfig.apiTargets[index - 1] 90 } 91} 92gradle.ext.currentSdk = studioCompat.enableApiModules ? ApiModule.CURRENT : 'current' 93 94// the hashmap from apiModuleProjectFolder -> ApiModule 95gradle.ext.folderToApiModuleMapping = new HashMap() 96 97/** 98 * For each APIModule in the given projectConfig, creates a gradle module. These modules use the 99 * common `apiModule.gradle` build file. 100 */ 101def createModules(projectConfig) { 102 Path buildFile = Paths.get(file("apiModule.gradle").toURI()) 103 projectConfig.apiTargets.each { ApiModule module -> 104 logger.info "creating ${module.moduleName}" 105 module.setParentModuleDependencies(projectConfig.dependencies) 106 include "${module.moduleName}" 107 def folder = new File(rootDir, "${projectConfig.folder}/${module.folderName}") 108 project("${module.moduleName}").projectDir = folder 109 project("${module.moduleName}").buildFileName = Paths.get(folder.toURI()).relativize(buildFile) 110 gradle.ext.folderToApiModuleMapping[folder.canonicalPath] = module 111 } 112} 113 114/** 115 * returns the APIModule for the given project. 116 */ 117ApiModule getApiModule(Project project) { 118 return gradle.ext.folderToApiModuleMapping[project.projectDir.canonicalPath] 119} 120 121studioCompat.modules.each { k, v -> 122 setupDependencies(v) 123} 124// create these fake modules only if Studio opens the project. 125if (studioCompat.enableApiModules) { 126 // validate we have the 99 folder, otherwise it wont work 127 def currentSdkPrebuilt = file("${rootProject.projectDir}/../../prebuilts/sdk/" + 128 "${ApiModule.CURRENT}/") 129 if (!currentSdkPrebuilt.exists()) { 130 throw new GradleScriptException( 131 "You need a symlink in prebuilts/sdk/${ApiModule.CURRENT} that points to" 132 + " prebuilts/sdk/current." 133 + "Without it, studio cannot understand current SDK.\n" 134 + "> ln -s ../../prebuilts/sdk/current " 135 + "../../prebuilts/sdk/${ApiModule.CURRENT}\n" 136 , new Exception()) 137 } 138 Properties localProps = new Properties() 139 def localPropsStream = new FileInputStream(file("${rootProject.projectDir}/local.properties")) 140 try { 141 localProps.load(localPropsStream) 142 def sdkDir = localProps.get("sdk.dir") 143 if (sdkDir != null && sdkDir != "") { 144 throw new GradleScriptException("You should not have sdk.dir in local.properties because" 145 + " it overrides android.dir and prevents studio from seeing current sdk. " 146 + " Studio may add it by mistake, just remove it and it will work fine.", 147 new Exception()) 148 } 149 } finally { 150 localPropsStream.close() 151 } 152 studioCompat.modules.each { k, v -> 153 createModules(v) 154 } 155} 156gradle.ext.studioCompat = studioCompat 157gradle.ext.getApiModule = this.&getApiModule