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