* Lint

* Optimize imports

* Icon
This commit is contained in:
Ricki Hirner 2024-01-31 13:09:15 +01:00 committed by GitHub
parent b2d06a491d
commit 95d098541f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
77 changed files with 252 additions and 245 deletions

View file

@ -15,11 +15,12 @@ import org.junit.Assert.assertTrue
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import kotlin.math.abs
object TestUtils {
fun assertWithin(expected: Long, actual: Long, tolerance: Long) {
val absDifference = Math.abs(expected - actual)
val absDifference = abs(expected - actual)
assertTrue(
"$actual not within ($expected ± $tolerance)",
absDifference <= tolerance

View file

@ -14,10 +14,10 @@ class DebugInfoActivityTest {
fun testIntentBuilder_LargeLocalResource() {
val a = 'A'.code.toByte()
val intent = DebugInfoActivity.IntentBuilder(InstrumentationRegistry.getInstrumentation().context)
.withLocalResource(String(ByteArray(1024*1024, { a })))
.withLocalResource(String(ByteArray(1024*1024) { a }))
.build()
val expected = StringBuilder(DebugInfoActivity.IntentBuilder.MAX_ELEMENT_SIZE)
expected.append(String(ByteArray(DebugInfoActivity.IntentBuilder.MAX_ELEMENT_SIZE - 3, { a })))
expected.append(String(ByteArray(DebugInfoActivity.IntentBuilder.MAX_ELEMENT_SIZE - 3) { a }))
expected.append("...")
assertEquals(expected.toString(), intent.getStringExtra("localResource"))
}
@ -26,10 +26,10 @@ class DebugInfoActivityTest {
fun testIntentBuilder_LargeLogs() {
val a = 'A'.code.toByte()
val intent = DebugInfoActivity.IntentBuilder(InstrumentationRegistry.getInstrumentation().context)
.withLogs(String(ByteArray(1024*1024, { a })))
.withLogs(String(ByteArray(1024*1024) { a }))
.build()
val expected = StringBuilder(DebugInfoActivity.IntentBuilder.MAX_ELEMENT_SIZE)
expected.append(String(ByteArray(DebugInfoActivity.IntentBuilder.MAX_ELEMENT_SIZE - 3, { a })))
expected.append(String(ByteArray(DebugInfoActivity.IntentBuilder.MAX_ELEMENT_SIZE - 3) { a }))
expected.append("...")
assertEquals(expected.toString(), intent.getStringExtra("logs"))
}

View file

@ -19,7 +19,7 @@ class LocalTestCollection: LocalCollection<LocalTestResource> {
override fun findDeleted() = entries.filter { it.deleted }
override fun findDirty() = entries.filter { it.dirty }
override fun findByName(name: String) = entries.filter { it.fileName == name }.firstOrNull()
override fun findByName(name: String) = entries.firstOrNull { it.fileName == name }
override fun markNotDirty(flags: Int): Int {
var updated = 0

View file

@ -146,24 +146,26 @@ class SyncManagerTest {
private fun queryCapabilitiesResponse(cTag: String? = null): MockResponse {
val body = StringBuilder()
body.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
"<multistatus xmlns=\"DAV:\" xmlns:CALDAV=\"http://calendarserver.org/ns/\">\n" +
" <response>\n" +
" <href>/</href>\n" +
" <propstat>\n" +
" <prop>\n")
if (cTag != null)
body.append("<CALDAV:getctag>$cTag</CALDAV:getctag>\n")
body.append(
" </prop>\n" +
" </propstat>\n" +
" </response>\n" +
"</multistatus>")
val response = MockResponse()
.setResponseCode(207)
.setHeader("Content-Type", "text/xml")
.setBody(body.toString())
return response
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
"<multistatus xmlns=\"DAV:\" xmlns:CALDAV=\"http://calendarserver.org/ns/\">\n" +
" <response>\n" +
" <href>/</href>\n" +
" <propstat>\n" +
" <prop>\n"
)
if (cTag != null)
body.append("<CALDAV:getctag>$cTag</CALDAV:getctag>\n")
body.append(
" </prop>\n" +
" </propstat>\n" +
" </response>\n" +
"</multistatus>"
)
return MockResponse()
.setResponseCode(207)
.setHeader("Content-Type", "text/xml")
.setBody(body.toString())
}
@Test

View file

@ -82,7 +82,7 @@ class TestSyncManager(
for ((url, eTag) in assertDownloadRemote) {
val fileName = DavUtils.lastSegmentOfUrl(url)
var localEntry = localCollection.entries.filter { it.fileName == fileName }.firstOrNull()
var localEntry = localCollection.entries.firstOrNull { it.fileName == fileName }
if (localEntry == null) {
val newEntry = LocalTestResource().also {
it.fileName = fileName

View file

@ -74,7 +74,6 @@
<activity android:name=".ui.intro.IntroActivity" android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".ui.AccountsActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"
android:exported="true">
<intent-filter>
@ -245,7 +244,8 @@
<!-- account type "DAVx⁵ Address book" -->
<service
android:name=".syncadapter.AddressBookAuthenticatorService"
android:exported="true"> <!-- Since Android 11, this must be true so that Google Contacts shows the address book accounts -->
android:exported="true"
tools:ignore="ExportedService"> <!-- Since Android 11, this must be true so that Google Contacts shows the address book accounts -->
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/>
</intent-filter>

View file

@ -5,7 +5,7 @@
package at.bitfire.davdroid
import org.apache.commons.lang3.StringUtils
import java.util.*
import java.util.Collections
class TextTable(
vararg val headers: String

View file

@ -6,7 +6,13 @@ package at.bitfire.davdroid.db
import androidx.lifecycle.LiveData
import androidx.paging.PagingSource
import androidx.room.*
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
@Dao
interface CollectionDao {

View file

@ -5,7 +5,12 @@
package at.bitfire.davdroid.db
import androidx.lifecycle.LiveData
import androidx.room.*
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
@Dao
interface HomeSetDao {

View file

@ -5,7 +5,11 @@
package at.bitfire.davdroid.db
import androidx.lifecycle.LiveData
import androidx.room.*
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import okhttp3.HttpUrl
@Dao

View file

@ -17,8 +17,6 @@ import at.bitfire.davdroid.webdav.DocumentState
import okhttp3.HttpUrl
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.digester.Digester
import java.io.FileNotFoundException
import java.time.Instant

View file

@ -5,7 +5,13 @@
package at.bitfire.davdroid.db
import androidx.lifecycle.LiveData
import androidx.room.*
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
@Dao
interface WebDavDocumentDao {

View file

@ -4,7 +4,6 @@
package at.bitfire.davdroid.di
import at.bitfire.davdroid.log.Logger
import dagger.hilt.DefineComponent
import dagger.hilt.components.SingletonComponent
import java.lang.ref.WeakReference

View file

@ -7,7 +7,7 @@ package at.bitfire.davdroid.log
import org.apache.commons.lang3.StringUtils
import org.apache.commons.lang3.exception.ExceptionUtils
import org.apache.commons.lang3.time.DateFormatUtils
import java.util.*
import java.util.Locale
import java.util.logging.Formatter
import java.util.logging.LogRecord

View file

@ -6,7 +6,6 @@ package at.bitfire.davdroid.network
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import androidx.annotation.RequiresApi
import at.bitfire.davdroid.log.Logger
import java.util.logging.Level
@ -40,7 +39,6 @@ object ConnectionUtils {
* @param ignoreVpns *true* filters VPN connections in the Internet check; *false* allows them as valid connection
* @return whether we are connected to the Internet
*/
@RequiresApi(23)
internal fun internetAvailable(connectivityManager: ConnectivityManager, ignoreVpns: Boolean): Boolean {
return connectivityManager.allNetworks.any { network ->
val capabilities = connectivityManager.getNetworkCapabilities(network)

View file

@ -10,7 +10,7 @@ import okhttp3.HttpUrl
import org.apache.commons.collections4.keyvalue.MultiKey
import org.apache.commons.collections4.map.HashedMap
import org.apache.commons.collections4.map.MultiKeyMap
import java.util.*
import java.util.LinkedList
/**
* Primitive cookie store that stores cookies in a (volatile) hash map.

View file

@ -12,16 +12,16 @@ import android.net.Uri
import android.provider.CalendarContract.Calendars
import android.provider.CalendarContract.Events
import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.util.DavUtils
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.SyncState
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.util.DavUtils
import at.bitfire.ical4android.AndroidCalendar
import at.bitfire.ical4android.AndroidCalendarFactory
import at.bitfire.ical4android.BatchOperation
import at.bitfire.ical4android.util.DateUtils
import at.bitfire.ical4android.util.MiscUtils.asSyncAdapter
import java.util.*
import java.util.LinkedList
import java.util.logging.Level
class LocalCalendar private constructor(

View file

@ -11,11 +11,17 @@ import android.content.ContentValues
import android.provider.CalendarContract
import android.provider.CalendarContract.Events
import at.bitfire.davdroid.BuildConfig
import at.bitfire.ical4android.*
import at.bitfire.ical4android.AndroidCalendar
import at.bitfire.ical4android.AndroidEvent
import at.bitfire.ical4android.AndroidEventFactory
import at.bitfire.ical4android.BatchOperation
import at.bitfire.ical4android.Event
import at.bitfire.ical4android.ICalendar
import at.bitfire.ical4android.Ical4Android
import at.bitfire.ical4android.util.MiscUtils.asSyncAdapter
import net.fortuna.ical4j.model.property.ProdId
import org.apache.commons.lang3.StringUtils
import java.util.*
import java.util.UUID
class LocalEvent: AndroidEvent, LocalResource<Event> {
@ -205,7 +211,7 @@ class LocalEvent: AndroidEvent, LocalResource<Event> {
}
// make sure that UID is set
val uid: String = dbUid ?: {
val uid: String = dbUid ?: run {
// generate new UID
val newUid = UUID.randomUUID().toString()
@ -218,7 +224,7 @@ class LocalEvent: AndroidEvent, LocalResource<Event> {
event?.uid = newUid
newUid
}()
}
val uidIsGoodFilename = uid.all { char ->
// see RFC 2396 2.2

View file

@ -8,8 +8,9 @@ import android.accounts.Account
import android.content.ContentProviderClient
import android.content.ContentValues
import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.db.*
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Principal
import at.bitfire.davdroid.db.SyncState
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.util.DavUtils
import at.bitfire.ical4android.JtxCollection

View file

@ -5,9 +5,14 @@
package at.bitfire.davdroid.resource
import android.content.ContentValues
import at.bitfire.ical4android.*
import at.bitfire.ical4android.AndroidTask
import at.bitfire.ical4android.AndroidTaskFactory
import at.bitfire.ical4android.AndroidTaskList
import at.bitfire.ical4android.BatchOperation
import at.bitfire.ical4android.Ical4Android
import at.bitfire.ical4android.Task
import org.dmfs.tasks.contract.TaskContract.Tasks
import java.util.*
import java.util.UUID
class LocalTask: AndroidTask, LocalResource<Task> {

View file

@ -10,10 +10,10 @@ import android.content.ContentValues
import android.content.Context
import android.net.Uri
import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.util.DavUtils
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.SyncState
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.util.DavUtils
import at.bitfire.ical4android.AndroidTaskList
import at.bitfire.ical4android.AndroidTaskListFactory
import at.bitfire.ical4android.TaskProvider

View file

@ -28,7 +28,7 @@ object TaskUtils {
fun currentProvider(context: Context): ProviderName? {
val settingsManager = EntryPointAccessors.fromApplication(context, TaskUtilsEntryPoint::class.java).settingsManager()
val preferredAuthority = settingsManager.getString(Settings.PREFERRED_TASKS_PROVIDER)
ProviderName.values()
ProviderName.entries.toTypedArray()
.sortedByDescending { it.authority == preferredAuthority }
.forEach { providerName ->
if (context.packageManager.resolveContentProvider(providerName.authority, 0) != null)

View file

@ -11,7 +11,7 @@ import at.bitfire.vcard4android.BatchOperation
import at.bitfire.vcard4android.Contact
import at.bitfire.vcard4android.GroupMethod
import at.bitfire.vcard4android.contactrow.DataRowBuilder
import java.util.*
import java.util.LinkedList
class GroupMembershipBuilder(dataRowUri: Uri, rawContactId: Long?, contact: Contact, val addressBook: LocalAddressBook, readOnly: Boolean)
: DataRowBuilder(Factory.MIME_TYPE, dataRowUri, rawContactId, contact, readOnly) {

View file

@ -8,7 +8,7 @@ import android.net.Uri
import at.bitfire.vcard4android.BatchOperation
import at.bitfire.vcard4android.Contact
import at.bitfire.vcard4android.contactrow.DataRowBuilder
import java.util.*
import java.util.LinkedList
class UnknownPropertiesBuilder(dataRowUri: Uri, rawContactId: Long?, contact: Contact, readOnly: Boolean)
: DataRowBuilder(Factory.mimeType(), dataRowUri, rawContactId, contact, readOnly) {

View file

@ -38,7 +38,6 @@ import java.util.logging.Level
* @throws InvalidAccountException on construction when the account doesn't exist (anymore)
* @throws IllegalArgumentException when the account type is not _DAVx5_ or _DAVx5 address book_
*/
@Suppress("FunctionName")
class AccountSettings(
val context: Context,
argAccount: Account
@ -224,7 +223,7 @@ class AccountSettings(
KEY_SYNC_INTERVAL_ADDRESSBOOKS
authority == CalendarContract.AUTHORITY ->
KEY_SYNC_INTERVAL_CALENDARS
TaskProvider.ProviderName.values().any { it.authority == authority } ->
TaskProvider.ProviderName.entries.any { it.authority == authority } ->
KEY_SYNC_INTERVAL_TASKS
else -> return null
}
@ -258,7 +257,7 @@ class AccountSettings(
KEY_SYNC_INTERVAL_ADDRESSBOOKS
authority == CalendarContract.AUTHORITY ->
KEY_SYNC_INTERVAL_CALENDARS
TaskProvider.ProviderName.values().any { it.authority == authority } ->
TaskProvider.ProviderName.entries.any { it.authority == authority } ->
KEY_SYNC_INTERVAL_TASKS
else -> {
Logger.log.warning("Sync interval not applicable to authority $authority")
@ -448,7 +447,7 @@ class AccountSettings(
try {
return GroupMethod.valueOf(name)
}
catch (e: IllegalArgumentException) {
catch (_: IllegalArgumentException) {
}
return GroupMethod.GROUP_VCARDS
}

View file

@ -153,70 +153,74 @@ class AccountSettingsMigrations(
*/
private fun update_11_12() {
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.WRITE_CALENDAR) == PackageManager.PERMISSION_GRANTED) {
val provider = context.contentResolver.acquireContentProviderClient(CalendarContract.AUTHORITY)
if (provider != null)
try {
// Attention: CalendarProvider does NOT limit the results of the ExtendedProperties query
// to the given account! So all extended properties will be processed number-of-accounts times.
val extUri = CalendarContract.ExtendedProperties.CONTENT_URI.asSyncAdapter(account)
context.contentResolver.acquireContentProviderClient(CalendarContract.AUTHORITY)?.use { provider ->
// Attention: CalendarProvider does NOT limit the results of the ExtendedProperties query
// to the given account! So all extended properties will be processed number-of-accounts times.
val extUri = CalendarContract.ExtendedProperties.CONTENT_URI.asSyncAdapter(account)
provider.query(extUri, arrayOf(
provider.query(
extUri, arrayOf(
CalendarContract.ExtendedProperties._ID, // idx 0
CalendarContract.ExtendedProperties.NAME, // idx 1
CalendarContract.ExtendedProperties.VALUE // idx 2
), null, null, null)?.use { cursor ->
while (cursor.moveToNext()) {
val id = cursor.getLong(0)
val rawValue = cursor.getString(2)
), null, null, null
)?.use { cursor ->
while (cursor.moveToNext()) {
val id = cursor.getLong(0)
val rawValue = cursor.getString(2)
val uri by lazy {
ContentUris.withAppendedId(CalendarContract.ExtendedProperties.CONTENT_URI, id).asSyncAdapter(account)
val uri by lazy {
ContentUris.withAppendedId(CalendarContract.ExtendedProperties.CONTENT_URI, id).asSyncAdapter(account)
}
when (cursor.getString(1)) {
UnknownProperty.CONTENT_ITEM_TYPE -> {
// unknown property; check whether it's a URL
try {
val property = UnknownProperty.fromJsonString(rawValue)
if (property is Url) { // rewrite to MIMETYPE_URL
val newValues = ContentValues(2)
newValues.put(CalendarContract.ExtendedProperties.NAME, AndroidEvent.MIMETYPE_URL)
newValues.put(CalendarContract.ExtendedProperties.VALUE, property.value)
provider.update(uri, newValues, null, null)
}
} catch (e: Exception) {
Logger.log.log(
Level.WARNING,
"Couldn't rewrite URL from unknown property to ${AndroidEvent.MIMETYPE_URL}",
e
)
}
}
when (cursor.getString(1)) {
UnknownProperty.CONTENT_ITEM_TYPE -> {
// unknown property; check whether it's a URL
try {
val property = UnknownProperty.fromJsonString(rawValue)
if (property is Url) { // rewrite to MIMETYPE_URL
"unknown-property" -> {
// unknown property (deprecated format); convert to current format
try {
val stream = ByteArrayInputStream(Base64.decode(rawValue, Base64.NO_WRAP))
ObjectInputStream(stream).use {
(it.readObject() as? Property)?.let { property ->
// rewrite to current format
val newValues = ContentValues(2)
newValues.put(CalendarContract.ExtendedProperties.NAME, AndroidEvent.MIMETYPE_URL)
newValues.put(CalendarContract.ExtendedProperties.VALUE, property.value)
newValues.put(CalendarContract.ExtendedProperties.NAME, UnknownProperty.CONTENT_ITEM_TYPE)
newValues.put(CalendarContract.ExtendedProperties.VALUE, UnknownProperty.toJsonString(property))
provider.update(uri, newValues, null, null)
}
} catch (e: Exception) {
Logger.log.log(Level.WARNING, "Couldn't rewrite URL from unknown property to ${AndroidEvent.MIMETYPE_URL}", e)
}
} catch (e: Exception) {
Logger.log.log(Level.WARNING, "Couldn't rewrite deprecated unknown property to current format", e)
}
"unknown-property" -> {
// unknown property (deprecated format); convert to current format
try {
val stream = ByteArrayInputStream(Base64.decode(rawValue, Base64.NO_WRAP))
ObjectInputStream(stream).use {
(it.readObject() as? Property)?.let { property ->
// rewrite to current format
val newValues = ContentValues(2)
newValues.put(CalendarContract.ExtendedProperties.NAME, UnknownProperty.CONTENT_ITEM_TYPE)
newValues.put(CalendarContract.ExtendedProperties.VALUE, UnknownProperty.toJsonString(property))
provider.update(uri, newValues, null, null)
}
}
} catch(e: Exception) {
Logger.log.log(Level.WARNING, "Couldn't rewrite deprecated unknown property to current format", e)
}
}
"unknown-property.v2" -> {
// unknown property (deprecated MIME type); rewrite to current MIME type
val newValues = ContentValues(1)
newValues.put(CalendarContract.ExtendedProperties.NAME, UnknownProperty.CONTENT_ITEM_TYPE)
provider.update(uri, newValues, null, null)
}
}
"unknown-property.v2" -> {
// unknown property (deprecated MIME type); rewrite to current MIME type
val newValues = ContentValues(1)
newValues.put(CalendarContract.ExtendedProperties.NAME, UnknownProperty.CONTENT_ITEM_TYPE)
provider.update(uri, newValues, null, null)
}
}
}
} finally {
provider.close()
}
}
}
}
@ -308,12 +312,8 @@ class AccountSettingsMigrations(
@SuppressLint("Recycle")
private fun update_6_7() {
// add calendar colors
context.contentResolver.acquireContentProviderClient(CalendarContract.AUTHORITY)?.let { provider ->
try {
AndroidCalendar.insertColors(provider, account)
} finally {
provider.close()
}
context.contentResolver.acquireContentProviderClient(CalendarContract.AUTHORITY)?.use { provider ->
AndroidCalendar.insertColors(provider, account)
}
// update allowed WiFi settings key

View file

@ -58,7 +58,7 @@ class SettingsManager internal constructor(
providers.addAll(factory.getProviders(context, this))
}
writeProvider = providers.firstOrNull() { it.canWrite() }
writeProvider = providers.firstOrNull { it.canWrite() }
Logger.log.fine("Changed settings are handled by $writeProvider")
}

View file

@ -8,7 +8,11 @@ import android.accounts.Account
import android.accounts.AccountManager
import android.content.Context
import androidx.hilt.work.HiltWorker
import androidx.work.*
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.Worker
import androidx.work.WorkerParameters
import at.bitfire.davdroid.R
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.log.Logger

View file

@ -8,7 +8,6 @@ import android.content.ContentProvider
import android.content.ContentValues
import android.net.Uri
@Suppress("ImplicitNullableNothingType")
class AddressBookProvider: ContentProvider() {
override fun onCreate() = false

View file

@ -12,10 +12,10 @@ import android.content.SyncResult
import android.content.pm.PackageManager
import android.provider.ContactsContract
import androidx.core.content.ContextCompat
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.settings.Settings
import at.bitfire.davdroid.settings.SettingsManager

View file

@ -9,10 +9,10 @@ import android.content.ContentProviderClient
import android.content.Context
import android.content.SyncResult
import android.provider.CalendarContract
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.resource.LocalCalendar
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.ical4android.AndroidCalendar

View file

@ -9,8 +9,8 @@ import android.content.ContentProviderClient
import android.content.Context
import android.content.SyncResult
import android.provider.ContactsContract
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.util.setAndVerifyUserData

View file

@ -10,10 +10,10 @@ import android.content.ContentProviderClient
import android.content.Context
import android.content.SyncResult
import android.os.Build
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.resource.LocalJtxCollection
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.ical4android.JtxCollection

View file

@ -6,7 +6,12 @@ package at.bitfire.davdroid.syncadapter
import android.accounts.Account
import android.app.Service
import android.content.*
import android.content.AbstractThreadedSyncAdapter
import android.content.ContentProviderClient
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.SyncResult
import android.os.Bundle
import androidx.lifecycle.Observer
import androidx.work.WorkInfo
@ -14,7 +19,11 @@ import androidx.work.WorkManager
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.AccountSettings
import kotlinx.coroutines.*
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout
import java.util.logging.Level
abstract class SyncAdapterService: Service() {

View file

@ -129,7 +129,7 @@ object SyncUtils {
val accountManager = AccountManager.get(context)
for (account in accountManager.getAccountsByType(context.getString(R.string.account_type))) {
val hasCalDAV = db.serviceDao().getByAccountAndType(account.name, Service.TYPE_CALDAV) != null
for (providerName in TaskProvider.ProviderName.values()) {
for (providerName in TaskProvider.ProviderName.entries) {
val isSyncable = ContentResolver.getIsSyncable(account, providerName.authority) // may be -1 (unknown state)
val shallBeSyncable = hasCalDAV && providerName == currentProvider
if ((shallBeSyncable && isSyncable != 1) || (!shallBeSyncable && isSyncable != 0)) {

View file

@ -48,6 +48,7 @@ import at.bitfire.davdroid.util.PermissionUtils
import at.bitfire.ical4android.TaskProvider
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import kotlinx.coroutines.delay
import kotlinx.coroutines.runInterruptible
import kotlinx.coroutines.withContext
import java.util.concurrent.TimeUnit
@ -383,7 +384,7 @@ class SyncWorker @AssistedInject constructor(
// We block the SyncWorker here so that it won't be started by the sync framework immediately again.
// This should be replaced by proper work scheduling as soon as we don't depend on the sync framework anymore.
if (blockDuration > 0)
Thread.sleep(blockDuration*1000)
delay(blockDuration*1000)
Logger.log.warning("Retrying on soft error (attempt $runAttemptCount of $MAX_RUN_ATTEMPTS)")
return@withContext Result.retry()

View file

@ -8,10 +8,10 @@ import android.accounts.Account
import android.content.ContentProviderClient
import android.content.Context
import android.content.SyncResult
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.settings.AccountSettings
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn

View file

@ -10,10 +10,10 @@ import android.content.ContentProviderClient
import android.content.Context
import android.content.SyncResult
import android.os.Build
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.db.Service
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.resource.LocalTaskList
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.ical4android.AndroidTaskList

View file

@ -35,7 +35,7 @@ class VCard4Strategy(val addressBook: LocalAddressBook): ContactGroupStrategy {
.newUpdate(addressBook.syncAdapterURI(ContentUris.withAppendedId(ContactsContract.Groups.CONTENT_URI, groupID)))
.withValue(ContactsContract.Groups.DIRTY, 1))
}
} catch(e: FileNotFoundException) {
} catch(_: FileNotFoundException) {
}
batch.commit()
}

View file

@ -195,7 +195,7 @@ class AccountsActivity: AppCompatActivity() {
},
dataSaverActive = warnings.dataSaverEnabled.observeAsState().value == true,
onManageDataSaver = {
val intent = Intent(android.provider.Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS, Uri.parse("package:" + packageName))
val intent = Intent(Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS, Uri.parse("package:$packageName"))
if (intent.resolveActivity(packageManager) != null)
startActivity(intent)
},
@ -207,7 +207,7 @@ class AccountsActivity: AppCompatActivity() {
},
lowStorageWarning = warnings.storageLow.observeAsState().value == true,
onManageStorage = {
val intent = Intent(android.provider.Settings.ACTION_INTERNAL_STORAGE_SETTINGS)
val intent = Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS)
if (intent.resolveActivity(packageManager) != null)
startActivity(intent)
}

View file

@ -25,12 +25,12 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.PackageChangedReceiver
import at.bitfire.davdroid.R
import at.bitfire.davdroid.databinding.ActivityPermissionsBinding
import at.bitfire.davdroid.util.PermissionUtils
import at.bitfire.davdroid.util.PermissionUtils.CALENDAR_PERMISSIONS
import at.bitfire.davdroid.util.PermissionUtils.CONTACT_PERMISSIONS
import at.bitfire.davdroid.util.PermissionUtils.havePermissions
import at.bitfire.davdroid.R
import at.bitfire.davdroid.databinding.ActivityPermissionsBinding
import at.bitfire.ical4android.TaskProvider
import at.bitfire.ical4android.TaskProvider.ProviderName

View file

@ -165,10 +165,8 @@ class CollectionInfoFragment: DialogFragment() {
*/
private fun getAppNameFromAuthority(authority: String): String {
val packageManager = getApplication<Application>().packageManager
@Suppress("DEPRECATION")
val packageName = packageManager.resolveContentProvider(authority, 0)?.packageName ?: authority
return try {
@Suppress("DEPRECATION")
val appInfo = packageManager.getPackageInfo(packageName, 0).applicationInfo
packageManager.getApplicationLabel(appInfo).toString()
} catch (e: PackageManager.NameNotFoundException) {

View file

@ -7,11 +7,17 @@ package at.bitfire.davdroid.ui.account
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.app.Application
import android.content.*
import android.content.Intent
import android.os.Bundle
import android.provider.CalendarContract
import android.provider.ContactsContract
import android.view.*
import android.view.Gravity
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import androidx.annotation.CallSuper
import androidx.core.view.MenuProvider
@ -19,8 +25,21 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.*
import androidx.paging.*
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.switchMap
import androidx.lifecycle.viewModelScope
import androidx.paging.LoadState
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.PagingDataAdapter
import androidx.paging.cachedIn
import androidx.paging.liveData
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -321,7 +340,7 @@ abstract class CollectionsFragment: Fragment(), SwipeRefreshLayout.OnRefreshList
if (collectionType == Collection.TYPE_ADDRESSBOOK)
listOf(getApplication<Application>().getString(R.string.address_books_authority), ContactsContract.AUTHORITY)
else
listOf(CalendarContract.AUTHORITY, taskProvider?.authority).filterNotNull()
listOfNotNull(CalendarContract.AUTHORITY, taskProvider?.authority)
val isSyncActive = SyncWorker.exists(getApplication(),
listOf(WorkInfo.State.RUNNING),
accountModel.account,

View file

@ -32,7 +32,7 @@ import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.apache.commons.lang3.StringUtils
import java.util.*
import java.util.UUID
import javax.inject.Inject
@AndroidEntryPoint
@ -43,7 +43,7 @@ class CreateAddressBookActivity: AppCompatActivity() {
}
@Inject lateinit var modelFactory: Model.Factory
val model by viewModels<Model>() {
val model by viewModels<Model> {
object: ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {

View file

@ -9,7 +9,11 @@ import android.content.Context
import android.content.Intent
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.*
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.TextView
import androidx.activity.viewModels
@ -41,7 +45,9 @@ import net.fortuna.ical4j.model.Calendar
import org.apache.commons.lang3.StringUtils
import java.time.ZoneId
import java.time.format.TextStyle
import java.util.*
import java.util.Locale
import java.util.TimeZone
import java.util.UUID
import javax.inject.Inject
@AndroidEntryPoint
@ -52,7 +58,7 @@ class CreateCalendarActivity: AppCompatActivity(), ColorPickerDialogListener {
}
@Inject lateinit var modelFactory: Model.Factory
val model by viewModels<Model>() {
val model by viewModels<Model> {
object: ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {

View file

@ -15,7 +15,6 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
@ -68,7 +67,7 @@ class CreateCollectionFragment: DialogFragment() {
}
@Inject lateinit var modelFactory: Model.Factory
val model by viewModels<Model>() {
val model by viewModels<Model> {
object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@ -100,7 +99,7 @@ class CreateCollectionFragment: DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model.createCollection().observe(this, Observer { exception ->
model.createCollection().observe(this, { exception ->
if (exception == null)
requireActivity().finish()
else {

View file

@ -12,7 +12,12 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.*
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import at.bitfire.dav4jvm.DavResource
import at.bitfire.davdroid.databinding.DeleteCollectionBinding
import at.bitfire.davdroid.db.AppDatabase
@ -47,7 +52,7 @@ class DeleteCollectionFragment: DialogFragment() {
}
@Inject lateinit var modelFactory: Model.Factory
val model by viewModels<Model>() {
val model by viewModels<Model> {
object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T =
@ -69,7 +74,7 @@ class DeleteCollectionFragment: DialogFragment() {
binding.progress.visibility = View.VISIBLE
binding.controls.visibility = View.GONE
model.deleteCollection().observe(viewLifecycleOwner, Observer { exception ->
model.deleteCollection().observe(viewLifecycleOwner, { exception ->
if (exception != null)
parentFragmentManager.beginTransaction()
.add(ExceptionInfoFragment.newInstance(exception, model.account), null)

View file

@ -202,15 +202,11 @@ class RenameAccountFragment: DialogFragment() {
// update main account of address book accounts
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED)
try {
context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY)?.let { provider ->
try {
for (addrBookAccount in accountManager.getAccountsByType(context.getString(R.string.account_type_address_book))) {
val addressBook = LocalAddressBook(context, addrBookAccount, provider)
if (oldAccount == addressBook.mainAccount)
addressBook.mainAccount = Account(newName, oldAccount.type)
}
} finally {
provider.close()
context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY)?.use { provider ->
for (addrBookAccount in accountManager.getAccountsByType(context.getString(R.string.account_type_address_book))) {
val addressBook = LocalAddressBook(context, addrBookAccount, provider)
if (oldAccount == addressBook.mainAccount)
addressBook.mainAccount = Account(newName, oldAccount.type)
}
}
} catch (e: Exception) {

View file

@ -81,7 +81,7 @@ class SettingsActivity: AppCompatActivity() {
@AndroidEntryPoint
class AccountSettingsFragment(): PreferenceFragmentCompat() {
class AccountSettingsFragment : PreferenceFragmentCompat() {
private val account by lazy { requireArguments().getParcelable<Account>(EXTRA_ACCOUNT)!! }
@Inject lateinit var settings: SettingsManager

View file

@ -15,11 +15,19 @@ import android.net.Uri
import android.os.Bundle
import android.provider.CalendarContract
import android.provider.CalendarContract.Calendars
import android.view.*
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.WorkerThread
import androidx.core.content.ContextCompat
import androidx.fragment.app.viewModels
import androidx.lifecycle.*
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.room.Transaction
import at.bitfire.dav4jvm.UrlUtils
import at.bitfire.davdroid.Constants
@ -74,7 +82,7 @@ class WebcalFragment: CollectionsFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
webcalModel.subscribedUrls.observe(this, Observer { urls ->
webcalModel.subscribedUrls.observe(this, { urls ->
Logger.log.log(Level.FINE, "Got Android calendar list", urls.keys)
})
}

View file

@ -10,8 +10,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import at.bitfire.davdroid.App
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.databinding.IntroWelcomeBinding
import dagger.Binds
import dagger.Module
@ -62,7 +60,7 @@ class WelcomeFragment: Fragment() {
@InstallIn(ActivityComponent::class)
abstract class WelcomeFragmentModule {
@Binds @IntoSet
abstract fun getFactory(factory: WelcomeFragment.Factory): IntroFragmentFactory
abstract fun getFactory(factory: Factory): IntroFragmentFactory
}
class Factory @Inject constructor() : IntroFragmentFactory {

View file

@ -23,7 +23,6 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.viewModelScope
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.R
@ -109,7 +108,7 @@ class AccountDetailsFragment : Fragment() {
loginModel.credentials,
config,
GroupMethod.valueOf(groupMethodName)
).observe(viewLifecycleOwner, Observer { success ->
).observe(viewLifecycleOwner, { success ->
if (success) {
// close Create account activity
requireActivity().finish()
@ -163,7 +162,7 @@ class AccountDetailsFragment : Fragment() {
val name = MutableLiveData<String>()
val nameError = MutableLiveData<String>()
val showApostropheWarning = MutableLiveData<Boolean>(false)
val showApostropheWarning = MutableLiveData(false)
val context: Context get() = getApplication()

View file

@ -115,7 +115,7 @@ class DetectConfigurationFragment: Fragment() {
}
} catch(e: Exception) {
// This shouldn't happen; instead configuration should be empty
at.bitfire.davdroid.log.Logger.log.log(Level.WARNING, "Uncaught exception during service detection, shouldn't happen", e)
Logger.log.log(Level.WARNING, "Uncaught exception during service detection, shouldn't happen", e)
}
}
}

View file

@ -26,7 +26,6 @@ import androidx.core.view.MenuProvider
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.viewModelScope
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
@ -71,7 +70,7 @@ class WebdavMountsActivity: AppCompatActivity() {
val adapter = MountsAdapter(this, model)
binding.list.adapter = adapter
binding.list.layoutManager = LinearLayoutManager(this)
model.mountInfos.observe(this, Observer { mounts ->
model.mountInfos.observe(this, { mounts ->
adapter.submitList(ArrayList(mounts))
val hasMounts = mounts.isNotEmpty()
@ -87,7 +86,7 @@ class WebdavMountsActivity: AppCompatActivity() {
.startChooser()
}
}
model.browseIntent.observe(this, Observer { intent ->
model.browseIntent.observe(this, { intent ->
if (intent != null)
browser.launch(intent)
})

View file

@ -19,10 +19,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import at.bitfire.davdroid.R
@Composable
fun ActionCard(

View file

@ -4,7 +4,6 @@
package at.bitfire.davdroid.ui.widget
import android.content.res.Configuration.ORIENTATION_PORTRAIT
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
@ -21,17 +20,14 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.TabletAndroid
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.BiasAlignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import at.bitfire.davdroid.R

View file

@ -19,8 +19,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
/**
* Provides a radio button with a text, a switch at the end, and an optional summary to be shown

View file

@ -4,7 +4,7 @@
package at.bitfire.davdroid.util
import java.util.*
import java.util.Collections
object ConcurrentUtils {

View file

@ -140,7 +140,7 @@ object DavUtils {
the random number selected. The target host specified in the
selected SRV RR is the next one to be contacted by the client.
*/
val minPriority = srvRecords.map { it.priority }.minOrNull()
val minPriority = srvRecords.minOfOrNull { it.priority }
val useableRecords = srvRecords.filter { it.priority == minPriority }.sortedBy { it.weight != 0 }
val map = TreeMap<Int, SRVRecord>()

View file

@ -236,7 +236,7 @@ class RandomAccessCallback private constructor(
): ProxyFileDescriptorCallback() {
companion object {
val TIMEOUT_INTERVAL = 15000L
const val TIMEOUT_INTERVAL = 15000L
}
sealed class Events {

View file

@ -7,8 +7,6 @@ package at.bitfire.davdroid.webdav.cache
import at.bitfire.davdroid.log.Logger
import org.apache.commons.io.FileUtils
import java.io.File
import java.io.IOException
import java.util.logging.Level
/**
* Disk-based cache that maps [String]s to [ByteArray]s.

View file

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
</vector>

View file

@ -1,5 +0,0 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#FFFFFF" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M11,8v3H8v2h3v3h2v-3h3v-2h-3V8H11zM13,2.05v3.03c3.39,0.49 6,3.39 6,6.92c0,0.9 -0.18,1.75 -0.48,2.54l2.6,1.53C21.68,14.83 22,13.45 22,12C22,6.82 18.05,2.55 13,2.05zM12,19c-3.87,0 -7,-3.13 -7,-7c0,-3.53 2.61,-6.43 6,-6.92V2.05C5.94,2.55 2,6.81 2,12c0,5.52 4.47,10 9.99,10c3.31,0 6.24,-1.61 8.06,-4.09l-2.6,-1.53C16.17,17.98 14.21,19 12,19z"/>
</vector>

View file

@ -1,5 +0,0 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#FFFFFF" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20,18.69L7.84,6.14 5.27,3.49 4,4.76l2.8,2.8v0.01c-0.52,0.99 -0.8,2.16 -0.8,3.42v5l-2,2v1h13.73l2,2L21,19.72l-1,-1.03zM12,22c1.11,0 2,-0.89 2,-2h-4c0,1.11 0.89,2 2,2zM18,14.68L18,11c0,-3.08 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68c-0.15,0.03 -0.29,0.08 -0.42,0.12 -0.1,0.03 -0.2,0.07 -0.3,0.11h-0.01c-0.01,0 -0.01,0 -0.02,0.01 -0.23,0.09 -0.46,0.2 -0.68,0.31 0,0 -0.01,0 -0.01,0.01L18,14.68z"/>
</vector>

View file

@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@android:color/white"
android:pathData="M21,1l-8.59,8.59L21,18.18V1zM4.77,4.5L3.5,5.77l6.36,6.36L1,21h17.73l2,2L22,21.73 4.77,4.5z" />
</vector>

View file

@ -74,7 +74,7 @@
android:layout_height="wrap_content"
style="@style/TextAppearance.MaterialComponents.Body1"
android:layout_marginBottom="8dp"
android:text="Authentication (optional)" />
android:text="@string/webdav_add_mount_authentication" />
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"

View file

@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"

View file

@ -15,7 +15,7 @@
android:padding="@dimen/activity_margin">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<TextView

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/syncAll"
android:icon="@drawable/ic_sync"
android:title="@string/accounts_sync_all"
app:showAsAction="ifRoom"/>
</menu>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="account_list_card">
<item name="android:layout_width">600dp</item>
</style>
</resources>

View file

@ -125,8 +125,6 @@
<string name="logging_notification_disable">Disable</string>
<!-- AccountsActivity -->
<string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string>
<string name="navigation_drawer_subtitle">CalDAV/CardDAV Sync Adapter</string>
<string name="navigation_drawer_about">About / License</string>
<string name="navigation_drawer_beta_feedback">Beta feedback</string>
@ -488,6 +486,7 @@
<string name="webdav_add_mount_display_name">Display name</string>
<string name="webdav_add_mount_url">WebDAV URL</string>
<string name="webdav_add_mount_url_invalid">Invalid URL</string>
<string name="webdav_add_mount_authentication">Authentication (optional)</string>
<string name="webdav_add_mount_username">User name</string>
<string name="webdav_add_mount_password">Password</string>
<string name="webdav_add_mount_add">Add mount</string>

View file

@ -67,13 +67,6 @@
</style>
<!-- AddAccountActivity -->
<style name="account_list_card">
<item name="android:layout_width">match_parent</item>
</style>
<!-- stepper (wizard) -->
<style name="stepper_nav_bar">

View file

@ -24,7 +24,7 @@ interface OseFlavorModules {
@InstallIn(ActivityComponent::class)
interface ForActivities {
@Binds
abstract fun accountsDrawerHandler(impl: OseAccountsDrawerHandler): AccountsDrawerHandler
fun accountsDrawerHandler(impl: OseAccountsDrawerHandler): AccountsDrawerHandler
@Binds
fun appLicenseInfoProvider(impl: OpenSourceLicenseInfoProvider): AboutActivity.AppLicenseInfoProvider

View file

@ -17,7 +17,7 @@ class ConcurrentUtilsTest {
@Test
fun testRunSingle_DifferentKeys_Sequentially() {
var nrCalled = AtomicInteger()
val nrCalled = AtomicInteger()
for (i in 0 until 10)
ConcurrentUtils.runSingle(i) { nrCalled.incrementAndGet() }
assertEquals(10, nrCalled.get())
@ -25,7 +25,7 @@ class ConcurrentUtilsTest {
@Test
fun testRunSingle_DifferentKeys_Parallel() {
var nrCalled = AtomicInteger()
val nrCalled = AtomicInteger()
val threads = mutableListOf<Thread>()
for (i in 0 until 10)
threads += thread {
@ -41,7 +41,7 @@ class ConcurrentUtilsTest {
@Test
fun testRunSingle_SameKey_Sequentially() {
val key = "a"
var nrCalled = AtomicInteger()
val nrCalled = AtomicInteger()
for (i in 0 until 10)
ConcurrentUtils.runSingle(key) { nrCalled.incrementAndGet() }
assertEquals(10, nrCalled.get())

View file

@ -84,8 +84,8 @@ class DavUtilsTest {
else -> throw AssertionError()
}
}
assertTrue(result[0] > 200 && result[0] < 500)
assertTrue(result[1] > 500 && result[1] < 800)
assertTrue(result[0] in 201..499)
assertTrue(result[1] in 501..799)
}
}

View file

@ -34,7 +34,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:8.2.1'
classpath 'com.android.tools.build:gradle:8.2.2'
classpath "com.google.dagger:hilt-android-gradle-plugin:${versions.hilt}"
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:${versions.aboutLibraries}"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"