blob: 21b865c13e3b2993fa80ad5620575dcabccdd80d [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 {
Sebastiano Barezzif5a9a782022-11-07 01:06:37 +010014 applicationId = "org.lineageos.aperture"
Sebastiano Barezzid11139c2022-10-30 16:37:13 +010015 minSdk = 26
LuK13379c4638c2022-09-05 13:37:03 +020016 targetSdk = 33
17 versionCode = 1
18 versionName = "1.0"
LuK13379c4638c2022-09-05 13:37:03 +020019 }
20
21 buildTypes {
Sebastiano Barezzif0b46402022-11-07 01:05:51 +010022 getByName("release") {
LuK13379c4638c2022-09-05 13:37:03 +020023 // Enables code shrinking, obfuscation, and optimization.
24 isMinifyEnabled = true
25
26 // Enables resource shrinking.
27 isShrinkResources = true
28
29 // Includes the default ProGuard rules files.
30 setProguardFiles(
31 listOf(
32 getDefaultProguardFile("proguard-android-optimize.txt"),
33 "proguard-rules.pro"
34 )
35 )
36 }
Sebastiano Barezzif5a9a782022-11-07 01:06:37 +010037 getByName("debug") {
38 // Append .dev to package name so we won't conflict with AOSP build.
39 applicationIdSuffix = ".dev"
40 }
LuK13379c4638c2022-09-05 13:37:03 +020041 }
42
43 compileOptions {
44 sourceCompatibility = JavaVersion.VERSION_1_8
45 targetCompatibility = JavaVersion.VERSION_1_8
46 }
47
48 kotlinOptions {
49 jvmTarget = "1.8"
50 }
51}
52
53dependencies {
LuK133700ac9b12023-01-25 20:14:54 +010054 // Align versions of all Kotlin components
55 implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
56
LuK13374ca40602023-05-24 20:34:45 +020057 implementation("androidx.core:core-ktx:1.10.1")
LuK13376d39d8a2023-02-22 20:30:20 +010058 implementation("androidx.appcompat:appcompat:1.6.1")
LuK13379c4638c2022-09-05 13:37:03 +020059 implementation("androidx.constraintlayout:constraintlayout:2.1.4")
Tommy Webb636f2252023-01-27 13:33:42 -050060 implementation("androidx.exifinterface:exifinterface:1.3.6")
LuK13374ca40602023-05-24 20:34:45 +020061 implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
LuK1337afc94a32022-09-05 23:30:33 +020062 implementation("androidx.preference:preference:1.2.0")
LuK1337bc3d67a2023-06-04 19:54:31 +020063 implementation("com.google.android.material:material:1.9.0")
LuK13379c4638c2022-09-05 13:37:03 +020064
65 // CameraX core library using the camera2 implementation
LuK13375f4883a2023-06-21 21:21:23 +020066 val cameraxVersion = "1.3.0-beta01"
LuK13379c4638c2022-09-05 13:37:03 +020067 // The following line is optional, as the core library is included indirectly by camera-camera2
68 implementation("androidx.camera:camera-core:${cameraxVersion}")
69 implementation("androidx.camera:camera-camera2:${cameraxVersion}")
70 // If you want to additionally use the CameraX Lifecycle library
71 implementation("androidx.camera:camera-lifecycle:${cameraxVersion}")
72 // If you want to additionally use the CameraX VideoCapture library
73 implementation("androidx.camera:camera-video:${cameraxVersion}")
74 // If you want to additionally use the CameraX View class
75 implementation("androidx.camera:camera-view:${cameraxVersion}")
76 // If you want to additionally use the CameraX Extensions library
77 implementation("androidx.camera:camera-extensions:${cameraxVersion}")
78
Sebastiano Barezzi6b71eb52022-11-10 00:05:27 +010079 // Media3
LuK13374ca40602023-05-24 20:34:45 +020080 val media3Version = "1.0.2"
Sebastiano Barezzi6b71eb52022-11-10 00:05:27 +010081 // For media playback using ExoPlayer
82 implementation("androidx.media3:media3-exoplayer:$media3Version")
83 // For building media playback UIs
84 implementation("androidx.media3:media3-ui:$media3Version")
85
LuK13379c4638c2022-09-05 13:37:03 +020086 // ZXing
87 implementation("com.google.zxing:core:3.5.0")
88
89 // Coil
LuK13375c420fa2022-10-10 13:22:45 +020090 implementation("io.coil-kt:coil:2.2.2")
91 implementation("io.coil-kt:coil-video:2.2.2")
LuK13379c4638c2022-09-05 13:37:03 +020092}
LuK133726b79022022-09-05 23:32:37 +020093
94tasks.register("generateBp") {
95 val project = project(":app")
96 val configuration = project.configurations["debugRuntimeClasspath"]
97
98 val libsBase = File("${project.projectDir.absolutePath}/libs")
99 libsBase.deleteRecursively()
100
101 val moduleString = { it: ModuleVersionIdentifier -> "${it.group}:${it.name}:${it.version}" }
102 val modulePath =
103 { it: ModuleVersionIdentifier -> "${it.group.replace(".", "/")}/${it.name}/${it.version}" }
104
105 val spaces = { it: Int ->
106 var ret = ""
107 for (i in it downTo 1) {
108 ret += ' '
109 }
110 ret
111 }
112
113 val moduleName = { it: Any ->
114 when (it) {
115 is ModuleVersionIdentifier -> {
116 "${rootProject.name}_${it.group}_${it.name}"
117 }
118 is String -> {
119 if (it.contains(":")) {
120 val (group, artifactId) = it.split(":")
121 "${rootProject.name}_${group}_${artifactId}"
122 } else {
123 "${rootProject.name}_${it}"
124 }
125 }
126 else -> {
127 throw Exception("Invalid `it` type")
128 }
129 }
130 }
131
132 val moduleNameAosp = { it: String ->
133 when (it) {
134 "androidx.constraintlayout:constraintlayout" -> "androidx-constraintlayout_constraintlayout"
135 "com.google.auto.value:auto-value-annotations" -> "auto_value_annotations"
Sebastiano Barezzi6b71eb52022-11-10 00:05:27 +0100136 "com.google.guava:guava" -> "guava"
LuK133726b79022022-09-05 23:32:37 +0200137 "com.google.guava:listenablefuture" -> "guava"
138 "org.jetbrains.kotlin:kotlin-stdlib" -> "kotlin-stdlib"
139 "org.jetbrains.kotlin:kotlin-stdlib-jdk8" -> "kotlin-stdlib-jdk8"
140 "org.jetbrains.kotlinx:kotlinx-coroutines-android" -> "kotlinx-coroutines-android"
141 else -> it.replace(":", "_")
142 }
143 }
144
145 val isAvailableInAosp = { group: String, artifactId: String ->
146 when {
147 group.startsWith("androidx") -> {
Sebastiano Barezzi6b71eb52022-11-10 00:05:27 +0100148 // We provide our own androidx.{camera,media3} & lifecycle-common
149 !group.startsWith("androidx.camera") &&
150 !group.startsWith("androidx.media3") &&
151 artifactId != "lifecycle-common"
LuK133726b79022022-09-05 23:32:37 +0200152 }
LuK13375c420fa2022-10-10 13:22:45 +0200153 group.startsWith("org.jetbrains") -> true
LuK133726b79022022-09-05 23:32:37 +0200154 group == "com.google.auto.value" -> true
155 group == "com.google.guava" -> true
156 group == "junit" -> true
157 else -> false
158 }
159 }
160
161 // Update app/Android.bp
162 File("${project.projectDir.absolutePath}/Android.bp").let { file ->
163 // Read dependencies
164 val dependencies = "${spaces(8)}// DO NOT EDIT THIS SECTION MANUALLY\n".plus(
LuK133700ac9b12023-01-25 20:14:54 +0100165 configuration.allDependencies.filter {
166 // kotlin-bom does not need to be added to dependencies
167 it.group != "org.jetbrains.kotlin" && it.name != "kotlin-bom"
168 }.joinToString("\n") {
LuK133726b79022022-09-05 23:32:37 +0200169 if (isAvailableInAosp(it.group!!, it.name)) {
170 "${spaces(8)}\"${moduleNameAosp("${it.group}:${it.name}")}\","
171 } else {
172 "${spaces(8)}\"${moduleName("${it.group}:${it.name}")}\","
173 }
174 }
175 )
176
177 // Replace existing dependencies with newly generated ones
178 file.writeText(
179 file.readText().replace(
180 "static_libs: \\[.*?\\]".toRegex(RegexOption.DOT_MATCHES_ALL),
181 "static_libs: [%s]".format("\n$dependencies\n${spaces(4)}")
182 )
183 )
184 }
185
186 // Update app/libs
187 configuration.resolvedConfiguration.resolvedArtifacts.sortedBy {
188 moduleString(it.moduleVersion.id)
189 }.distinctBy {
190 moduleString(it.moduleVersion.id)
191 }.forEach {
192 val id = it.moduleVersion.id
193
194 // Skip modules that are available in AOSP
195 if (isAvailableInAosp(id.group, it.name)) {
196 return@forEach
197 }
198
199 // Get file path
200 val dirPath = "${libsBase}/${modulePath(id)}"
201 val filePath = "${dirPath}/${it.file.name}"
202
203 // Copy artifact to app/libs
204 it.file.copyTo(File(filePath))
205
206 // Parse dependencies
207 val dependencies =
Sebastiano Barezzifa391d02022-10-31 14:36:20 +0100208 it.file.parentFile.parentFile.walk().filter { file -> file.extension == "pom" }
209 .map { file ->
LuK133726b79022022-09-05 23:32:37 +0200210 val ret = mutableListOf<String>()
211
212 val pom = XmlParser().parse(file)
213 val dependencies = (pom["dependencies"] as NodeList).firstOrNull() as Node?
214
215 dependencies?.children()?.forEach { node ->
216 val dependency = node as Node
217 ret.add(
218 "${
219 (dependency.get("groupId") as NodeList).text()
220 }:${
221 (dependency.get("artifactId") as NodeList).text()
222 }"
223 )
224 }
225
226 ret
Sebastiano Barezzifa391d02022-10-31 14:36:20 +0100227 }.flatten()
LuK133726b79022022-09-05 23:32:37 +0200228
LuK13376c560fa2022-10-31 22:40:11 +0100229 var targetSdkVersion = android.defaultConfig.targetSdk
LuK133726b79022022-09-05 23:32:37 +0200230 var minSdkVersion = 14
231
232 // Extract AndroidManifest.xml for AARs
233 if (it.file.extension == "aar") {
234 copy {
235 from(zipTree(filePath).matching { include("/AndroidManifest.xml") }.singleFile)
236 into(dirPath)
237 }
238
239 val androidManifest = XmlParser().parse(File("${dirPath}/AndroidManifest.xml"))
240
241 val usesSdk = (androidManifest["uses-sdk"] as NodeList).first() as Node
242 targetSdkVersion = (usesSdk.get("@targetSdkVersion") as Int?) ?: targetSdkVersion
243 minSdkVersion = (usesSdk.get("@minSdkVersion") as Int?) ?: minSdkVersion
244 }
245
246 // Write Android.bp
247 File("$libsBase/Android.bp").let { file ->
248 // Add autogenerated header if file is empty
249 if (file.length() == 0L) {
250 file.writeText("// DO NOT EDIT THIS FILE MANUALLY")
251 }
252
253 val formatDeps = { addNoDeps: Boolean ->
254 val deps = dependencies.filter { dep ->
255 when {
256 configuration.resolvedConfiguration.resolvedArtifacts.firstOrNull { artifact ->
257 dep == "${artifact.moduleVersion.id.group}:${artifact.moduleVersion.id.name}"
258 } == null -> {
259 val moduleName = if (addNoDeps) {
260 moduleName(id)
261 } else {
262 "${moduleName(id)}-nodeps"
263 }
264 println("$moduleName: Skipping $dep because it's not in resolvedArtifacts")
265 false
266 }
267 dep == "org.jetbrains.kotlin:kotlin-stdlib-common" -> false
268 else -> true
269 }
LuK133747cafc32023-01-25 23:20:18 +0100270 }.distinct().toMutableList()
LuK133726b79022022-09-05 23:32:37 +0200271
272 if (addNoDeps) {
273 // Add -nodeps dependency for android_library/java_library_static
274 deps.add(0, "${id.group}_${id.name}-nodeps")
275 }
276
277 var ret = ""
278
279 if (deps.isNotEmpty()) {
280 deps.forEach { dep ->
281 ret += if (dep.contains(":")) {
282 val (group, artifactId) = dep.split(":")
283 if (isAvailableInAosp(group, artifactId)) {
284 "\n${spaces(8)}\"${moduleNameAosp(dep)}\","
285 } else {
286 "\n${spaces(8)}\"${moduleName(dep)}\","
287 }
288 } else {
289 "\n${spaces(8)}\"${moduleName(dep)}\","
290 }
291 }
292 ret += "\n${spaces(4)}"
293 }
294
295 ret
296 }
297
298 when (it.extension) {
299 "aar" -> {
300 file.appendText(
301 """
302
303 android_library_import {
304 name: "${moduleName(id)}-nodeps",
305 aars: ["${modulePath(id)}/${it.file.name}"],
306 sdk_version: "$targetSdkVersion",
307 min_sdk_version: "$minSdkVersion",
308 apex_available: [
309 "//apex_available:platform",
310 "//apex_available:anyapex",
311 ],
312 static_libs: [%s],
313 }
314
315 android_library {
316 name: "${moduleName(id)}",
317 sdk_version: "$targetSdkVersion",
318 min_sdk_version: "$minSdkVersion",
319 apex_available: [
320 "//apex_available:platform",
321 "//apex_available:anyapex",
322 ],
323 manifest: "${modulePath(id)}/AndroidManifest.xml",
324 static_libs: [%s],
325 java_version: "1.7",
326 }
327
328 """.trimIndent().format(formatDeps(false), formatDeps(true))
329 )
330 }
331 "jar" -> {
332 file.appendText(
333 """
334
335 java_import {
336 name: "${moduleName(id)}-nodeps",
337 jars: ["${modulePath(id)}/${it.file.name}"],
338 sdk_version: "$targetSdkVersion",
339 min_sdk_version: "$minSdkVersion",
340 apex_available: [
341 "//apex_available:platform",
342 "//apex_available:anyapex",
343 ],
344 }
345
346 java_library_static {
347 name: "${moduleName(id)}",
348 sdk_version: "$targetSdkVersion",
349 min_sdk_version: "$minSdkVersion",
350 apex_available: [
351 "//apex_available:platform",
352 "//apex_available:anyapex",
353 ],
354 static_libs: [%s],
355 java_version: "1.7",
356 }
357
358 """.trimIndent().format(formatDeps(true))
359 )
360 }
361 else -> throw Exception("Unknown file extension: ${it.extension}")
362 }
363 }
364 }
365}