mirror of
https://github.com/bitfireAT/davx5-ose
synced 2024-10-15 15:59:18 +00:00
parent
b2d06a491d
commit
95d098541f
|
@ -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
|
||||
|
|
|
@ -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"))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" +
|
||||
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")
|
||||
" <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()
|
||||
"</multistatus>"
|
||||
)
|
||||
return MockResponse()
|
||||
.setResponseCode(207)
|
||||
.setHeader("Content-Type", "text/xml")
|
||||
.setBody(body.toString())
|
||||
return response
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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> {
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -153,18 +153,18 @@ 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 {
|
||||
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 ->
|
||||
), null, null, null
|
||||
)?.use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
val id = cursor.getLong(0)
|
||||
val rawValue = cursor.getString(2)
|
||||
|
@ -185,9 +185,14 @@ class AccountSettingsMigrations(
|
|||
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)
|
||||
Logger.log.log(
|
||||
Level.WARNING,
|
||||
"Couldn't rewrite URL from unknown property to ${AndroidEvent.MIMETYPE_URL}",
|
||||
e
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
"unknown-property" -> {
|
||||
// unknown property (deprecated format); convert to current format
|
||||
try {
|
||||
|
@ -201,10 +206,11 @@ class AccountSettingsMigrations(
|
|||
provider.update(uri, newValues, null, null)
|
||||
}
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
} 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)
|
||||
|
@ -214,8 +220,6 @@ class AccountSettingsMigrations(
|
|||
}
|
||||
}
|
||||
}
|
||||
} 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 {
|
||||
context.contentResolver.acquireContentProviderClient(CalendarContract.AUTHORITY)?.use { provider ->
|
||||
AndroidCalendar.insertColors(provider, account)
|
||||
} finally {
|
||||
provider.close()
|
||||
}
|
||||
}
|
||||
|
||||
// update allowed WiFi settings key
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -202,16 +202,12 @@ 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 {
|
||||
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)
|
||||
}
|
||||
} finally {
|
||||
provider.close()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Logger.log.log(Level.SEVERE, "Couldn't update address book accounts", e)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
package at.bitfire.davdroid.util
|
||||
|
||||
import java.util.*
|
||||
import java.util.Collections
|
||||
|
||||
object ConcurrentUtils {
|
||||
|
||||
|
|
|
@ -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>()
|
||||
|
|
|
@ -236,7 +236,7 @@ class RandomAccessCallback private constructor(
|
|||
): ProxyFileDescriptorCallback() {
|
||||
|
||||
companion object {
|
||||
val TIMEOUT_INTERVAL = 15000L
|
||||
const val TIMEOUT_INTERVAL = 15000L
|
||||
}
|
||||
|
||||
sealed class Events {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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}"
|
||||
|
|
Loading…
Reference in a new issue