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        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 */
133def 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}
139gradle.ext.currentSdk = studioCompat.enableApiModules ? ApiModule.CURRENT : 'current'
140
141// the hashmap from apiModuleProjectFolder -> ApiModule
142gradle.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 */
148def 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 */
164ApiModule getApiModule(Project project) {
165    return gradle.ext.folderToApiModuleMapping[project.projectDir.canonicalPath]
166}
167
168studioCompat.modules.each { k, v ->
169    setupDependencies(v)
170}
171// create these fake modules only if Studio opens the project.
172if (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}
203gradle.ext.studioCompat = studioCompat
204gradle.ext.getApiModule = this.&getApiModule
205