359 lines
13 KiB
Plaintext
359 lines
13 KiB
Plaintext
/*
|
|
* SPDX-FileCopyrightText: 2023 The LineageOS Project
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import groovy.util.Node
|
|
import groovy.util.NodeList
|
|
import groovy.xml.XmlParser
|
|
|
|
plugins {
|
|
id("com.android.application")
|
|
id("kotlin-android")
|
|
}
|
|
|
|
android {
|
|
compileSdk = 33
|
|
|
|
defaultConfig {
|
|
applicationId = "org.lineageos.glimpse"
|
|
minSdk = 26
|
|
targetSdk = 33
|
|
versionCode = 1
|
|
versionName = "1.0"
|
|
}
|
|
|
|
buildTypes {
|
|
getByName("release") {
|
|
// Enables code shrinking, obfuscation, and optimization.
|
|
isMinifyEnabled = true
|
|
|
|
// Enables resource shrinking.
|
|
isShrinkResources = true
|
|
|
|
// Includes the default ProGuard rules files.
|
|
setProguardFiles(
|
|
listOf(
|
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
"proguard-rules.pro"
|
|
)
|
|
)
|
|
}
|
|
getByName("debug") {
|
|
// Append .dev to package name so we won't conflict with AOSP build.
|
|
applicationIdSuffix = ".dev"
|
|
}
|
|
}
|
|
|
|
compileOptions {
|
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
|
targetCompatibility = JavaVersion.VERSION_1_8
|
|
}
|
|
|
|
kotlinOptions {
|
|
jvmTarget = "1.8"
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
// Align versions of all Kotlin components
|
|
implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
|
|
|
|
implementation("androidx.core:core-ktx:1.10.1")
|
|
implementation("androidx.appcompat:appcompat:1.6.1")
|
|
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
|
implementation("com.google.android.material:material:1.9.0")
|
|
|
|
// Media3
|
|
implementation("androidx.media3:media3-exoplayer:1.1.0")
|
|
implementation("androidx.media3:media3-ui:1.1.0")
|
|
|
|
// Navigation
|
|
implementation("androidx.navigation:navigation-fragment-ktx:2.6.0")
|
|
implementation("androidx.navigation:navigation-ui-ktx:2.6.0")
|
|
|
|
// Coil
|
|
implementation("io.coil-kt:coil:2.2.2")
|
|
implementation("io.coil-kt:coil-gif:2.2.2")
|
|
implementation("io.coil-kt:coil-video:2.2.2")
|
|
}
|
|
|
|
tasks.register("generateBp") {
|
|
val project = project(":app")
|
|
val configuration = project.configurations["debugRuntimeClasspath"]
|
|
|
|
val libsBase = File("${project.projectDir.absolutePath}/libs")
|
|
libsBase.deleteRecursively()
|
|
|
|
val moduleString = { it: ModuleVersionIdentifier -> "${it.group}:${it.name}:${it.version}" }
|
|
val modulePath =
|
|
{ it: ModuleVersionIdentifier -> "${it.group.replace(".", "/")}/${it.name}/${it.version}" }
|
|
|
|
val spaces = { it: Int ->
|
|
var ret = ""
|
|
for (i in it downTo 1) {
|
|
ret += ' '
|
|
}
|
|
ret
|
|
}
|
|
|
|
val moduleName = { it: Any ->
|
|
when (it) {
|
|
is ModuleVersionIdentifier -> {
|
|
"${rootProject.name}_${it.group}_${it.name}"
|
|
}
|
|
|
|
is String -> {
|
|
if (it.contains(":")) {
|
|
val (group, artifactId) = it.split(":")
|
|
"${rootProject.name}_${group}_${artifactId}"
|
|
} else {
|
|
"${rootProject.name}_${it}"
|
|
}
|
|
}
|
|
|
|
else -> {
|
|
throw Exception("Invalid `it` type")
|
|
}
|
|
}
|
|
}
|
|
|
|
val moduleNameAosp = { it: String ->
|
|
when (it) {
|
|
"androidx.constraintlayout:constraintlayout" -> "androidx-constraintlayout_constraintlayout"
|
|
"com.google.auto.value:auto-value-annotations" -> "auto_value_annotations"
|
|
"com.google.guava:guava" -> "guava"
|
|
"com.google.guava:listenablefuture" -> "guava"
|
|
"org.jetbrains.kotlin:kotlin-stdlib" -> "kotlin-stdlib"
|
|
"org.jetbrains.kotlin:kotlin-stdlib-jdk8" -> "kotlin-stdlib-jdk8"
|
|
"org.jetbrains.kotlinx:kotlinx-coroutines-android" -> "kotlinx-coroutines-android"
|
|
else -> it.replace(":", "_")
|
|
}
|
|
}
|
|
|
|
val isAvailableInAosp = { group: String, artifactId: String ->
|
|
when {
|
|
group.startsWith("androidx") -> {
|
|
// We provide our own androidx.{media3,multidex} & lifecycle-common
|
|
!group.startsWith("androidx.media3") &&
|
|
!group.startsWith("androidx.multidex") &&
|
|
artifactId != "lifecycle-common"
|
|
}
|
|
|
|
group.startsWith("org.jetbrains") -> true
|
|
group == "com.google.auto.value" -> true
|
|
group == "com.google.guava" -> true
|
|
group == "junit" -> true
|
|
else -> false
|
|
}
|
|
}
|
|
|
|
// Update app/Android.bp
|
|
File("${project.projectDir.absolutePath}/Android.bp").let { file ->
|
|
// Read dependencies
|
|
val dependencies = "${spaces(8)}// DO NOT EDIT THIS SECTION MANUALLY\n".plus(
|
|
configuration.allDependencies.filter {
|
|
// kotlin-bom does not need to be added to dependencies
|
|
it.group != "org.jetbrains.kotlin" && it.name != "kotlin-bom"
|
|
}.joinToString("\n") {
|
|
if (isAvailableInAosp(it.group!!, it.name)) {
|
|
"${spaces(8)}\"${moduleNameAosp("${it.group}:${it.name}")}\","
|
|
} else {
|
|
"${spaces(8)}\"${moduleName("${it.group}:${it.name}")}\","
|
|
}
|
|
}
|
|
)
|
|
|
|
// Replace existing dependencies with newly generated ones
|
|
file.writeText(
|
|
file.readText().replace(
|
|
"static_libs: \\[.*?\\]".toRegex(RegexOption.DOT_MATCHES_ALL),
|
|
"static_libs: [%s]".format("\n$dependencies\n${spaces(4)}")
|
|
)
|
|
)
|
|
}
|
|
|
|
// Update app/libs
|
|
configuration.resolvedConfiguration.resolvedArtifacts.sortedBy {
|
|
moduleString(it.moduleVersion.id)
|
|
}.distinctBy {
|
|
moduleString(it.moduleVersion.id)
|
|
}.forEach {
|
|
val id = it.moduleVersion.id
|
|
|
|
// Skip modules that are available in AOSP
|
|
if (isAvailableInAosp(id.group, it.name)) {
|
|
return@forEach
|
|
}
|
|
|
|
// Get file path
|
|
val dirPath = "${libsBase}/${modulePath(id)}"
|
|
val filePath = "${dirPath}/${it.file.name}"
|
|
|
|
// Copy artifact to app/libs
|
|
it.file.copyTo(File(filePath))
|
|
|
|
// Parse dependencies
|
|
val dependencies =
|
|
it.file.parentFile.parentFile.walk().filter { file -> file.extension == "pom" }
|
|
.map { file ->
|
|
val ret = mutableListOf<String>()
|
|
|
|
val pom = XmlParser().parse(file)
|
|
val dependencies = (pom["dependencies"] as NodeList).firstOrNull() as Node?
|
|
|
|
dependencies?.children()?.forEach { node ->
|
|
val dependency = node as Node
|
|
ret.add(
|
|
"${
|
|
(dependency.get("groupId") as NodeList).text()
|
|
}:${
|
|
(dependency.get("artifactId") as NodeList).text()
|
|
}"
|
|
)
|
|
}
|
|
|
|
ret
|
|
}.flatten()
|
|
|
|
var targetSdkVersion = android.defaultConfig.targetSdk
|
|
var minSdkVersion = 14
|
|
|
|
// Extract AndroidManifest.xml for AARs
|
|
if (it.file.extension == "aar") {
|
|
copy {
|
|
from(zipTree(filePath).matching { include("/AndroidManifest.xml") }.singleFile)
|
|
into(dirPath)
|
|
}
|
|
|
|
val androidManifest = XmlParser().parse(File("${dirPath}/AndroidManifest.xml"))
|
|
|
|
val usesSdk = (androidManifest["uses-sdk"] as NodeList).first() as Node
|
|
targetSdkVersion = (usesSdk.get("@targetSdkVersion") as Int?) ?: targetSdkVersion
|
|
minSdkVersion = (usesSdk.get("@minSdkVersion") as Int?) ?: minSdkVersion
|
|
}
|
|
|
|
// Write Android.bp
|
|
File("$libsBase/Android.bp").let { file ->
|
|
// Add autogenerated header if file is empty
|
|
if (file.length() == 0L) {
|
|
file.writeText("// DO NOT EDIT THIS FILE MANUALLY")
|
|
}
|
|
|
|
val formatDeps = { addNoDeps: Boolean ->
|
|
val deps = dependencies.filter { dep ->
|
|
when {
|
|
configuration.resolvedConfiguration.resolvedArtifacts.firstOrNull { artifact ->
|
|
dep == "${artifact.moduleVersion.id.group}:${artifact.moduleVersion.id.name}"
|
|
} == null -> {
|
|
val moduleName = if (addNoDeps) {
|
|
moduleName(id)
|
|
} else {
|
|
"${moduleName(id)}-nodeps"
|
|
}
|
|
println("$moduleName: Skipping $dep because it's not in resolvedArtifacts")
|
|
false
|
|
}
|
|
|
|
dep == "org.jetbrains.kotlin:kotlin-stdlib-common" -> false
|
|
else -> true
|
|
}
|
|
}.distinct().toMutableList()
|
|
|
|
if (addNoDeps) {
|
|
// Add -nodeps dependency for android_library/java_library_static
|
|
deps.add(0, "${id.group}_${id.name}-nodeps")
|
|
}
|
|
|
|
var ret = ""
|
|
|
|
if (deps.isNotEmpty()) {
|
|
deps.forEach { dep ->
|
|
ret += if (dep.contains(":")) {
|
|
val (group, artifactId) = dep.split(":")
|
|
if (isAvailableInAosp(group, artifactId)) {
|
|
"\n${spaces(8)}\"${moduleNameAosp(dep)}\","
|
|
} else {
|
|
"\n${spaces(8)}\"${moduleName(dep)}\","
|
|
}
|
|
} else {
|
|
"\n${spaces(8)}\"${moduleName(dep)}\","
|
|
}
|
|
}
|
|
ret += "\n${spaces(4)}"
|
|
}
|
|
|
|
ret
|
|
}
|
|
|
|
when (it.extension) {
|
|
"aar" -> {
|
|
file.appendText(
|
|
"""
|
|
|
|
android_library_import {
|
|
name: "${moduleName(id)}-nodeps",
|
|
aars: ["${modulePath(id)}/${it.file.name}"],
|
|
sdk_version: "$targetSdkVersion",
|
|
min_sdk_version: "$minSdkVersion",
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"//apex_available:anyapex",
|
|
],
|
|
static_libs: [%s],
|
|
}
|
|
|
|
android_library {
|
|
name: "${moduleName(id)}",
|
|
sdk_version: "$targetSdkVersion",
|
|
min_sdk_version: "$minSdkVersion",
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"//apex_available:anyapex",
|
|
],
|
|
manifest: "${modulePath(id)}/AndroidManifest.xml",
|
|
static_libs: [%s],
|
|
java_version: "1.7",
|
|
}
|
|
|
|
""".trimIndent().format(formatDeps(false), formatDeps(true))
|
|
)
|
|
}
|
|
|
|
"jar" -> {
|
|
file.appendText(
|
|
"""
|
|
|
|
java_import {
|
|
name: "${moduleName(id)}-nodeps",
|
|
jars: ["${modulePath(id)}/${it.file.name}"],
|
|
sdk_version: "$targetSdkVersion",
|
|
min_sdk_version: "$minSdkVersion",
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"//apex_available:anyapex",
|
|
],
|
|
}
|
|
|
|
java_library_static {
|
|
name: "${moduleName(id)}",
|
|
sdk_version: "$targetSdkVersion",
|
|
min_sdk_version: "$minSdkVersion",
|
|
apex_available: [
|
|
"//apex_available:platform",
|
|
"//apex_available:anyapex",
|
|
],
|
|
static_libs: [%s],
|
|
java_version: "1.7",
|
|
}
|
|
|
|
""".trimIndent().format(formatDeps(true))
|
|
)
|
|
}
|
|
|
|
else -> throw Exception("Unknown file extension: ${it.extension}")
|
|
}
|
|
}
|
|
}
|
|
}
|