Compare commits

..

13 Commits

Author SHA1 Message Date
Ricki Hirner
a30dc63714 Update AndroidManifest to set install location to internal only (again) 2026-02-06 14:36:19 +01:00
Ricki Hirner
93431ee6d5 Remove build.gradle.kts and update settings.gradle.kts
- Remove `build.gradle.kts` file
- Update `settings.gradle.kts` to use `gradlePluginPortal` for plugins
- Set `repositoriesMode` to `PREFER_SETTINGS`
- Add comments for clarity in `settings.gradle.kts`
2026-02-06 14:30:28 +01:00
Ricki Hirner
31c4eb6380 Update package references and permissions
- Update references from `com.davx5.ose.App` to `at.bitfire.davdroid.CoreApp`
- Enable archive naming in `app-ose/build.gradle.kts`
- Remove redundant permission declarations in `core/src/main/AndroidManifest.xml`
2026-02-06 14:14:23 +01:00
Ricki Hirner
6b6c340844 Refactor App Initialization
- Introduce `CoreApp` for common initialization logic
- Refactor `App` to extend `CoreApp` and handle WorkManager configuration
2026-02-06 14:04:11 +01:00
Ricki Hirner
e1a58ef576 Don't run app-ose tests yet because there are none 2026-02-06 11:18:49 +01:00
Ricki Hirner
ec00cc6a3f Move WorkManagerInitializer from core to app-ose AndroidManifest 2026-02-06 11:11:48 +01:00
Ricki Hirner
2ce9b83356 Fix core instrumentation tests 2026-02-06 10:57:01 +01:00
Ricki Hirner
47b4ecd705 Add OpenID AppAuth library 2026-02-05 20:06:37 +01:00
Ricki Hirner
bced7e5ee5 Update test configuration
- Add managed device for testing
- Set device to "Pixel 3" with API level 34
- Use AOSP system image source
2026-02-05 20:00:17 +01:00
Ricki Hirner
360c2249cf Update test workflows 2026-02-05 19:55:42 +01:00
Ricki Hirner
53791871c6 Split core and app-ose 2026-02-05 18:16:35 +01:00
Ricki Hirner
9bddf4e8d4 Rename "app" subproject to core 2026-02-05 17:30:18 +01:00
Ricki Hirner
eab054d1c3 Move OSE code to separate package (#1974)
- Move DebugInfoCrashHandler.kt to com.davx5.ose
- Move StandardLoginTypePage.kt to com.davx5.ose.ui.setup
- Move StandardLoginTypesProvider.kt to com.davx5.ose.ui.setup
- Move CustomCertManagerModule.kt to com.davx5.ose.di
- Move OseIntroPageFactory.kt to com.davx5.ose.ui.intro
- Move OseColorSchemesModule.kt to com.davx5.ose.di
- Move OseFlavorModule.kt to com.davx5.ose.di
- Move OpenSourceLicenseInfoProvider.kt to com.davx5.ose.ui.about
- Move OseTheme.kt to com.davx5.ose.ui
2026-02-05 17:21:57 +01:00
29 changed files with 411 additions and 388 deletions

View File

@@ -49,10 +49,10 @@ jobs:
# Cache configurations for the other jobs (including assemble for CodeQL)
- name: Populate configuration cache
run: |
./gradlew --dry-run app:assembleDebug
./gradlew --dry-run app:lintOseDebug
./gradlew --dry-run app:testOseDebugUnitTest
./gradlew --dry-run app:virtualOseDebugAndroidTest
./gradlew --dry-run core:assembleDebug app:assembleDebug
./gradlew --dry-run core:lintDebug app:lintOseDebug
./gradlew --dry-run core:testDebugUnitTest
./gradlew --dry-run core:virtualDebugAndroidTest
unit_tests:
needs: compile
@@ -76,10 +76,10 @@ jobs:
key: android-${{ hashFiles('app/build.gradle.kts') }}
- name: Lint checks
run: ./gradlew app:lintOseDebug
run: ./gradlew core:lintDebug app:lintOseDebug
- name: Unit tests
run: ./gradlew app:testOseDebugUnitTest
run: ./gradlew core:testDebugUnitTest
instrumented_tests:
needs: compile
@@ -126,7 +126,7 @@ jobs:
sudo udevadm trigger --name-match=kvm
- name: Instrumented tests
run: ./gradlew app:virtualOseDebugAndroidTest
run: ./gradlew core:virtualDebugAndroidTest
- name: Cache AVD
uses: actions/cache/save@v5

126
app-ose/build.gradle.kts Normal file
View File

@@ -0,0 +1,126 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.hilt)
alias(libs.plugins.ksp)
}
android {
compileSdk = 36
defaultConfig {
minSdk = 24 // Android 7.0
targetSdk = 36 // Android 16
applicationId = "at.bitfire.davdroid"
versionCode = 405090005
versionName = "4.5.9"
base.archivesName = "davx5-$versionCode-$versionName"
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
buildFeatures {
compose = true
}
// Java namespace for our classes (not to be confused with Android package ID)
namespace = "com.davx5.ose"
flavorDimensions += "distribution"
productFlavors {
create("ose") {
dimension = "distribution"
versionNameSuffix = "-ose"
}
}
androidResources {
generateLocaleConfig = true
}
buildTypes {
getByName("release") {
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules-release.pro")
isShrinkResources = true
signingConfig = signingConfigs.findByName("bitfire")
}
}
signingConfigs {
create("bitfire") {
storeFile = file(System.getenv("ANDROID_KEYSTORE") ?: "/dev/null")
storePassword = System.getenv("ANDROID_KEYSTORE_PASSWORD")
keyAlias = System.getenv("ANDROID_KEY_ALIAS")
keyPassword = System.getenv("ANDROID_KEY_PASSWORD")
}
}
@Suppress("UnstableApiUsage")
testOptions {
managedDevices {
localDevices {
create("virtual") {
device = "Pixel 3"
// TBD: API level 35 and higher causes network tests to fail sometimes, see https://github.com/bitfireAT/davx5-ose/issues/1525
// Suspected reason: https://developer.android.com/about/versions/15/behavior-changes-all#background-network-access
apiLevel = 34
systemImageSource = "aosp-atd"
}
}
}
}
}
dependencies {
// include core subproject (manages its own dependencies itself, however from same version catalog)
implementation(project(":core"))
// Kotlin / Android
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines)
coreLibraryDesugaring(libs.android.desugaring)
// Hilt
implementation(libs.hilt.android.base)
ksp(libs.androidx.hilt.compiler)
ksp(libs.hilt.android.compiler)
// support libs
implementation(libs.androidx.core)
implementation(libs.androidx.hilt.work)
implementation(libs.androidx.lifecycle.viewmodel.base)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.work.base)
// Jetpack Compose
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.material3)
debugImplementation(libs.androidx.compose.ui.tooling)
implementation(libs.androidx.compose.ui.toolingPreview)
// own libraries
implementation(libs.bitfire.cert4android)
// third-party libs
implementation(libs.guava)
implementation(libs.okhttp.base)
implementation(libs.openid.appauth)
}

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="internalOnly">
<application android:name=".App">
<!-- Required for Hilt/WorkManager integration. See
- https://developer.android.com/develop/background-work/background-tasks/persistent/configuration/custom-configuration#remove-default
- https://developer.android.com/training/dependency-injection/hilt-jetpack#workmanager
However, we must not disable AndroidX startup completely, as it's needed by other libraries like okhttp. -->
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
</application>
</manifest>

View File

@@ -0,0 +1,30 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package com.davx5.ose
import androidx.work.Configuration
import at.bitfire.davdroid.CoreApp
import dagger.hilt.android.HiltAndroidApp
/**
* Actual implementation of Application, used for Hilt. Delegates to [CoreApp].
*/
@HiltAndroidApp
class App: CoreApp(), Configuration.Provider {
/**
* Required for Hilt/WorkManager integration, see:
* https://developer.android.com/training/dependency-injection/hilt-jetpack#workmanager
*
* This requires to remove the androidx.work.WorkManagerInitializer from App Startup
* in the AndroidManifest, see:
* https://developer.android.com/develop/background-work/background-tasks/persistent/configuration/custom-configuration#remove-default
*/
override val workManagerConfiguration: Configuration
get() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.build()
}

View File

@@ -7,7 +7,7 @@ package com.davx5.ose.di
import androidx.compose.material3.ColorScheme
import at.bitfire.davdroid.di.scope.DarkColorScheme
import at.bitfire.davdroid.di.scope.LightColorScheme
import com.davx5.ose.ui.OseTheme
import at.bitfire.davdroid.ui.OseTheme
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@@ -15,7 +15,7 @@ import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
class OseColorSchemesModule {
class ColorSchemesModule {
@Provides
@LightColorScheme

View File

@@ -11,7 +11,7 @@ import at.bitfire.davdroid.ui.intro.IntroPageFactory
import at.bitfire.davdroid.ui.setup.LoginTypesProvider
import com.davx5.ose.ui.about.OpenSourceLicenseInfoProvider
import com.davx5.ose.ui.intro.OseIntroPageFactory
import com.davx5.ose.ui.setup.StandardLoginTypesProvider
import at.bitfire.davdroid.ui.setup.StandardLoginTypesProvider
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn

View File

@@ -4,7 +4,7 @@
package com.davx5.ose.ui.about
import android.app.Application
import android.content.Context
import android.text.Spanned
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -14,14 +14,16 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.text.HtmlCompat
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import at.bitfire.davdroid.di.scope.IoDispatcher
import at.bitfire.davdroid.ui.UiUtils.toAnnotatedString
import at.bitfire.davdroid.ui.about.AboutActivity
import com.google.common.io.CharStreams
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.launch
import javax.inject.Inject
@@ -41,13 +43,16 @@ class OpenSourceLicenseInfoProvider @Inject constructor(): AboutActivity.AppLice
@HiltViewModel
class Model @Inject constructor(app: Application): AndroidViewModel(app) {
class Model @Inject constructor(
@ApplicationContext private val context: Context,
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
): ViewModel() {
var gpl by mutableStateOf<Spanned?>(null)
init {
viewModelScope.launch(Dispatchers.IO) {
app.resources.assets.open("gplv3.html").use { inputStream ->
viewModelScope.launch(ioDispatcher) {
context.resources.assets.open("gplv3.html").use { inputStream ->
val raw = CharStreams.toString(inputStream.bufferedReader())
gpl = HtmlCompat.fromHtml(raw, HtmlCompat.FROM_HTML_MODE_LEGACY)
}

View File

@@ -1,233 +0,0 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.hilt)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.ksp)
alias(libs.plugins.mikepenz.aboutLibraries.android)
}
// Android configuration
android {
compileSdk = 36
defaultConfig {
applicationId = "at.bitfire.davdroid"
versionCode = 405090005
versionName = "4.5.9"
base.archivesName = "davx5-$versionCode-$versionName"
minSdk = 24 // Android 7.0
targetSdk = 36 // Android 16
testInstrumentationRunner = "at.bitfire.davdroid.HiltTestRunner"
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
compileOptions {
// required for
// - dnsjava 3.x: java.nio.file.Path
// - ical4android: time API
isCoreLibraryDesugaringEnabled = true
}
buildFeatures {
buildConfig = true
compose = true
}
// Java namespace for our classes (not to be confused with Android package ID)
namespace = "com.davx5.ose"
flavorDimensions += "distribution"
productFlavors {
create("ose") {
dimension = "distribution"
versionNameSuffix = "-ose"
}
}
sourceSets {
getByName("androidTest") {
assets.srcDir("$projectDir/schemas")
}
}
signingConfigs {
create("bitfire") {
storeFile = file(System.getenv("ANDROID_KEYSTORE") ?: "/dev/null")
storePassword = System.getenv("ANDROID_KEYSTORE_PASSWORD")
keyAlias = System.getenv("ANDROID_KEY_ALIAS")
keyPassword = System.getenv("ANDROID_KEY_PASSWORD")
}
}
buildTypes {
getByName("release") {
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules-release.pro")
isShrinkResources = true
signingConfig = signingConfigs.findByName("bitfire")
}
}
lint {
disable += arrayOf("GoogleAppIndexingWarning", "ImpliedQuantity", "MissingQuantity", "MissingTranslation", "ExtraTranslation", "RtlEnabled", "RtlHardcoded", "Typos")
}
androidResources {
generateLocaleConfig = true
}
packaging {
resources {
// multiple (test) dependencies have LICENSE files at same location
merges += arrayOf("META-INF/LICENSE*")
}
}
@Suppress("UnstableApiUsage")
testOptions {
managedDevices {
localDevices {
create("virtual") {
device = "Pixel 3"
// TBD: API level 35 and higher causes network tests to fail sometimes, see https://github.com/bitfireAT/davx5-ose/issues/1525
// Suspected reason: https://developer.android.com/about/versions/15/behavior-changes-all#background-network-access
apiLevel = 34
systemImageSource = "aosp-atd"
}
}
}
}
}
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
}
aboutLibraries {
export {
// exclude timestamps for reproducible builds [https://github.com/bitfireAT/davx5-ose/issues/994]
excludeFields.add("generated")
}
}
dependencies {
// app core
implementation(project(":core"))
// Kotlin / Android
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines)
coreLibraryDesugaring(libs.android.desugaring)
// Hilt
implementation(libs.hilt.android.base)
ksp(libs.androidx.hilt.compiler)
ksp(libs.hilt.android.compiler)
// support libs
implementation(libs.androidx.activityCompose)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.browser)
implementation(libs.androidx.core)
implementation(libs.androidx.hilt.navigation.compose)
implementation(libs.androidx.hilt.work)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.androidx.lifecycle.viewmodel.base)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.paging)
implementation(libs.androidx.paging.compose)
implementation(libs.androidx.preference)
implementation(libs.androidx.security)
implementation(libs.androidx.work.base)
// Jetpack Compose
implementation(libs.compose.accompanist.permissions)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.material3.adaptive)
implementation(libs.androidx.compose.materialIconsExtended)
debugImplementation(libs.androidx.compose.ui.tooling)
implementation(libs.androidx.compose.ui.toolingPreview)
// Glance Widgets
implementation(libs.androidx.glance.base)
implementation(libs.androidx.glance.material3)
// Jetpack Room
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.base)
implementation(libs.androidx.room.paging)
ksp(libs.androidx.room.compiler)
// own libraries
implementation(libs.bitfire.cert4android)
implementation(libs.bitfire.dav4jvm) {
exclude(group="junit")
exclude(group="org.ogce", module="xpp3") // Android has its own XmlPullParser implementation
}
implementation(libs.bitfire.synctools) {
exclude(group="androidx.test") // synctools declares test rules, but we don't want them in non-test code
exclude(group = "junit")
}
// third-party libs
implementation(libs.conscrypt)
implementation(libs.dnsjava)
implementation(libs.guava)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.okhttp)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.mikepenz.aboutLibraries.m3)
implementation(libs.okhttp.base)
implementation(libs.okhttp.brotli)
implementation(libs.okhttp.logging)
implementation(libs.openid.appauth)
implementation(libs.unifiedpush) {
// UnifiedPush connector seems to be using a workaround by importing this library.
// Will be removed after https://github.com/tink-crypto/tink-java-apps/pull/5 is merged.
// See: https://codeberg.org/UnifiedPush/android-connector/src/commit/28cb0d622ed0a972996041ab9cc85b701abc48c6/connector/build.gradle#L56-L59
exclude(group = "com.google.crypto.tink", module = "tink")
}
implementation(libs.unifiedpush.fcm)
// force some versions for compatibility with our minSdk level (see version catalog for details)
implementation(libs.commons.codec)
implementation(libs.commons.lang)
// for tests
androidTestImplementation(libs.androidx.arch.core.testing)
androidTestImplementation(libs.androidx.room.testing)
androidTestImplementation(libs.androidx.test.core)
androidTestImplementation(libs.androidx.test.junit)
androidTestImplementation(libs.androidx.test.rules)
androidTestImplementation(libs.androidx.test.runner)
androidTestImplementation(libs.androidx.work.testing)
androidTestImplementation(libs.hilt.android.testing)
androidTestImplementation(libs.junit)
androidTestImplementation(libs.kotlinx.coroutines.test)
androidTestImplementation(libs.mockk.android)
androidTestImplementation(libs.okhttp.mockwebserver)
testImplementation(libs.bitfire.dav4jvm)
testImplementation(libs.junit)
testImplementation(libs.mockk)
testImplementation(libs.okhttp.mockwebserver)
testImplementation(libs.robolectric)
}

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="internalOnly">
<application android:name=".App">
<!-- Remove the node added by AppAuth (remove only from net.openid.appauth library, not from our flavor manifest files) -->
<activity android:name="net.openid.appauth.RedirectUriReceiverActivity"
tools:node="remove" tools:selector="net.openid.appauth"/>
</application>
</manifest>

View File

@@ -1,13 +0,0 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.hilt) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.mikepenz.aboutLibraries.android) apply false
}

View File

@@ -42,12 +42,6 @@ android {
// Java namespace for our classes (not to be confused with Android package ID)
namespace = "at.bitfire.davdroid"
sourceSets {
getByName("androidTest") {
assets.srcDir("$projectDir/schemas")
}
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
@@ -65,6 +59,12 @@ android {
}
}
sourceSets {
getByName("androidTest") {
assets.srcDir("$projectDir/schemas")
}
}
@Suppress("UnstableApiUsage")
testOptions {
managedDevices {

View File

@@ -0,0 +1,28 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.di
import at.bitfire.cert4android.CustomCertManager
import at.bitfire.cert4android.CustomCertStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import java.util.Optional
@Module
@InstallIn(SingletonComponent::class)
class Cert4AndroidModule {
@Provides
fun customCertManager(): Optional<CustomCertManager> = Optional.empty()
@Provides
fun customHostnameVerifier(): Optional<CustomCertManager.HostnameVerifier> = Optional.empty()
@Provides
fun customCertStore(): Optional<CustomCertStore> = Optional.empty()
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.di
import androidx.compose.material3.ColorScheme
import at.bitfire.davdroid.di.scope.DarkColorScheme
import at.bitfire.davdroid.di.scope.LightColorScheme
import at.bitfire.davdroid.ui.OseTheme
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
class ColorSchemesModule {
@Provides
@LightColorScheme
fun lightColorScheme(): ColorScheme = OseTheme.lightScheme
@Provides
@DarkColorScheme
fun darkColorScheme(): ColorScheme = OseTheme.darkScheme
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.di
import at.bitfire.davdroid.ui.AccountsDrawerHandler
import at.bitfire.davdroid.ui.OseAccountsDrawerHandler
import at.bitfire.davdroid.ui.about.AboutActivity
import at.bitfire.davdroid.ui.about.FakeAppLicenseInfoProvider
import at.bitfire.davdroid.ui.intro.FakeIntroPageFactory
import at.bitfire.davdroid.ui.intro.IntroPageFactory
import at.bitfire.davdroid.ui.setup.LoginTypesProvider
import at.bitfire.davdroid.ui.setup.StandardLoginTypesProvider
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import dagger.hilt.android.components.ViewModelComponent
import dagger.hilt.components.SingletonComponent
interface OseModules {
@Module
@InstallIn(ActivityComponent::class)
interface ForActivities {
@Binds
fun accountsDrawerHandler(impl: OseAccountsDrawerHandler): AccountsDrawerHandler
@Binds
fun loginTypesProvider(impl: StandardLoginTypesProvider): LoginTypesProvider
}
@Module
@InstallIn(ViewModelComponent::class)
interface ForViewModels {
@Binds
fun appLicenseInfoProvider(impl: FakeAppLicenseInfoProvider): AboutActivity.AppLicenseInfoProvider
@Binds
fun loginTypesProvider(impl: StandardLoginTypesProvider): LoginTypesProvider
}
@Module
@InstallIn(SingletonComponent::class)
interface Global {
@Binds
fun introPageFactory(impl: FakeIntroPageFactory): IntroPageFactory
}
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.ui.about
import androidx.compose.runtime.Composable
import javax.inject.Inject
class FakeAppLicenseInfoProvider @Inject constructor(): AboutActivity.AppLicenseInfoProvider {
@Composable
override fun LicenseInfo() {
throw NotImplementedError()
}
}

View File

@@ -0,0 +1,14 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.ui.intro
import javax.inject.Inject
class FakeIntroPageFactory @Inject constructor(): IntroPageFactory {
override val introPages: Array<IntroPage>
get() = throw NotImplementedError()
}

View File

@@ -18,13 +18,7 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<!-- other permissions -->
<!-- android.permission-group.CONTACTS -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<!-- android.permission-group.CALENDAR -->
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<!-- synctools declares contacts / events / task access permissions -->
<!-- android.permission-group.LOCATION -->
<!-- getting the WiFi name (for "sync in Wifi only") requires
@@ -35,8 +29,6 @@
<!-- required since Android 10 to get the WiFi name while in background (= while syncing) -->
<uses-permission-sdk-23 android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<!-- ical4android declares task access permissions -->
<!-- Disable GPS capability requirement, which is implicitly derived from ACCESS_FINE_LOCATION
permission and makes app unusable on some devices without GPS. We need location permissions only
to get the current WiFi SSID, and we don't need GPS for that. -->
@@ -52,21 +44,6 @@
tools:ignore="UnusedAttribute"
android:supportsRtl="true">
<!-- Required for Hilt/WorkManager integration. See
- https://developer.android.com/develop/background-work/background-tasks/persistent/configuration/custom-configuration#remove-default
- https://developer.android.com/training/dependency-injection/hilt-jetpack#workmanager
However, we must not disable AndroidX startup completely, as it's needed by other libraries like okhttp. -->
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
<!-- Remove the node added by AppAuth (remove only from net.openid.appauth library, not from our flavor manifest files) -->
<activity android:name="net.openid.appauth.RedirectUriReceiverActivity"
tools:node="remove" tools:selector="net.openid.appauth"/>

View File

@@ -2,17 +2,15 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package com.davx5.ose
package at.bitfire.davdroid
import android.app.Application
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import at.bitfire.davdroid.di.scope.DefaultDispatcher
import at.bitfire.davdroid.log.LogManager
import at.bitfire.davdroid.startup.StartupPlugin
import at.bitfire.davdroid.sync.account.AccountsCleanupWorker
import at.bitfire.davdroid.ui.UiUtils
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
@@ -20,14 +18,17 @@ import kotlinx.coroutines.launch
import java.util.logging.Logger
import javax.inject.Inject
@HiltAndroidApp
class App: Application(), Configuration.Provider {
/**
* The actual app should extend this class. The derived class must then be set
* as `@HiltAndroidApp.`
*/
open class CoreApp: Application() {
@Inject
lateinit var logger: Logger
/**
* Creates the [LogManager] singleton and thus initializes logging.
* Creates the [at.bitfire.davdroid.log.LogManager] singleton and thus initializes logging.
*/
@Inject
lateinit var logManager: LogManager
@@ -42,11 +43,6 @@ class App: Application(), Configuration.Provider {
@Inject
lateinit var workerFactory: HiltWorkerFactory
override val workManagerConfiguration: Configuration
get() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.build()
override fun onCreate() {
super.onCreate()
@@ -67,10 +63,10 @@ class App: Application(), Configuration.Provider {
@OptIn(DelicateCoroutinesApi::class)
GlobalScope.launch(defaultDispatcher) {
// clean up orphaned accounts in DB from time to time
AccountsCleanupWorker.enable(this@App)
AccountsCleanupWorker.Companion.enable(this@CoreApp)
// create/update app shortcuts
UiUtils.updateShortcuts(this@App)
UiUtils.updateShortcuts(this@CoreApp)
// run startup plugins (async)
for (plugin in plugins.sortedBy { it.priorityAsync() }) {

View File

@@ -12,7 +12,7 @@ interface StartupPlugin {
}
/**
* Runs synchronously during [at.bitfire.davdroid.App.onCreate]. Use only for tasks that must be completed before
* Runs synchronously during [at.bitfire.davdroid.CoreApp.onCreate]. Use only for tasks that must be completed before
* the app can run. Causes the app to start slower.
*
* Will be run before [onAppCreateAsync].
@@ -26,7 +26,7 @@ interface StartupPlugin {
/**
* Runs asynchronously after [at.bitfire.davdroid.App.onCreate]. Use for tasks that can be run in the background.
* Runs asynchronously after [at.bitfire.davdroid.CoreApp.onCreate]. Use for tasks that can be run in the background.
*
* Will be run after [onAppCreate].
*

View File

@@ -2,7 +2,7 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package com.davx5.ose.ui
package at.bitfire.davdroid.ui
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme

View File

@@ -2,7 +2,7 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package com.davx5.ose.ui.setup
package at.bitfire.davdroid.ui.setup
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
@@ -25,8 +25,6 @@ import at.bitfire.davdroid.ui.ExternalUris
import at.bitfire.davdroid.ui.ExternalUris.withStatParams
import at.bitfire.davdroid.ui.UiUtils.toAnnotatedString
import at.bitfire.davdroid.ui.composable.Assistant
import at.bitfire.davdroid.ui.setup.LoginInfo
import at.bitfire.davdroid.ui.setup.LoginType
@Composable
fun StandardLoginTypePage(

View File

@@ -2,22 +2,12 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package com.davx5.ose.ui.setup
package at.bitfire.davdroid.ui.setup
import android.content.Intent
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import at.bitfire.davdroid.ui.setup.AdvancedLogin
import at.bitfire.davdroid.ui.setup.EmailLogin
import at.bitfire.davdroid.ui.setup.FastmailLogin
import at.bitfire.davdroid.ui.setup.GoogleLogin
import at.bitfire.davdroid.ui.setup.LoginActivity
import at.bitfire.davdroid.ui.setup.LoginInfo
import at.bitfire.davdroid.ui.setup.LoginType
import at.bitfire.davdroid.ui.setup.LoginTypesProvider
import at.bitfire.davdroid.ui.setup.LoginTypesProvider.LoginAction
import at.bitfire.davdroid.ui.setup.NextcloudLogin
import at.bitfire.davdroid.ui.setup.UrlLogin
import java.util.logging.Logger
import javax.inject.Inject

View File

@@ -1,36 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--suppress AndroidUnknownAttribute -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="108"
android:viewportHeight="108"
android:width="108dp"
android:height="108dp">
<group
android:translateX="-213.3939"
android:translateY="-709.5244">
<group
android:scaleX="0.0662553"
android:scaleY="0.0662553"
android:translateX="233.5464"
android:translateY="729.8276">
<path
android:pathData="M282.78183 280.50711l-85.53115 -85.53116 -0.00001 228.08306 228.08306 0 -85.53115 -85.53114c94.36922 -94.36921 247.75506 -94.36951 342.12458 0.00001 28.79533 28.79533 49.03756 48.10677 59.87183 84.60006l83.25028 0c-12.82982 -57.30603 -41.34018 -96.85969 -86.10134 -141.62083 -126.01589 -126.0159 -330.15022 -126.0159 -456.1661 0zm399.14533 399.14532c-94.36952 94.36952 -247.75535 94.36921 -342.12458 0 -28.79562 -28.79564 -49.03816 -48.10677 -59.8718 -84.60006l-83.25029 0c12.82949 57.30571 41.33988 96.85938 86.10134 141.62083 126.01588 126.0159 330.15021 126.0159 456.1661 0l85.53115 85.53115 0.00001 -228.08305 -228.08307 0z"
android:fillColor="#ffffff" />
<path
android:pathData="M201.33878 550.34595l27.70423 0c25.78414 0 44.43649 -13.44067 44.43649 -44.98509 0 -31.54442 -18.65235 -44.16219 -45.80799 -44.16219l-26.33273 0zm23.58974 -18.92666l0 -51.29397 1.3715 0c12.89207 0 23.04114 4.38879 23.04114 25.23554 0 20.84675 -10.14907 26.05843 -23.04114 26.05843z"
android:fillColor="#ffffff" />
<path
android:pathData="M311.13854 507.00666c2.1944 -8.50328 4.38879 -19.20096 6.30889 -28.25283l0.5486 0c2.19439 8.91472 4.38879 19.74955 6.58318 28.25283l1.50865 6.17173 -16.45796 0zm-34.28741 43.33929l24.13834 0 4.38879 -18.92666 24.96124 0 4.38878 18.92666 24.96124 0 -27.15563 -89.14728 -28.52713 0z"
android:fillColor="#ffffff" />
<path
android:pathData="M380.56703 550.34595l28.52713 0 26.33273 -89.14728 -24.13834 0 -9.05188 38.9505c-2.33154 9.46333 -4.11449 18.65236 -6.58318 28.25283l-0.5486 0c-2.46869 -9.60047 -4.11449 -18.7895 -6.58318 -28.25283l-9.32618 -38.9505 -24.96124 0z"
android:fillColor="#ffffff" />
<path
android:pathData="M449.1301 596.08783l39.35586 0 6.19081 -15.47702c2.4321 -6.41191 5.0853 -12.82382 7.51741 -19.01463l0.8844 0c3.3165 6.19081 6.41191 12.82382 9.72841 19.01463l8.84401 15.47702 40.68246 0 -33.16504 -53.06408 31.39624 -57.48608 -39.35586 0 -5.3064 15.47703c-1.98991 6.1908 -4.64311 12.82381 -6.63301 19.01462l-0.8844 0c-2.87431 -6.19081 -5.96971 -12.82382 -8.84402 -19.01462l-7.95961 -15.47703 -40.68245 0 31.39624 53.06408z"
android:fillColor="#ffffff" />
<path
android:pathData="M601.43782 509.37229c18.53926 0 34.49164 -11.78465 34.49164 -32.19221 0 -19.25783 -13.50922 -28.16817 -29.3179 -28.16817 -3.01801 0 -5.46117 0.28743 -8.62291 1.43715l1.14972 -13.2218 32.76707 0 0 -20.69499 -54.03691 0 -2.29945 46.85116 10.63493 6.89832c5.46117 -3.44916 7.76062 -4.31145 12.64693 -4.31145 7.18576 0 12.35951 4.02402 12.35951 11.78464 0 8.04806 -4.88632 11.78465 -13.50923 11.78465 -6.6109 0 -12.93437 -3.73659 -18.39554 -8.62291l-10.92236 15.52124c7.47319 7.47319 18.10812 12.93437 33.0545 12.93437z"
android:fillColor="#ffffff" />
</group>
</group>
<?xml version="1.0" encoding="utf-8"?>
<!--suppress AndroidUnknownAttribute -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="108"
android:viewportHeight="108"
android:width="108dp"
android:height="108dp">
<group
android:translateX="-213.3939"
android:translateY="-709.5244">
<group
android:scaleX="0.0662553"
android:scaleY="0.0662553"
android:translateX="233.5464"
android:translateY="729.8276">
<path
android:pathData="M282.78183 280.50711l-85.53115 -85.53116 -0.00001 228.08306 228.08306 0 -85.53115 -85.53114c94.36922 -94.36921 247.75506 -94.36951 342.12458 0.00001 28.79533 28.79533 49.03756 48.10677 59.87183 84.60006l83.25028 0c-12.82982 -57.30603 -41.34018 -96.85969 -86.10134 -141.62083 -126.01589 -126.0159 -330.15022 -126.0159 -456.1661 0zm399.14533 399.14532c-94.36952 94.36952 -247.75535 94.36921 -342.12458 0 -28.79562 -28.79564 -49.03816 -48.10677 -59.8718 -84.60006l-83.25029 0c12.82949 57.30571 41.33988 96.85938 86.10134 141.62083 126.01588 126.0159 330.15021 126.0159 456.1661 0l85.53115 85.53115 0.00001 -228.08305 -228.08307 0z"
android:fillColor="#ffffff" />
<path
android:pathData="M201.33878 550.34595l27.70423 0c25.78414 0 44.43649 -13.44067 44.43649 -44.98509 0 -31.54442 -18.65235 -44.16219 -45.80799 -44.16219l-26.33273 0zm23.58974 -18.92666l0 -51.29397 1.3715 0c12.89207 0 23.04114 4.38879 23.04114 25.23554 0 20.84675 -10.14907 26.05843 -23.04114 26.05843z"
android:fillColor="#ffffff" />
<path
android:pathData="M311.13854 507.00666c2.1944 -8.50328 4.38879 -19.20096 6.30889 -28.25283l0.5486 0c2.19439 8.91472 4.38879 19.74955 6.58318 28.25283l1.50865 6.17173 -16.45796 0zm-34.28741 43.33929l24.13834 0 4.38879 -18.92666 24.96124 0 4.38878 18.92666 24.96124 0 -27.15563 -89.14728 -28.52713 0z"
android:fillColor="#ffffff" />
<path
android:pathData="M380.56703 550.34595l28.52713 0 26.33273 -89.14728 -24.13834 0 -9.05188 38.9505c-2.33154 9.46333 -4.11449 18.65236 -6.58318 28.25283l-0.5486 0c-2.46869 -9.60047 -4.11449 -18.7895 -6.58318 -28.25283l-9.32618 -38.9505 -24.96124 0z"
android:fillColor="#ffffff" />
<path
android:pathData="M449.1301 596.08783l39.35586 0 6.19081 -15.47702c2.4321 -6.41191 5.0853 -12.82382 7.51741 -19.01463l0.8844 0c3.3165 6.19081 6.41191 12.82382 9.72841 19.01463l8.84401 15.47702 40.68246 0 -33.16504 -53.06408 31.39624 -57.48608 -39.35586 0 -5.3064 15.47703c-1.98991 6.1908 -4.64311 12.82381 -6.63301 19.01462l-0.8844 0c-2.87431 -6.19081 -5.96971 -12.82382 -8.84402 -19.01462l-7.95961 -15.47703 -40.68245 0 31.39624 53.06408z"
android:fillColor="#ffffff" />
<path
android:pathData="M601.43782 509.37229c18.53926 0 34.49164 -11.78465 34.49164 -32.19221 0 -19.25783 -13.50922 -28.16817 -29.3179 -28.16817 -3.01801 0 -5.46117 0.28743 -8.62291 1.43715l1.14972 -13.2218 32.76707 0 0 -20.69499 -54.03691 0 -2.29945 46.85116 10.63493 6.89832c5.46117 -3.44916 7.76062 -4.31145 12.64693 -4.31145 7.18576 0 12.35951 4.02402 12.35951 11.78464 0 8.04806 -4.88632 11.78465 -13.50923 11.78465 -6.6109 0 -12.93437 -3.73659 -18.39554 -8.62291l-10.92236 15.52124c7.47319 7.47319 18.10812 12.93437 33.0545 12.93437z"
android:fillColor="#ffffff" />
</group>
</group>
</vector>

View File

@@ -3,23 +3,21 @@
*/
pluginManagement {
repositories {
google()
mavenCentral()
// AboutLibraries
maven("https://plugins.gradle.org/m2/")
repositories { // used for resolving plugins
google() // Android plugins
gradlePluginPortal() // most plugins, including AboutLibraries
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
// Repositories declared in settings.gradle(.kts) override those declared in a project.
repositoriesMode = RepositoriesMode.PREFER_SETTINGS
// AppIntro, dav4jvm
maven("https://jitpack.io")
repositories { // used for resolving dependencies
mavenCentral() // most Java stuff
google() // Android libs
maven("https://jitpack.io") // AppIntro, dav4jvm, synctools
}
}
@@ -38,5 +36,5 @@ if (!buildCacheUrl.isNullOrEmpty()) {
}
}
include(":app-ose")
include(":core")
include(":app")