Files
Calendar/app/build.gradle.kts
Naveen Singh 57a6f2da8f fix: improve event scheduling logic on reboot (#743)
* fix: call `goAsync()` before doing background work in boot completed receiver

It's the recommended mechanism. Otherwise, there's a good chance that the system may kill the process as soon as `onReceive()` returns.

* fix: remove `canScheduleExactAlarms()` check for Android 13 and above

`AlarmManager.canScheduleExactAlarms()` should return `true` for `USE_EXACT_ALARM` as per the source code, but skipping the check shouldn't hurt. It might also help in case OEMs have customized this behavior.

See: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/main/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java#2850

* fix: reschedule events when time is set or when timezone changes

* refactor: delegate startup work to work manager

 - This receiver was doing too much work and likely timed out when there are many events. Using a dedicated job should prevent such issues.
 - The `android.permission.FOREGROUND_SERVICE` permission is required prior to Android 12 for expedited work.

* fix: reschedule events on app startup when alarms are missing

This should help with recovery in case the app was force-stopped or if the alarms were cleared somehow, e.g., by battery optimization or if the OS ate the BOOT_COMPLETED broadcast for some reason.

* docs: update changelog


Refs: https://github.com/FossifyOrg/Calendar/issues/217
2025-08-31 02:39:04 +05:30

152 lines
4.8 KiB
Kotlin

import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.konan.properties.Properties
import java.io.FileInputStream
plugins {
alias(libs.plugins.android)
alias(libs.plugins.kotlinAndroid)
alias(libs.plugins.ksp)
alias(libs.plugins.detekt)
}
val keystorePropertiesFile: File = rootProject.file("keystore.properties")
val keystoreProperties = Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}
fun hasSigningVars(): Boolean {
return providers.environmentVariable("SIGNING_KEY_ALIAS").orNull != null
&& providers.environmentVariable("SIGNING_KEY_PASSWORD").orNull != null
&& providers.environmentVariable("SIGNING_STORE_FILE").orNull != null
&& providers.environmentVariable("SIGNING_STORE_PASSWORD").orNull != null
}
android {
compileSdk = project.libs.versions.app.build.compileSDKVersion.get().toInt()
defaultConfig {
applicationId = project.property("APP_ID").toString()
minSdk = project.libs.versions.app.build.minimumSDK.get().toInt()
targetSdk = project.libs.versions.app.build.targetSDK.get().toInt()
versionCode = project.property("VERSION_CODE").toString().toInt()
versionName = project.property("VERSION_NAME").toString()
multiDexEnabled = true
vectorDrawables.useSupportLibrary = true
setProperty("archivesBaseName", "calendar-$versionCode")
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
}
}
signingConfigs {
if (keystorePropertiesFile.exists()) {
register("release") {
keyAlias = keystoreProperties.getProperty("keyAlias")
keyPassword = keystoreProperties.getProperty("keyPassword")
storeFile = file(keystoreProperties.getProperty("storeFile"))
storePassword = keystoreProperties.getProperty("storePassword")
}
} else if (hasSigningVars()) {
register("release") {
keyAlias = providers.environmentVariable("SIGNING_KEY_ALIAS").get()
keyPassword = providers.environmentVariable("SIGNING_KEY_PASSWORD").get()
storeFile = file(providers.environmentVariable("SIGNING_STORE_FILE").get())
storePassword = providers.environmentVariable("SIGNING_STORE_PASSWORD").get()
}
} else {
logger.warn("Warning: No signing config found. Build will be unsigned.")
}
}
buildFeatures {
viewBinding = true
buildConfig = true
}
buildTypes {
debug {
applicationIdSuffix = ".debug"
}
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
if (keystorePropertiesFile.exists() || hasSigningVars()) {
signingConfig = signingConfigs.getByName("release")
}
}
}
flavorDimensions.add("variants")
productFlavors {
register("core")
register("foss")
register("gplay")
}
sourceSets {
getByName("main").java.srcDirs("src/main/kotlin")
}
compileOptions {
val currentJavaVersionFromLibs = JavaVersion.valueOf(libs.versions.app.build.javaVersion.get().toString())
sourceCompatibility = currentJavaVersionFromLibs
targetCompatibility = currentJavaVersionFromLibs
}
dependenciesInfo {
includeInApk = false
}
androidResources {
@Suppress("UnstableApiUsage")
generateLocaleConfig = true
}
tasks.withType<KotlinCompile> {
compilerOptions.jvmTarget.set(
JvmTarget.fromTarget(project.libs.versions.app.build.kotlinJVMTarget.get())
)
}
namespace = project.property("APP_ID").toString()
lint {
checkReleaseBuilds = false
abortOnError = true
warningsAsErrors = false
baseline = file("lint-baseline.xml")
lintConfig = rootProject.file("lint.xml")
}
bundle {
language {
enableSplit = false
}
}
}
detekt {
baseline = file("detekt-baseline.xml")
config.setFrom("$rootDir/detekt.yml")
buildUponDefaultConfig = true
allRules = false
}
dependencies {
implementation(libs.fossify.commons)
implementation(libs.androidx.multidex)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.swiperefreshlayout)
implementation(libs.androidx.print)
implementation(libs.bundles.room)
implementation(libs.androidx.work.runtime.ktx)
ksp(libs.androidx.room.compiler)
detektPlugins(libs.compose.detekt)
}