blob: 32ff7019ab2d98c4d01b0c2eecd61efe182bd6dd [file] [log] [blame]
LuK133726b79022022-09-05 23:32:37 +02001import groovy.util.Node
2import groovy.util.NodeList
3import groovy.xml.XmlParser
4
LuK13379c4638c2022-09-05 13:37:03 +02005plugins {
6 id("com.android.application")
7 id("kotlin-android")
8}
9
10android {
11 compileSdk = 33
12
13 defaultConfig {
LuK133747933d12022-09-06 15:27:27 +020014 applicationId = "org.lineageos.aperture.dev"
LuK13379c4638c2022-09-05 13:37:03 +020015 minSdk = 31
16 targetSdk = 33
17 versionCode = 1
18 versionName = "1.0"
19
20 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
21 }
22
23 buildTypes {
24 named("release") {
25 // Enables code shrinking, obfuscation, and optimization.
26 isMinifyEnabled = true
27
28 // Enables resource shrinking.
29 isShrinkResources = true
30
31 // Includes the default ProGuard rules files.
32 setProguardFiles(
33 listOf(
34 getDefaultProguardFile("proguard-android-optimize.txt"),
35 "proguard-rules.pro"
36 )
37 )
38 }
39 }
40
41 compileOptions {
42 sourceCompatibility = JavaVersion.VERSION_1_8
43 targetCompatibility = JavaVersion.VERSION_1_8
44 }
45
46 kotlinOptions {
47 jvmTarget = "1.8"
48 }
49}
50
51dependencies {
LuK13375c420fa2022-10-10 13:22:45 +020052 implementation("androidx.core:core-ktx:1.9.0")
53 implementation("androidx.appcompat:appcompat:1.5.1")
LuK13379c4638c2022-09-05 13:37:03 +020054 implementation("androidx.constraintlayout:constraintlayout:2.1.4")
55 implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1")
LuK1337afc94a32022-09-05 23:30:33 +020056 implementation("androidx.preference:preference:1.2.0")
Sebastiano Barezzid130c6f2022-10-31 15:14:53 +010057 implementation("com.google.android.material:material:1.8.0-alpha02")
LuK13379c4638c2022-09-05 13:37:03 +020058
59 // CameraX core library using the camera2 implementation
60 val cameraxVersion = "1.2.0-beta02"
61 // The following line is optional, as the core library is included indirectly by camera-camera2
62 implementation("androidx.camera:camera-core:${cameraxVersion}")
63 implementation("androidx.camera:camera-camera2:${cameraxVersion}")
64 // If you want to additionally use the CameraX Lifecycle library
65 implementation("androidx.camera:camera-lifecycle:${cameraxVersion}")
66 // If you want to additionally use the CameraX VideoCapture library
67 implementation("androidx.camera:camera-video:${cameraxVersion}")
68 // If you want to additionally use the CameraX View class
69 implementation("androidx.camera:camera-view:${cameraxVersion}")
70 // If you want to additionally use the CameraX Extensions library
71 implementation("androidx.camera:camera-extensions:${cameraxVersion}")
72
73 // ZXing
74 implementation("com.google.zxing:core:3.5.0")
75
76 // Coil
LuK13375c420fa2022-10-10 13:22:45 +020077 implementation("io.coil-kt:coil:2.2.2")
78 implementation("io.coil-kt:coil-video:2.2.2")
LuK13379c4638c2022-09-05 13:37:03 +020079}
LuK133726b79022022-09-05 23:32:37 +020080
81tasks.register("generateBp") {
82 val project = project(":app")
83 val configuration = project.configurations["debugRuntimeClasspath"]
84
85 val libsBase = File("${project.projectDir.absolutePath}/libs")
86 libsBase.deleteRecursively()
87
88 val moduleString = { it: ModuleVersionIdentifier -> "${it.group}:${it.name}:${it.version}" }
89 val modulePath =
90 { it: ModuleVersionIdentifier -> "${it.group.replace(".", "/")}/${it.name}/${it.version}" }
91
92 val spaces = { it: Int ->
93 var ret = ""
94 for (i in it downTo 1) {
95 ret += ' '
96 }
97 ret
98 }
99
100 val moduleName = { it: Any ->
101 when (it) {
102 is ModuleVersionIdentifier -> {
103 "${rootProject.name}_${it.group}_${it.name}"
104 }
105 is String -> {
106 if (it.contains(":")) {
107 val (group, artifactId) = it.split(":")
108 "${rootProject.name}_${group}_${artifactId}"
109 } else {
110 "${rootProject.name}_${it}"
111 }
112 }
113 else -> {
114 throw Exception("Invalid `it` type")
115 }
116 }
117 }
118
119 val moduleNameAosp = { it: String ->
120 when (it) {
121 "androidx.constraintlayout:constraintlayout" -> "androidx-constraintlayout_constraintlayout"
122 "com.google.auto.value:auto-value-annotations" -> "auto_value_annotations"
123 "com.google.guava:listenablefuture" -> "guava"
124 "org.jetbrains.kotlin:kotlin-stdlib" -> "kotlin-stdlib"
125 "org.jetbrains.kotlin:kotlin-stdlib-jdk8" -> "kotlin-stdlib-jdk8"
126 "org.jetbrains.kotlinx:kotlinx-coroutines-android" -> "kotlinx-coroutines-android"
127 else -> it.replace(":", "_")
128 }
129 }
130
131 val isAvailableInAosp = { group: String, artifactId: String ->
132 when {
133 group.startsWith("androidx") -> {
134 // We provide our own androidx.camera & lifecycle-common
135 !group.startsWith("androidx.camera") && artifactId != "lifecycle-common"
136 }
LuK13375c420fa2022-10-10 13:22:45 +0200137 group.startsWith("org.jetbrains") -> true
LuK133726b79022022-09-05 23:32:37 +0200138 group == "com.google.auto.value" -> true
139 group == "com.google.guava" -> true
140 group == "junit" -> true
141 else -> false
142 }
143 }
144
145 // Update app/Android.bp
146 File("${project.projectDir.absolutePath}/Android.bp").let { file ->
147 // Read dependencies
148 val dependencies = "${spaces(8)}// DO NOT EDIT THIS SECTION MANUALLY\n".plus(
149 configuration.allDependencies.joinToString("\n") {
150 if (isAvailableInAosp(it.group!!, it.name)) {
151 "${spaces(8)}\"${moduleNameAosp("${it.group}:${it.name}")}\","
152 } else {
153 "${spaces(8)}\"${moduleName("${it.group}:${it.name}")}\","
154 }
155 }
156 )
157
158 // Replace existing dependencies with newly generated ones
159 file.writeText(
160 file.readText().replace(
161 "static_libs: \\[.*?\\]".toRegex(RegexOption.DOT_MATCHES_ALL),
162 "static_libs: [%s]".format("\n$dependencies\n${spaces(4)}")
163 )
164 )
165 }
166
167 // Update app/libs
168 configuration.resolvedConfiguration.resolvedArtifacts.sortedBy {
169 moduleString(it.moduleVersion.id)
170 }.distinctBy {
171 moduleString(it.moduleVersion.id)
172 }.forEach {
173 val id = it.moduleVersion.id
174
175 // Skip modules that are available in AOSP
176 if (isAvailableInAosp(id.group, it.name)) {
177 return@forEach
178 }
179
180 // Get file path
181 val dirPath = "${libsBase}/${modulePath(id)}"
182 val filePath = "${dirPath}/${it.file.name}"
183
184 // Copy artifact to app/libs
185 it.file.copyTo(File(filePath))
186
187 // Parse dependencies
188 val dependencies =
Sebastiano Barezzifa391d02022-10-31 14:36:20 +0100189 it.file.parentFile.parentFile.walk().filter { file -> file.extension == "pom" }
190 .map { file ->
LuK133726b79022022-09-05 23:32:37 +0200191 val ret = mutableListOf<String>()
192
193 val pom = XmlParser().parse(file)
194 val dependencies = (pom["dependencies"] as NodeList).firstOrNull() as Node?
195
196 dependencies?.children()?.forEach { node ->
197 val dependency = node as Node
198 ret.add(
199 "${
200 (dependency.get("groupId") as NodeList).text()
201 }:${
202 (dependency.get("artifactId") as NodeList).text()
203 }"
204 )
205 }
206
207 ret
Sebastiano Barezzifa391d02022-10-31 14:36:20 +0100208 }.flatten()
LuK133726b79022022-09-05 23:32:37 +0200209
LuK1337ba4d20f2022-09-06 20:24:53 +0200210 var targetSdkVersion = android.defaultConfig.minSdk
LuK133726b79022022-09-05 23:32:37 +0200211 var minSdkVersion = 14
212
213 // Extract AndroidManifest.xml for AARs
214 if (it.file.extension == "aar") {
215 copy {
216 from(zipTree(filePath).matching { include("/AndroidManifest.xml") }.singleFile)
217 into(dirPath)
218 }
219
220 val androidManifest = XmlParser().parse(File("${dirPath}/AndroidManifest.xml"))
221
222 val usesSdk = (androidManifest["uses-sdk"] as NodeList).first() as Node
223 targetSdkVersion = (usesSdk.get("@targetSdkVersion") as Int?) ?: targetSdkVersion
224 minSdkVersion = (usesSdk.get("@minSdkVersion") as Int?) ?: minSdkVersion
225 }
226
227 // Write Android.bp
228 File("$libsBase/Android.bp").let { file ->
229 // Add autogenerated header if file is empty
230 if (file.length() == 0L) {
231 file.writeText("// DO NOT EDIT THIS FILE MANUALLY")
232 }
233
234 val formatDeps = { addNoDeps: Boolean ->
235 val deps = dependencies.filter { dep ->
236 when {
237 configuration.resolvedConfiguration.resolvedArtifacts.firstOrNull { artifact ->
238 dep == "${artifact.moduleVersion.id.group}:${artifact.moduleVersion.id.name}"
239 } == null -> {
240 val moduleName = if (addNoDeps) {
241 moduleName(id)
242 } else {
243 "${moduleName(id)}-nodeps"
244 }
245 println("$moduleName: Skipping $dep because it's not in resolvedArtifacts")
246 false
247 }
248 dep == "org.jetbrains.kotlin:kotlin-stdlib-common" -> false
249 else -> true
250 }
LuK133726b79022022-09-05 23:32:37 +0200251 }.toMutableList()
252
253 if (addNoDeps) {
254 // Add -nodeps dependency for android_library/java_library_static
255 deps.add(0, "${id.group}_${id.name}-nodeps")
256 }
257
258 var ret = ""
259
260 if (deps.isNotEmpty()) {
261 deps.forEach { dep ->
262 ret += if (dep.contains(":")) {
263 val (group, artifactId) = dep.split(":")
264 if (isAvailableInAosp(group, artifactId)) {
265 "\n${spaces(8)}\"${moduleNameAosp(dep)}\","
266 } else {
267 "\n${spaces(8)}\"${moduleName(dep)}\","
268 }
269 } else {
270 "\n${spaces(8)}\"${moduleName(dep)}\","
271 }
272 }
273 ret += "\n${spaces(4)}"
274 }
275
276 ret
277 }
278
279 when (it.extension) {
280 "aar" -> {
281 file.appendText(
282 """
283
284 android_library_import {
285 name: "${moduleName(id)}-nodeps",
286 aars: ["${modulePath(id)}/${it.file.name}"],
287 sdk_version: "$targetSdkVersion",
288 min_sdk_version: "$minSdkVersion",
289 apex_available: [
290 "//apex_available:platform",
291 "//apex_available:anyapex",
292 ],
293 static_libs: [%s],
294 }
295
296 android_library {
297 name: "${moduleName(id)}",
298 sdk_version: "$targetSdkVersion",
299 min_sdk_version: "$minSdkVersion",
300 apex_available: [
301 "//apex_available:platform",
302 "//apex_available:anyapex",
303 ],
304 manifest: "${modulePath(id)}/AndroidManifest.xml",
305 static_libs: [%s],
306 java_version: "1.7",
307 }
308
309 """.trimIndent().format(formatDeps(false), formatDeps(true))
310 )
311 }
312 "jar" -> {
313 file.appendText(
314 """
315
316 java_import {
317 name: "${moduleName(id)}-nodeps",
318 jars: ["${modulePath(id)}/${it.file.name}"],
319 sdk_version: "$targetSdkVersion",
320 min_sdk_version: "$minSdkVersion",
321 apex_available: [
322 "//apex_available:platform",
323 "//apex_available:anyapex",
324 ],
325 }
326
327 java_library_static {
328 name: "${moduleName(id)}",
329 sdk_version: "$targetSdkVersion",
330 min_sdk_version: "$minSdkVersion",
331 apex_available: [
332 "//apex_available:platform",
333 "//apex_available:anyapex",
334 ],
335 static_libs: [%s],
336 java_version: "1.7",
337 }
338
339 """.trimIndent().format(formatDeps(true))
340 )
341 }
342 else -> throw Exception("Unknown file extension: ${it.extension}")
343 }
344 }
345 }
346}