import app.cash.licensee.LicenseeTask import com.android.build.gradle.api.AndroidBasePlugin import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id 'com.android.application' version "8.6.0" id 'com.android.library' version "8.6.0" apply false id 'com.android.test' version '8.6.0' apply false id 'androidx.baselineprofile' version '1.3.0' id 'org.jetbrains.kotlin.android' version "2.0.20" id 'org.jetbrains.kotlin.plugin.compose' version "2.0.20" id 'org.jetbrains.kotlin.plugin.parcelize' version "2.0.20" id 'org.jetbrains.kotlin.plugin.serialization' version "2.0.20" id "com.google.devtools.ksp" version "2.0.20-1.0.25" id 'com.google.protobuf' version "0.9.4" id 'app.cash.licensee' version "1.11.0" id 'dev.rikka.tools.refine' version "4.4.0" id 'org.gradle.android.cache-fix' version '3.0.1' id 'com.diffplug.spotless' version '6.25.0' } allprojects { plugins.withType(AndroidBasePlugin).configureEach { apply plugin: 'org.gradle.android.cache-fix' android { compileSdk 35 defaultConfig { minSdk 26 targetSdk 34 vectorDrawables.useSupportLibrary = true } lint { abortOnError true checkReleaseBuilds false } } dependencies { implementation 'androidx.core:core-ktx:1.13.1' implementation 'androidx.appcompat:appcompat:1.7.0' } } plugins.withId('com.google.protobuf') { def protocVersion = '4.28.1' protobuf { // Configure the protoc executable protoc { artifact = "com.google.protobuf:protoc:${protocVersion}" } generateProtoTasks { all().configureEach { task -> task.builtins { remove java java { option "lite" } } } } } dependencies { implementation "com.google.protobuf:protobuf-javalite:$protocVersion" } } plugins.withType(JavaBasePlugin).configureEach { java { toolchain.languageVersion = JavaLanguageVersion.of(17) } } tasks.withType(KotlinCompile).configureEach { compilerOptions.freeCompilerArgs.add( "-Xjvm-default=all", ) } ext { FRAMEWORK_PREBUILTS_DIR = "$rootDir/prebuilts/libs" daggerVersion = '2.52' addFrameworkJar = { String name -> def frameworkJar = new File(FRAMEWORK_PREBUILTS_DIR, name) if (!frameworkJar.exists()) { throw new IllegalArgumentException("Framework jar path ${frameworkJar.path} doesn't exist") } gradle.projectsEvaluated { tasks.withType(JavaCompile).configureEach { classpath = files(frameworkJar, classpath) } tasks.withType(KotlinCompile).configureEach { libraries.from(files(frameworkJar)) } } dependencies { compileOnly files(frameworkJar) } } compileOnlyCommonJars = { dependencies { compileOnly fileTree(dir: FRAMEWORK_PREBUILTS_DIR, include: 'SystemUI-core.jar') compileOnly fileTree(dir: FRAMEWORK_PREBUILTS_DIR, include: 'SystemUI-statsd.jar') compileOnly fileTree(dir: FRAMEWORK_PREBUILTS_DIR, include: 'WindowManager-Shell-14.jar') compileOnly projects.compatLib compileOnly projects.compatLib.compatLibVQ compileOnly projects.compatLib.compatLibVR compileOnly projects.compatLib.compatLibVS compileOnly projects.compatLib.compatLibVT compileOnly projects.compatLib.compatLibVU } } } } final def buildCommit = providers.exec { commandLine('git', 'rev-parse', '--short=7', 'HEAD') }.standardOutput.asText.get().trim() final def ciBuild = System.getenv("CI") == "true" final def ciRef = System.getenv("GITHUB_REF") ?: "" final def ciRunNumber = System.getenv("GITHUB_RUN_NUMBER") ?: "" final def isReleaseBuild = ciBuild && ciRef.contains("beta") final def devReleaseName = ciBuild ? "Dev.(#${ciRunNumber})" : "Dev.(${buildCommit})" final def version = "14" final def releaseName = "Beta 3" final def versionDisplayName = "${version}.${isReleaseBuild ? releaseName : devReleaseName}" final def majorVersion = versionDisplayName.split("\\.")[0] final def quickstepMinSdk = "29" final def quickstepMaxSdk = "34" android { namespace "com.android.launcher3" defaultConfig { // Lawnchair Launcher 14.0 Beta 3 // See CONTRIBUTING.md#versioning-scheme versionCode 14_00_02_03 versionName "${versionDisplayName}" buildConfigField "String", "VERSION_DISPLAY_NAME", "\"${versionDisplayName}\"" buildConfigField "String", "MAJOR_VERSION", "\"${majorVersion}\"" buildConfigField "String", "COMMIT_HASH", "\"${buildCommit}\"" buildConfigField "boolean", "ENABLE_AUTO_INSTALLS_LAYOUT", "false" manifestPlaceholders.quickstepMinSdk = quickstepMinSdk manifestPlaceholders.quickstepMaxSdk = quickstepMaxSdk buildConfigField "int", "QUICKSTEP_MIN_SDK", quickstepMinSdk buildConfigField "int", "QUICKSTEP_MAX_SDK", quickstepMaxSdk } applicationVariants.configureEach { variant -> variant.outputs.configureEach { def channel = variant.productFlavors.last().name outputFileName = "Lawnchair.${variant.versionName}.$channel.${variant.buildType.name}.apk" } } androidResources { generateLocaleConfig true } buildFeatures { aidl true buildConfig true resValues true } final def keystorePropertiesFile = rootProject.file("keystore.properties") def releaseSigning = signingConfigs.debug if (keystorePropertiesFile.exists()) { final def keystoreProperties = new Properties() keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) releaseSigning = signingConfigs.create("release") { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile rootProject.file(keystoreProperties['storeFile']) storePassword keystoreProperties['storePassword'] } } packagingOptions.resources.excludes += [ "**/*.proto", "**/*.bin", "**/*.java", "**/*.properties", "**/*.version", "**/*.*_module", "com/**", "google/**", "kotlin/**", "kotlinx/**", "okhttp3/**", "META-INF/services/**", "META-INF/com/**", "META-INF/licenses/**", "META-INF/AL2.0", "META-INF/LGPL2.1", ] // Load all proguard configs from AOSP def proguardFilesFromAosp = allprojects .collect { it.file("proguard.flags") } .findAll { it.exists() } .toArray() buildTypes { all { signingConfig releaseSigning pseudoLocalesEnabled true } debug { applicationIdSuffix ".debug" resValue("string", "derived_app_name", "Lawnchair (Debug)") } release { resValue("string", "derived_app_name", "Lawnchair") minifyEnabled true shrinkResources true proguardFiles proguardFilesFromAosp + "proguard.pro" } } compileOptions { coreLibraryDesugaringEnabled true } dependenciesInfo { includeInApk = false includeInBundle = false } // See: https://developer.android.com/studio/build/build-variants#flavor-dimensions flavorDimensions += ["app", "recents", "channel"] productFlavors { lawn { dimension "app" } withQuickstep { dimension "recents" minSdk 26 } github { applicationId 'app.lawnchair' dimension "channel" } play { applicationId "app.lawnchair.play" dimension "channel" isDefault true } configureEach { resValue("string", "launcher_component", "${applicationId}/app.lawnchair.LawnchairLauncher") } } sourceSets { main { res.srcDirs = ['res'] java.srcDirs = ['src', 'src_plugins'] manifest.srcFile 'AndroidManifest-common.xml' proto { srcDirs = ['protos/', 'quickstep/protos_overrides/'] } } lawn { java.srcDirs = ['src_flags', 'src_shortcuts_overrides', 'lawnchair/src', 'tests/shared'] aidl.srcDirs = ['lawnchair/aidl'] res.srcDirs = ['lawnchair/res', 'platform_frameworks_libs_systemui/animationlib/res'] manifest.srcFile "lawnchair/AndroidManifest.xml" assets { srcDirs 'lawnchair/assets' } proto { srcDirs = ['lawnchair/protos/'] } } lawnWithQuickstepGithub { manifest.srcFile "quickstep/AndroidManifest-launcher.xml" } lawnWithQuickstepPlay { manifest.srcFile "quickstep/AndroidManifest-launcher.xml" } withQuickstep { res.srcDirs = ['quickstep/res', 'quickstep/recents_ui_overrides/res'] java.srcDirs = ['quickstep/src', 'quickstep/recents_ui_overrides/src'] manifest.srcFile "quickstep/AndroidManifest.xml" } } } androidComponents { onVariants(selector().all()) { variant -> def capName = variant.name.capitalize() def licenseeTask = tasks.named("licenseeAndroid$capName", LicenseeTask) def copyArtifactsTask = tasks.register("copy${capName}Artifacts", Copy) { dependsOn(licenseeTask) from(licenseeTask.map { it.jsonOutput }) // Copy artifacts.json to a new directory. into(layout.buildDirectory.dir("generated/dependencyAssets/${variant.name}")) } variant.sources.assets?.addGeneratedSourceDirectory(licenseeTask) { // Avoid using LicenseeTask::outputDir as it contains extra files that we don't need. objects.directoryProperty().fileProvider(copyArtifactsTask.map { it.destinationDir }) } } } composeCompiler { stabilityConfigurationFile = layout.projectDirectory.file("compose_compiler_config.conf") reportsDestination = layout.buildDirectory.dir("compose_build_reports") } addFrameworkJar('framework-14.jar') dependencies { implementation projects.iconloaderlib implementation projects.searchuilib implementation projects.animationlib // Recents lib dependency withQuickstepCompileOnly projects.hiddenApi withQuickstepImplementation projects.systemUIShared withQuickstepImplementation projects.systemUIAnim withQuickstepImplementation projects.systemUnFold withQuickstepImplementation projects.systemUIViewCapture withQuickstepImplementation projects.systemUILog withQuickstepCompileOnly projects.systemUIPlugin withQuickstepImplementation projects.systemUIPluginCore withQuickstepCompileOnly projects.systemUICommon // QuickSwitch Compat withQuickstepImplementation projects.compatLib withQuickstepImplementation projects.compatLib.compatLibVQ withQuickstepImplementation projects.compatLib.compatLibVR withQuickstepImplementation projects.compatLib.compatLibVS withQuickstepImplementation projects.compatLib.compatLibVT withQuickstepImplementation projects.compatLib.compatLibVU implementation fileTree(dir: FRAMEWORK_PREBUILTS_DIR, include: 'SystemUI-statsd-14.jar') implementation fileTree(dir: FRAMEWORK_PREBUILTS_DIR, include: 'WindowManager-Shell-14.jar') withQuickstepCompileOnly fileTree(dir: FRAMEWORK_PREBUILTS_DIR, include: 'framework-14.jar') coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.2' implementation 'androidx.profileinstaller:profileinstaller:1.3.1' baselineProfile projects.baselineProfile implementation "androidx.dynamicanimation:dynamicanimation:1.0.0" implementation "androidx.recyclerview:recyclerview:1.3.2" implementation "androidx.preference:preference-ktx:1.2.1" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1' implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2' implementation 'com.github.ChickenHook:RestrictionBypass:2.2' implementation 'dev.rikka.tools.refine:runtime:4.4.0' implementation platform("androidx.compose:compose-bom:2024.09.01") implementation "androidx.compose.ui:ui" implementation "androidx.compose.ui:ui-util" debugImplementation "androidx.compose.ui:ui-tooling" implementation "androidx.compose.ui:ui-tooling-preview" implementation "androidx.compose.ui:ui-text-google-fonts" implementation "androidx.compose.foundation:foundation" implementation "androidx.compose.material:material-icons-extended" implementation "androidx.compose.material:material" implementation "androidx.compose.runtime:runtime-livedata" implementation 'androidx.compose.material3:material3' implementation 'androidx.compose.material3:material3-window-size-class' implementation "androidx.activity:activity-compose:1.9.2" implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5" implementation "androidx.navigation:navigation-compose:2.8.0" implementation "androidx.constraintlayout:constraintlayout:2.1.4" implementation "androidx.palette:palette-ktx:1.0.0" implementation "androidx.slice:slice-core:1.1.0-alpha02" def accompanistVersion = '0.36.0' implementation "com.google.accompanist:accompanist-adaptive:$accompanistVersion" implementation "com.google.accompanist:accompanist-drawablepainter:$accompanistVersion" implementation "com.google.accompanist:accompanist-permissions:$accompanistVersion" implementation "com.google.android.material:material:1.12.0" implementation "io.github.fornewid:material-motion-compose-core:1.2.1" implementation 'dev.kdrag0n:colorkt:1.0.5' implementation 'io.coil-kt:coil-compose:2.7.0' implementation 'me.xdrop:fuzzywuzzy:1.4.0' def optoVersion = "1.0.18" implementation "com.patrykmichalik.opto:domain:$optoVersion" implementation "com.patrykmichalik.opto:core:$optoVersion" implementation "com.patrykmichalik.opto:compose:$optoVersion" implementation "androidx.datastore:datastore-preferences:1.1.1" def retrofitVersion = "2.11.0" implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" implementation "com.squareup.retrofit2:converter-kotlinx-serialization:$retrofitVersion" def roomVersion = '2.6.1' implementation "androidx.room:room-runtime:$roomVersion" implementation "androidx.room:room-ktx:$roomVersion" ksp "androidx.room:room-compiler:$roomVersion" implementation "com.github.topjohnwu.libsu:service:6.0.0" // Persian Date implementation 'com.github.samanzamani:PersianDate:1.7.1' implementation 'com.airbnb.android:lottie:6.5.2' // Compose drag and drop library implementation 'sh.calvin.reorderable:reorderable:2.3.2' // Smartspacer implementation('com.kieronquinn.smartspacer:sdk-client:1.0.11') { exclude group: "com.github.skydoves", module: "balloon" } implementation("com.github.android:renderscript-intrinsics-replacement-toolkit:b6363490c3") } ksp { arg("room.schemaLocation", "$projectDir/schemas") arg("room.generateKotlin", "true") arg("room.incremental", "true") } spotless { java { target("compatLib/**/src/**/*.java") googleJavaFormat().aosp() removeUnusedImports() } kotlin { target("lawnchair/src/**/*.kt") ktlint().customRuleSets([ "io.nlopez.compose.rules:ktlint:0.4.12", ]).editorConfigOverride([ "ktlint_compose_compositionlocal-allowlist": "disabled", ]) } } licensee { allow("Apache-2.0") allow("BSD-3-Clause") allow("GPL-2.0-or-later") allowDependency("com.github.topjohnwu.libsu", "core", "6.0.0") allowDependency("com.github.topjohnwu.libsu", "service", "6.0.0") allowUrl("https://github.com/patrykmichalik/opto/blob/master/LICENSE") allowUrl("https://github.com/RikkaApps/HiddenApiRefinePlugin/blob/main/LICENSE") allowUrl("https://opensource.org/licenses/mit-license.php") }