Compare commits

..

17 Commits

Author SHA1 Message Date
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
Ricki Hirner
5e84648fb4 Replace BuildConfig.allowCustomCerts by DI (#1971)
* Update IntroScreen colors

- Replace M3ColorScheme with MaterialTheme.colorScheme
- Update background and icon colors to use MaterialTheme

* Update color scheme references

- Replace `M3ColorScheme.primaryLight` with `MaterialTheme.colorScheme.primary` in `WelcomePage.kt` and `AccountsDrawerHandler.kt`.

* Update AppTheme to accept custom color schemes

- Add `lightColorScheme` and `darkColorScheme` parameters
- Replace hardcoded color schemes with the new parameters

* Add color scheme dependency injection

- Add `LightColorScheme` and `DarkColorScheme` qualifiers
- Create `OseColorSchemes` module for providing color schemes
- Update `AppTheme` to use injected color schemes

* Update glance material dependency to material3

- Update `androidx.glance.material` to `androidx.glance.material3`
- Adjust imports and usage in `IconSyncButtonWidget.kt` and `LabeledSyncButtonWidget.kt` to use `GlanceTheme` and `ColorProviders` for color schemes
- Replace deprecated `ColorProvider` with `GlanceTheme.colors` for primary and onPrimary colors

* Refactor widget receivers and widgets to use dependency injection more properly

- Update `LabeledSyncButtonWidgetReceiver` and `IconSyncButtonWidgetReceiver` to use Hilt for dependency injection.
- Inject `SyncWidgetModel`, `LightColorScheme`, and `DarkColorScheme` into both widget receivers.
- Remove the use of `EntryPoint` and `EntryPointAccessors` from `LabeledSyncButtonWidget` and `IconSyncButtonWidget`.
- Pass injected dependencies directly to the widget constructors.

* Rename ThemeColors to OseTheme

- Update imports and references to use OseTheme
- Rename object M3ColorScheme to OseTheme

* Move AppTheme to ui.composable package because it's a reusable Composable

* Update AboutApp to use dynamic version info instead of BuildConfig

- Pass versionName and versionCode from AboutModel to AboutApp
- Remove dependency on BuildConfig in AboutApp
- Update AboutApp_Preview with sample version info

* Update URI statistics parameters

- Update `withStatParams` to include package name and version
- Replace `BuildConfig.APPLICATION_ID` with `context.packageName`
- Add context parameter to `withStatParams` in various activities

* Don't depend on BuildConfig for application name and version

- Introduce `ProductIds` for managing product IDs and User-Agent
- Update various classes to use `ProductIds` for product ID generation
- Move `TextTable` class from `at.bitfire.davdroid` to `at.bitfire.davdroid.util`

* Refactor OAuth classes for dependency injection

- Convert `OAuthFastmail` and `OAuthGoogle` to injectable classes
- Update `FastmailLoginModel` and `GoogleLoginModel` to use injected instances
- Move `redirectUri` initialization to `OAuthIntegration` constructor

* Adapt DI

- Move CustomCertManagerModule to ose configuration
- Move coroutine scopes to scope package

* minor changes

* Remove custom certificate build config

- Remove `allowCustomCerts` build config field
- Replace `@Singleton` with `@Reusable` in CustomCertManagerModule

* Update imports and LogcatHandler initialization

- Update imports to use scoped dispatchers
- Replace BuildConfig.APPLICATION_ID with javaClass.name in LogcatHandler initialization
2026-02-05 13:59:31 +01:00
Ricki Hirner
490abcb88a Reduce BuildConfig dependencies (#1969)
* Update IntroScreen colors

- Replace M3ColorScheme with MaterialTheme.colorScheme
- Update background and icon colors to use MaterialTheme

* Update color scheme references

- Replace `M3ColorScheme.primaryLight` with `MaterialTheme.colorScheme.primary` in `WelcomePage.kt` and `AccountsDrawerHandler.kt`.

* Update AppTheme to accept custom color schemes

- Add `lightColorScheme` and `darkColorScheme` parameters
- Replace hardcoded color schemes with the new parameters

* Add color scheme dependency injection

- Add `LightColorScheme` and `DarkColorScheme` qualifiers
- Create `OseColorSchemes` module for providing color schemes
- Update `AppTheme` to use injected color schemes

* Update glance material dependency to material3

- Update `androidx.glance.material` to `androidx.glance.material3`
- Adjust imports and usage in `IconSyncButtonWidget.kt` and `LabeledSyncButtonWidget.kt` to use `GlanceTheme` and `ColorProviders` for color schemes
- Replace deprecated `ColorProvider` with `GlanceTheme.colors` for primary and onPrimary colors

* Refactor widget receivers and widgets to use dependency injection more properly

- Update `LabeledSyncButtonWidgetReceiver` and `IconSyncButtonWidgetReceiver` to use Hilt for dependency injection.
- Inject `SyncWidgetModel`, `LightColorScheme`, and `DarkColorScheme` into both widget receivers.
- Remove the use of `EntryPoint` and `EntryPointAccessors` from `LabeledSyncButtonWidget` and `IconSyncButtonWidget`.
- Pass injected dependencies directly to the widget constructors.

* Rename ThemeColors to OseTheme

- Update imports and references to use OseTheme
- Rename object M3ColorScheme to OseTheme

* Move AppTheme to ui.composable package because it's a reusable Composable

* Update AboutApp to use dynamic version info instead of BuildConfig

- Pass versionName and versionCode from AboutModel to AboutApp
- Remove dependency on BuildConfig in AboutApp
- Update AboutApp_Preview with sample version info

* Update URI statistics parameters

- Update `withStatParams` to include package name and version
- Replace `BuildConfig.APPLICATION_ID` with `context.packageName`
- Add context parameter to `withStatParams` in various activities

* Don't depend on BuildConfig for application name and version

- Introduce `ProductIds` for managing product IDs and User-Agent
- Update various classes to use `ProductIds` for product ID generation
- Move `TextTable` class from `at.bitfire.davdroid` to `at.bitfire.davdroid.util`

* Refactor OAuth classes for dependency injection

- Convert `OAuthFastmail` and `OAuthGoogle` to injectable classes
- Update `FastmailLoginModel` and `GoogleLoginModel` to use injected instances
- Move `redirectUri` initialization to `OAuthIntegration` constructor
2026-02-05 12:20:21 +01:00
Ricki Hirner
cca12e79d8 [UI] Properly provide color schemes over DI (#1966)
* Update IntroScreen colors

- Replace M3ColorScheme with MaterialTheme.colorScheme
- Update background and icon colors to use MaterialTheme

* Update color scheme references

- Replace `M3ColorScheme.primaryLight` with `MaterialTheme.colorScheme.primary` in `WelcomePage.kt` and `AccountsDrawerHandler.kt`.

* Update AppTheme to accept custom color schemes

- Add `lightColorScheme` and `darkColorScheme` parameters
- Replace hardcoded color schemes with the new parameters

* Add color scheme dependency injection

- Add `LightColorScheme` and `DarkColorScheme` qualifiers
- Create `OseColorSchemes` module for providing color schemes
- Update `AppTheme` to use injected color schemes

* Update glance material dependency to material3

- Update `androidx.glance.material` to `androidx.glance.material3`
- Adjust imports and usage in `IconSyncButtonWidget.kt` and `LabeledSyncButtonWidget.kt` to use `GlanceTheme` and `ColorProviders` for color schemes
- Replace deprecated `ColorProvider` with `GlanceTheme.colors` for primary and onPrimary colors

* Refactor widget receivers and widgets to use dependency injection more properly

- Update `LabeledSyncButtonWidgetReceiver` and `IconSyncButtonWidgetReceiver` to use Hilt for dependency injection.
- Inject `SyncWidgetModel`, `LightColorScheme`, and `DarkColorScheme` into both widget receivers.
- Remove the use of `EntryPoint` and `EntryPointAccessors` from `LabeledSyncButtonWidget` and `IconSyncButtonWidget`.
- Pass injected dependencies directly to the widget constructors.

* Rename ThemeColors to OseTheme

- Update imports and references to use OseTheme
- Rename object M3ColorScheme to OseTheme

* Move AppTheme to ui.composable package because it's a reusable Composable

* Always use Light Color Scheme for certain intro UI

- Inject `lightColorScheme` in `IntroActivity`
- Pass `lightColorScheme` to `IntroScreen`
- Use `lightColorScheme` for background and color in `IntroScreen` and `WelcomePage`

* Minor syntax
2026-02-05 11:43:55 +01:00
Ricki Hirner
915cf73027 Update version to 4.5.9 2026-02-04 10:58:57 +01:00
Ricki Hirner
53773eaf83 Go back to 4.5.9-rc.2 (4.5.9 with version code 405090003 was never released) 2026-02-03 16:00:55 +01:00
Ricki Hirner
9cd685982d Update synctools to correctly process tel: URIs in vCards (#1963) 2026-02-03 15:59:46 +01:00
Sunik Kupfer
d4902e84ce [synctools] Tasks rewrite: Use reader/writer (#1959)
* Update synctools; Use writer/reader

Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>

* Update synctools

Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>

---------

Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
2026-02-03 15:22:15 +01:00
dependabot[bot]
ec485fcfa5 Bump the app-dependencies group with 8 updates (#1961)
Bumps the app-dependencies group with 8 updates:

| Package | From | To |
| --- | --- | --- |
| gradle-wrapper | `9.3.0` | `9.3.1` |
| androidx.activity:activity-compose | `1.12.2` | `1.12.3` |
| androidx.compose:compose-bom | `2026.01.00` | `2026.01.01` |
| androidx.paging:paging-runtime-ktx | `3.3.6` | `3.4.0` |
| androidx.paging:paging-compose | `3.3.6` | `3.4.0` |
| androidx.work:work-runtime-ktx | `2.11.0` | `2.11.1` |
| androidx.work:work-testing | `2.11.0` | `2.11.1` |
| [com.google.devtools.ksp](https://github.com/google/ksp) | `2.3.4` | `2.3.5` |


Updates `gradle-wrapper` from 9.3.0 to 9.3.1

Updates `androidx.activity:activity-compose` from 1.12.2 to 1.12.3

Updates `androidx.compose:compose-bom` from 2026.01.00 to 2026.01.01

Updates `androidx.paging:paging-runtime-ktx` from 3.3.6 to 3.4.0

Updates `androidx.paging:paging-compose` from 3.3.6 to 3.4.0

Updates `androidx.paging:paging-compose` from 3.3.6 to 3.4.0

Updates `androidx.work:work-runtime-ktx` from 2.11.0 to 2.11.1

Updates `androidx.work:work-testing` from 2.11.0 to 2.11.1

Updates `androidx.work:work-testing` from 2.11.0 to 2.11.1

Updates `com.google.devtools.ksp` from 2.3.4 to 2.3.5
- [Release notes](https://github.com/google/ksp/releases)
- [Commits](https://github.com/google/ksp/compare/2.3.4...2.3.5)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: androidx.activity:activity-compose
  dependency-version: 1.12.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: androidx.compose:compose-bom
  dependency-version: 2026.01.01
  dependency-type: direct:production
  dependency-group: app-dependencies
- dependency-name: androidx.paging:paging-runtime-ktx
  dependency-version: 3.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: app-dependencies
- dependency-name: androidx.paging:paging-compose
  dependency-version: 3.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: app-dependencies
- dependency-name: androidx.paging:paging-compose
  dependency-version: 3.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: app-dependencies
- dependency-name: androidx.work:work-runtime-ktx
  dependency-version: 2.11.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: androidx.work:work-testing
  dependency-version: 2.11.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: androidx.work:work-testing
  dependency-version: 2.11.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: com.google.devtools.ksp
  dependency-version: 2.3.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-03 14:57:10 +01:00
Ricki Hirner
5709aaa2e5 Bump version to 4.5.9 2026-02-03 12:12:05 +01:00
Ricki Hirner
a19c397ef6 Sync files with davx5 repo (#1958)
* Sync changes with davx5 repo

* Remove unnecessary test launcher icons
2026-02-02 12:30:04 +01:00
540 changed files with 967 additions and 572 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 app:testOseDebugUnitTest
./gradlew --dry-run core:virtualDebugAndroidTest app:virtualOseDebugAndroidTest
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 app:testOseDebugUnitTest
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 app:virtualOseDebugAndroidTest
- 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 module
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,11 @@
<?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"
android:installLocation="internalOnly">
<application android:name=".App"/>
</manifest>

View File

@@ -2,12 +2,12 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid
package com.davx5.ose
import android.app.Application
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import at.bitfire.davdroid.di.DefaultDispatcher
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
@@ -27,7 +27,7 @@ class App: Application(), Configuration.Provider {
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
@@ -67,7 +67,7 @@ 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@App)
// create/update app shortcuts
UiUtils.updateShortcuts(this@App)

View File

@@ -1,8 +1,8 @@
/***************************************************************************************************
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
*/
package at.bitfire.davdroid
package com.davx5.ose
import android.content.Context
import at.bitfire.davdroid.ui.DebugInfoActivity

View File

@@ -0,0 +1,28 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
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 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

@@ -2,63 +2,60 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.di
package com.davx5.ose.di
import android.content.Context
import at.bitfire.cert4android.CustomCertManager
import at.bitfire.cert4android.CustomCertStore
import at.bitfire.cert4android.SettingsProvider
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.settings.Settings
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.ForegroundTracker
import dagger.Module
import dagger.Provides
import dagger.Reusable
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import okhttp3.internal.tls.OkHostnameVerifier
import java.util.Optional
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
/**
* cert4android integration module
*/
@Module
@InstallIn(SingletonComponent::class)
class CustomCertManagerModule {
@Provides
@Singleton
fun customCertManager(
@ApplicationContext context: Context,
settings: SettingsManager
): Optional<CustomCertManager> =
if (BuildConfig.allowCustomCerts)
Optional.of(CustomCertManager(
certStore = CustomCertStore.getInstance(context),
settings = object : SettingsProvider {
override val appInForeground: Boolean
get() = ForegroundTracker.inForeground.value
override val trustSystemCerts: Boolean
get() = !settings.getBoolean(Settings.DISTRUST_SYSTEM_CERTIFICATES)
}
))
else
Optional.empty()
fun customCertStore(@ApplicationContext context: Context): Optional<CustomCertStore> =
Optional.of(CustomCertStore.getInstance(context))
@Provides
@Singleton
@Reusable
fun customCertManager(
customCertStore: Optional<CustomCertStore>,
settings: SettingsManager
): Optional<CustomCertManager> =
Optional.of(
CustomCertManager(
certStore = customCertStore.get(),
settings = object : SettingsProvider {
override val appInForeground: Boolean
get() = ForegroundTracker.inForeground.value
override val trustSystemCerts: Boolean
get() = !settings.getBoolean(Settings.DISTRUST_SYSTEM_CERTIFICATES)
}
))
@Provides
@Reusable
fun customHostnameVerifier(
customCertManager: Optional<CustomCertManager>
): Optional<CustomCertManager.HostnameVerifier> =
if (BuildConfig.allowCustomCerts && customCertManager.isPresent) {
val hostnameVerifier = customCertManager.get().HostnameVerifier(OkHostnameVerifier)
Optional.of(hostnameVerifier)
} else
Optional.empty()
Optional.of(customCertManager.get().HostnameVerifier(OkHostnameVerifier))
}

View File

@@ -2,17 +2,15 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.di
package com.davx5.ose.di
import at.bitfire.davdroid.push.DistributorPreferencesProvider
import at.bitfire.davdroid.push.PushRegistrationManager
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.OpenSourceLicenseInfoProvider
import at.bitfire.davdroid.ui.intro.IntroPageFactory
import at.bitfire.davdroid.ui.intro.OseIntroPageFactory
import at.bitfire.davdroid.ui.setup.LoginTypesProvider
import com.davx5.ose.ui.about.OpenSourceLicenseInfoProvider
import com.davx5.ose.ui.intro.OseIntroPageFactory
import at.bitfire.davdroid.ui.setup.StandardLoginTypesProvider
import dagger.Binds
import dagger.Module
@@ -48,9 +46,6 @@ interface OseModules {
interface Global {
@Binds
fun introPageFactory(impl: OseIntroPageFactory): IntroPageFactory
@Binds
fun pushDistributorPreferences(impl: DistributorPreferencesProvider): PushRegistrationManager.DistributorPreferences
}
}

View File

@@ -2,9 +2,9 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.ui.about
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,13 +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
@@ -40,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

@@ -2,8 +2,15 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.ui.intro
package com.davx5.ose.ui.intro
import at.bitfire.davdroid.ui.intro.BackupsPage
import at.bitfire.davdroid.ui.intro.BatteryOptimizationsPage
import at.bitfire.davdroid.ui.intro.IntroPageFactory
import at.bitfire.davdroid.ui.intro.OpenSourcePage
import at.bitfire.davdroid.ui.intro.PermissionsIntroPage
import at.bitfire.davdroid.ui.intro.TasksIntroPage
import at.bitfire.davdroid.ui.intro.WelcomePage
import javax.inject.Inject
class OseIntroPageFactory @Inject constructor(

1
app/src/.gitignore vendored
View File

@@ -1 +0,0 @@
espressoTest

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,22 +0,0 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid
import at.bitfire.synctools.icalendar.ical4jVersion
import ezvcard.Ezvcard
/**
* Brand-specific constants like (non-theme) colors, homepage URLs etc.
*/
object Constants {
const val DAVDROID_GREEN_RGBA = 0xFF8bc34a.toInt()
// product IDs for iCalendar/vCard
val iCalProdId = "DAVx5/${BuildConfig.VERSION_NAME} ical4j/$ical4jVersion"
const val vCardProdId = "+//IDN bitfire.at//DAVx5/${BuildConfig.VERSION_NAME} ez-vcard/${Ezvcard.VERSION}"
}

View File

@@ -1,78 +0,0 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.push
import android.content.Context
import at.bitfire.davdroid.push.PushRegistrationManager.DistributorPreferences
import at.bitfire.davdroid.settings.Settings.EXPLICIT_PUSH_DISABLE
import at.bitfire.davdroid.settings.SettingsManager
import dagger.hilt.android.qualifiers.ApplicationContext
import org.unifiedpush.android.connector.UnifiedPush
import java.util.logging.Logger
import javax.inject.Inject
class PushDistributorManager @Inject constructor(
@ApplicationContext private val context: Context,
private val logger: Logger,
private val settings: SettingsManager,
private val distributorPreferences: DistributorPreferences,
) {
/**
* Get the distributor registered by the user.
* @return The distributor package name if any, else `null`.
*/
fun getCurrentDistributor() = UnifiedPush.getSavedDistributor(context)
/**
* Get a list of available distributors installed on the system.
* @return The list of distributor's package name.
*/
fun getDistributors() = UnifiedPush.getDistributors(context)
/**
* Sets or removes (disable push) the distributor.
*
* @param pushDistributor new distributor or `null` to disable Push
*/
fun setPushDistributor(pushDistributor: String?) {
// Disable UnifiedPush and remove all subscriptions
UnifiedPush.removeDistributor(context)
update()
if (pushDistributor != null) {
// If a distributor was passed, store it and create/register subscriptions
UnifiedPush.saveDistributor(context, pushDistributor)
update()
}
}
/**
* Makes sure a distributor is selected if Push is enabled.
*
* Uses preferences from [distributorPreferences].
*/
fun update() {
val currentDistributor = getCurrentDistributor()
val isPushDisabled = settings.getBooleanOrNull(EXPLICIT_PUSH_DISABLE)
if (currentDistributor == null) {
if (isPushDisabled == true) {
logger.info("Push is explicitly disabled, no distributor will be selected.")
} else {
val availableDistributors = getDistributors()
if (availableDistributors.isNotEmpty()) {
logger.fine("No Push distributor selected, but ${availableDistributors.size} distributors are available.")
// select preferred distributor if available, otherwise first available
val distributor = distributorPreferences.packageNames.firstNotNullOfOrNull { preferredPackageName ->
availableDistributors.find { it == preferredPackageName }
} ?: availableDistributors.first()
logger.fine("Automatically selecting Push distributor: $distributor")
UnifiedPush.saveDistributor(context, distributor)
} else {
logger.fine("No Push distributor selected and no distributors are available.")
}
}
}
}
}

View File

@@ -1,12 +0,0 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.ui.widget
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
class IconSyncButtonWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = IconSyncButtonWidget()
}

View File

@@ -1,12 +0,0 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.ui.widget
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
class LabeledSyncButtonWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = LabeledSyncButtonWidget()
}

View File

@@ -1,12 +0,0 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.push
import javax.inject.Inject
class DistributorPreferencesProvider @Inject constructor() : PushRegistrationManager.DistributorPreferences {
// No special preferences for OSE flavor, select the first distributor available
override val packageNames: List<String> = emptyList()
}

View File

@@ -4,6 +4,7 @@
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

View File

View File

@@ -3,7 +3,7 @@
*/
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.android.library)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.hilt)
alias(libs.plugins.kotlin.serialization)
@@ -16,18 +16,7 @@ android {
compileSdk = 36
defaultConfig {
applicationId = "at.bitfire.davdroid"
versionCode = 405090002
versionName = "4.5.9-rc.1"
base.archivesName = "davx5-ose-$versionName"
minSdk = 24 // Android 7.0
targetSdk = 36 // Android 16
// whether the build supports and allows to use custom certificates
buildConfigField("boolean", "allowCustomCerts", "true")
testInstrumentationRunner = "at.bitfire.davdroid.HiltTestRunner"
}
@@ -53,37 +42,9 @@ android {
// Java namespace for our classes (not to be confused with Android package ID)
namespace = "at.bitfire.davdroid"
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")
isMinifyEnabled = false
}
}
@@ -91,10 +52,6 @@ android {
disable += arrayOf("GoogleAppIndexingWarning", "ImpliedQuantity", "MissingQuantity", "MissingTranslation", "ExtraTranslation", "RtlEnabled", "RtlHardcoded", "Typos")
}
androidResources {
generateLocaleConfig = true
}
packaging {
resources {
// multiple (test) dependencies have LICENSE files at same location
@@ -102,6 +59,12 @@ android {
}
}
sourceSets {
getByName("androidTest") {
assets.srcDir("$projectDir/schemas")
}
}
@Suppress("UnstableApiUsage")
testOptions {
managedDevices {
@@ -130,7 +93,7 @@ aboutLibraries {
}
dependencies {
// core
// Kotlin / Android
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines)
coreLibraryDesugaring(libs.android.desugaring)
@@ -167,7 +130,7 @@ dependencies {
// Glance Widgets
implementation(libs.androidx.glance.base)
implementation(libs.androidx.glance.material)
implementation(libs.androidx.glance.material3)
// Jetpack Room
implementation(libs.androidx.room.runtime)

View File

View File

@@ -10,7 +10,6 @@ import android.os.Build
import android.os.Bundle
import androidx.test.runner.AndroidJUnitRunner
import at.bitfire.davdroid.di.TestCoroutineDispatchersModule
import at.bitfire.davdroid.test.BuildConfig
import at.bitfire.synctools.log.LogcatHandler
import dagger.hilt.android.testing.HiltTestApplication
import java.util.logging.Level
@@ -29,7 +28,7 @@ class HiltTestRunner : AndroidJUnitRunner() {
val rootLogger = Logger.getLogger("")
rootLogger.level = Level.ALL
rootLogger.handlers.forEach { rootLogger.removeHandler(it) }
rootLogger.addHandler(LogcatHandler(BuildConfig.APPLICATION_ID))
rootLogger.addHandler(LogcatHandler(javaClass.name))
// MockK requirements
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)

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

@@ -5,6 +5,10 @@
package at.bitfire.davdroid.di
import at.bitfire.davdroid.di.TestCoroutineDispatchersModule.standardTestDispatcher
import at.bitfire.davdroid.di.scope.DefaultDispatcher
import at.bitfire.davdroid.di.scope.IoDispatcher
import at.bitfire.davdroid.di.scope.MainDispatcher
import at.bitfire.davdroid.di.scope.SyncDispatcher
import dagger.Module
import dagger.Provides
import dagger.hilt.components.SingletonComponent

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
}
}

Some files were not shown because too many files have changed in this diff Show More