blob: 42832d0279fb381174699516c75f09378c5700c4 [file] [log] [blame]
Michael Bestasdd2506a2023-07-20 20:53:02 +03001/*
2 * SPDX-FileCopyrightText: 2022-2023 The LineageOS Project
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
LuK133726b79022022-09-05 23:32:37 +02006import groovy.util.Node
7import groovy.util.NodeList
8import groovy.xml.XmlParser
9
LuK13379c4638c2022-09-05 13:37:03 +020010plugins {
11 id("com.android.application")
12 id("kotlin-android")
13}
14
15android {
16 compileSdk = 33
17
18 defaultConfig {
Sebastiano Barezzif5a9a782022-11-07 01:06:37 +010019 applicationId = "org.lineageos.aperture"
Sebastiano Barezzid11139c2022-10-30 16:37:13 +010020 minSdk = 26
LuK13379c4638c2022-09-05 13:37:03 +020021 targetSdk = 33
22 versionCode = 1
23 versionName = "1.0"
LuK13379c4638c2022-09-05 13:37:03 +020024 }
25
26 buildTypes {
Sebastiano Barezzif0b46402022-11-07 01:05:51 +010027 getByName("release") {
LuK13379c4638c2022-09-05 13:37:03 +020028 // Enables code shrinking, obfuscation, and optimization.
29 isMinifyEnabled = true
30
31 // Enables resource shrinking.
32 isShrinkResources = true
33
34 // Includes the default ProGuard rules files.
35 setProguardFiles(
36 listOf(
37 getDefaultProguardFile("proguard-android-optimize.txt"),
38 "proguard-rules.pro"
39 )
40 )
41 }
Sebastiano Barezzif5a9a782022-11-07 01:06:37 +010042 getByName("debug") {
43 // Append .dev to package name so we won't conflict with AOSP build.
44 applicationIdSuffix = ".dev"
45 }
LuK13379c4638c2022-09-05 13:37:03 +020046 }
47
48 compileOptions {
49 sourceCompatibility = JavaVersion.VERSION_1_8
50 targetCompatibility = JavaVersion.VERSION_1_8
51 }
52
53 kotlinOptions {
54 jvmTarget = "1.8"
55 }
56}
57
58dependencies {
LuK133700ac9b12023-01-25 20:14:54 +010059 // Align versions of all Kotlin components
60 implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
61
LuK13374ca40602023-05-24 20:34:45 +020062 implementation("androidx.core:core-ktx:1.10.1")
Sebastiano Barezzi1a512eb2023-06-22 23:20:38 +020063 implementation("androidx.activity:activity-ktx:1.7.2")
LuK13376d39d8a2023-02-22 20:30:20 +010064 implementation("androidx.appcompat:appcompat:1.6.1")
LuK13379c4638c2022-09-05 13:37:03 +020065 implementation("androidx.constraintlayout:constraintlayout:2.1.4")
Tommy Webb636f2252023-01-27 13:33:42 -050066 implementation("androidx.exifinterface:exifinterface:1.3.6")
LuK13374ca40602023-05-24 20:34:45 +020067 implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
LuK1337afc94a32022-09-05 23:30:33 +020068 implementation("androidx.preference:preference:1.2.0")
LuK1337bc3d67a2023-06-04 19:54:31 +020069 implementation("com.google.android.material:material:1.9.0")
LuK13379c4638c2022-09-05 13:37:03 +020070
71 // CameraX core library using the camera2 implementation
LuK1337c9be1842023-07-27 15:07:40 +020072 val cameraxVersion = "1.3.0-beta02"
LuK13379c4638c2022-09-05 13:37:03 +020073 // The following line is optional, as the core library is included indirectly by camera-camera2
74 implementation("androidx.camera:camera-core:${cameraxVersion}")
75 implementation("androidx.camera:camera-camera2:${cameraxVersion}")
76 // If you want to additionally use the CameraX Lifecycle library
77 implementation("androidx.camera:camera-lifecycle:${cameraxVersion}")
78 // If you want to additionally use the CameraX VideoCapture library
79 implementation("androidx.camera:camera-video:${cameraxVersion}")
80 // If you want to additionally use the CameraX View class
81 implementation("androidx.camera:camera-view:${cameraxVersion}")
82 // If you want to additionally use the CameraX Extensions library
83 implementation("androidx.camera:camera-extensions:${cameraxVersion}")
84
Sebastiano Barezzi6b71eb52022-11-10 00:05:27 +010085 // Media3
Sebastiano Barezzideb87662023-08-24 14:40:48 +020086 val media3Version = "1.1.1"
Sebastiano Barezzi6b71eb52022-11-10 00:05:27 +010087 // For media playback using ExoPlayer
88 implementation("androidx.media3:media3-exoplayer:$media3Version")
89 // For building media playback UIs
90 implementation("androidx.media3:media3-ui:$media3Version")
91
LuK13379c4638c2022-09-05 13:37:03 +020092 // ZXing
93 implementation("com.google.zxing:core:3.5.0")
94
95 // Coil
LuK13375c420fa2022-10-10 13:22:45 +020096 implementation("io.coil-kt:coil:2.2.2")
97 implementation("io.coil-kt:coil-video:2.2.2")
LuK13379c4638c2022-09-05 13:37:03 +020098}
LuK133726b79022022-09-05 23:32:37 +020099
100tasks.register("generateBp") {
101 val project = project(":app")
102 val configuration = project.configurations["debugRuntimeClasspath"]
103
104 val libsBase = File("${project.projectDir.absolutePath}/libs")
105 libsBase.deleteRecursively()
106
107 val moduleString = { it: ModuleVersionIdentifier -> "${it.group}:${it.name}:${it.version}" }
108 val modulePath =
109 { it: ModuleVersionIdentifier -> "${it.group.replace(".", "/")}/${it.name}/${it.version}" }
110
111 val spaces = { it: Int ->
112 var ret = ""
113 for (i in it downTo 1) {
114 ret += ' '
115 }
116 ret
117 }
118
119 val moduleName = { it: Any ->
120 when (it) {
121 is ModuleVersionIdentifier -> {
122 "${rootProject.name}_${it.group}_${it.name}"
123 }
124 is String -> {
125 if (it.contains(":")) {
126 val (group, artifactId) = it.split(":")
127 "${rootProject.name}_${group}_${artifactId}"
128 } else {
129 "${rootProject.name}_${it}"
130 }
131 }
132 else -> {
133 throw Exception("Invalid `it` type")
134 }
135 }
136 }
137
138 val moduleNameAosp = { it: String ->
139 when (it) {
140 "androidx.constraintlayout:constraintlayout" -> "androidx-constraintlayout_constraintlayout"
141 "com.google.auto.value:auto-value-annotations" -> "auto_value_annotations"
Sebastiano Barezzi6b71eb52022-11-10 00:05:27 +0100142 "com.google.guava:guava" -> "guava"
LuK133726b79022022-09-05 23:32:37 +0200143 "com.google.guava:listenablefuture" -> "guava"
144 "org.jetbrains.kotlin:kotlin-stdlib" -> "kotlin-stdlib"
145 "org.jetbrains.kotlin:kotlin-stdlib-jdk8" -> "kotlin-stdlib-jdk8"
146 "org.jetbrains.kotlinx:kotlinx-coroutines-android" -> "kotlinx-coroutines-android"
147 else -> it.replace(":", "_")
148 }
149 }
150
151 val isAvailableInAosp = { group: String, artifactId: String ->
152 when {
153 group.startsWith("androidx") -> {
Sebastiano Barezzi6b71eb52022-11-10 00:05:27 +0100154 // We provide our own androidx.{camera,media3} & lifecycle-common
155 !group.startsWith("androidx.camera") &&
156 !group.startsWith("androidx.media3") &&
157 artifactId != "lifecycle-common"
LuK133726b79022022-09-05 23:32:37 +0200158 }
LuK13375c420fa2022-10-10 13:22:45 +0200159 group.startsWith("org.jetbrains") -> true
LuK133726b79022022-09-05 23:32:37 +0200160 group == "com.google.auto.value" -> true
161 group == "com.google.guava" -> true
162 group == "junit" -> true
163 else -> false
164 }
165 }
166
167 // Update app/Android.bp
168 File("${project.projectDir.absolutePath}/Android.bp").let { file ->
169 // Read dependencies
170 val dependencies = "${spaces(8)}// DO NOT EDIT THIS SECTION MANUALLY\n".plus(
LuK133700ac9b12023-01-25 20:14:54 +0100171 configuration.allDependencies.filter {
172 // kotlin-bom does not need to be added to dependencies
173 it.group != "org.jetbrains.kotlin" && it.name != "kotlin-bom"
174 }.joinToString("\n") {
LuK133726b79022022-09-05 23:32:37 +0200175 if (isAvailableInAosp(it.group!!, it.name)) {
176 "${spaces(8)}\"${moduleNameAosp("${it.group}:${it.name}")}\","
177 } else {
178 "${spaces(8)}\"${moduleName("${it.group}:${it.name}")}\","
179 }
180 }
181 )
182
183 // Replace existing dependencies with newly generated ones
184 file.writeText(
185 file.readText().replace(
186 "static_libs: \\[.*?\\]".toRegex(RegexOption.DOT_MATCHES_ALL),
187 "static_libs: [%s]".format("\n$dependencies\n${spaces(4)}")
188 )
189 )
190 }
191
192 // Update app/libs
193 configuration.resolvedConfiguration.resolvedArtifacts.sortedBy {
194 moduleString(it.moduleVersion.id)
195 }.distinctBy {
196 moduleString(it.moduleVersion.id)
197 }.forEach {
198 val id = it.moduleVersion.id
199
200 // Skip modules that are available in AOSP
201 if (isAvailableInAosp(id.group, it.name)) {
202 return@forEach
203 }
204
205 // Get file path
206 val dirPath = "${libsBase}/${modulePath(id)}"
207 val filePath = "${dirPath}/${it.file.name}"
208
209 // Copy artifact to app/libs
210 it.file.copyTo(File(filePath))
211
212 // Parse dependencies
213 val dependencies =
Sebastiano Barezzifa391d02022-10-31 14:36:20 +0100214 it.file.parentFile.parentFile.walk().filter { file -> file.extension == "pom" }
215 .map { file ->
LuK133726b79022022-09-05 23:32:37 +0200216 val ret = mutableListOf<String>()
217
218 val pom = XmlParser().parse(file)
219 val dependencies = (pom["dependencies"] as NodeList).firstOrNull() as Node?
220
221 dependencies?.children()?.forEach { node ->
222 val dependency = node as Node
223 ret.add(
224 "${
225 (dependency.get("groupId") as NodeList).text()
226 }:${
227 (dependency.get("artifactId") as NodeList).text()
228 }"
229 )
230 }
231
232 ret
Sebastiano Barezzifa391d02022-10-31 14:36:20 +0100233 }.flatten()
LuK133726b79022022-09-05 23:32:37 +0200234
LuK13376c560fa2022-10-31 22:40:11 +0100235 var targetSdkVersion = android.defaultConfig.targetSdk
LuK133726b79022022-09-05 23:32:37 +0200236 var minSdkVersion = 14
237
238 // Extract AndroidManifest.xml for AARs
239 if (it.file.extension == "aar") {
240 copy {
241 from(zipTree(filePath).matching { include("/AndroidManifest.xml") }.singleFile)
242 into(dirPath)
243 }
244
245 val androidManifest = XmlParser().parse(File("${dirPath}/AndroidManifest.xml"))
246
247 val usesSdk = (androidManifest["uses-sdk"] as NodeList).first() as Node
248 targetSdkVersion = (usesSdk.get("@targetSdkVersion") as Int?) ?: targetSdkVersion
249 minSdkVersion = (usesSdk.get("@minSdkVersion") as Int?) ?: minSdkVersion
250 }
251
252 // Write Android.bp
253 File("$libsBase/Android.bp").let { file ->
254 // Add autogenerated header if file is empty
255 if (file.length() == 0L) {
256 file.writeText("// DO NOT EDIT THIS FILE MANUALLY")
257 }
258
259 val formatDeps = { addNoDeps: Boolean ->
260 val deps = dependencies.filter { dep ->
261 when {
262 configuration.resolvedConfiguration.resolvedArtifacts.firstOrNull { artifact ->
263 dep == "${artifact.moduleVersion.id.group}:${artifact.moduleVersion.id.name}"
264 } == null -> {
265 val moduleName = if (addNoDeps) {
266 moduleName(id)
267 } else {
268 "${moduleName(id)}-nodeps"
269 }
270 println("$moduleName: Skipping $dep because it's not in resolvedArtifacts")
271 false
272 }
273 dep == "org.jetbrains.kotlin:kotlin-stdlib-common" -> false
274 else -> true
275 }
LuK133747cafc32023-01-25 23:20:18 +0100276 }.distinct().toMutableList()
LuK133726b79022022-09-05 23:32:37 +0200277
278 if (addNoDeps) {
279 // Add -nodeps dependency for android_library/java_library_static
280 deps.add(0, "${id.group}_${id.name}-nodeps")
281 }
282
283 var ret = ""
284
285 if (deps.isNotEmpty()) {
286 deps.forEach { dep ->
287 ret += if (dep.contains(":")) {
288 val (group, artifactId) = dep.split(":")
289 if (isAvailableInAosp(group, artifactId)) {
290 "\n${spaces(8)}\"${moduleNameAosp(dep)}\","
291 } else {
292 "\n${spaces(8)}\"${moduleName(dep)}\","
293 }
294 } else {
295 "\n${spaces(8)}\"${moduleName(dep)}\","
296 }
297 }
298 ret += "\n${spaces(4)}"
299 }
300
301 ret
302 }
303
304 when (it.extension) {
305 "aar" -> {
306 file.appendText(
307 """
308
309 android_library_import {
310 name: "${moduleName(id)}-nodeps",
311 aars: ["${modulePath(id)}/${it.file.name}"],
312 sdk_version: "$targetSdkVersion",
313 min_sdk_version: "$minSdkVersion",
314 apex_available: [
315 "//apex_available:platform",
316 "//apex_available:anyapex",
317 ],
318 static_libs: [%s],
319 }
320
321 android_library {
322 name: "${moduleName(id)}",
323 sdk_version: "$targetSdkVersion",
324 min_sdk_version: "$minSdkVersion",
325 apex_available: [
326 "//apex_available:platform",
327 "//apex_available:anyapex",
328 ],
329 manifest: "${modulePath(id)}/AndroidManifest.xml",
330 static_libs: [%s],
331 java_version: "1.7",
332 }
333
334 """.trimIndent().format(formatDeps(false), formatDeps(true))
335 )
336 }
337 "jar" -> {
338 file.appendText(
339 """
340
341 java_import {
342 name: "${moduleName(id)}-nodeps",
343 jars: ["${modulePath(id)}/${it.file.name}"],
344 sdk_version: "$targetSdkVersion",
345 min_sdk_version: "$minSdkVersion",
346 apex_available: [
347 "//apex_available:platform",
348 "//apex_available:anyapex",
349 ],
350 }
351
352 java_library_static {
353 name: "${moduleName(id)}",
354 sdk_version: "$targetSdkVersion",
355 min_sdk_version: "$minSdkVersion",
356 apex_available: [
357 "//apex_available:platform",
358 "//apex_available:anyapex",
359 ],
360 static_libs: [%s],
361 java_version: "1.7",
362 }
363
364 """.trimIndent().format(formatDeps(true))
365 )
366 }
367 else -> throw Exception("Unknown file extension: ${it.extension}")
368 }
369 }
370 }
371}