362 increase minimum api level to android 7 (bitfireAT/davx5#363)

* Increase minSdkVersion to 24 (Android 7.0)

* Remove obsolete api level checks

* Use latest dnsjava

* Use latest apache commons

* Minor formatting

* Unify getSystemService() calls

* Remove further unnecessary calls

* Remove noinspection GradleDependency for Apache Commons libs

---------

Co-authored-by: Ricki Hirner <hirner@bitfire.at>
This commit is contained in:
Sunik Kupfer 2023-10-10 11:25:07 +02:00 committed by Ricki Hirner
parent 0ba00d7bb0
commit 3da48ab3a2
No known key found for this signature in database
GPG key ID: 79A019FCAAEDD3AA
28 changed files with 182 additions and 233 deletions

View file

@ -25,7 +25,7 @@ android {
setProperty "archivesBaseName", "davx5-ose-" + getVersionName()
minSdkVersion 21 // Android 5
minSdkVersion 24 // Android 7.0
targetSdkVersion 33 // Android 13
buildConfigField "String", "userAgent", "\"DAVx5\""
@ -182,14 +182,10 @@ dependencies {
implementation "com.squareup.okhttp3:logging-interceptor:${versions.okhttp}"
//noinspection GradleDependency - don't update until API level 26 (Android 8) is the minimum API [https://github.com/bitfireAT/davx5/issues/130]
implementation 'commons-io:commons-io:2.8.0'
//noinspection GradleDependency - dnsjava 3+ needs Java 8/Android 7
implementation 'dnsjava:dnsjava:2.1.9'
implementation 'dnsjava:dnsjava:3.5.2'
implementation 'net.openid:appauth:0.11.1'
//noinspection GradleDependency
implementation "org.apache.commons:commons-collections4:${versions.commonsCollections}"
//noinspection GradleDependency
implementation "org.apache.commons:commons-lang3:${versions.commonsLang}"
//noinspection GradleDependency
implementation "org.apache.commons:commons-text:${versions.commonsText}"
// for tests
@ -208,4 +204,4 @@ dependencies {
testImplementation "com.squareup.okhttp3:mockwebserver:${versions.okhttp}"
testImplementation 'junit:junit:4.13.2'
}
}

View file

@ -12,6 +12,7 @@ import android.os.Build
import android.os.PowerManager
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.getSystemService
import at.bitfire.davdroid.settings.Settings
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.AppSettingsActivity
@ -62,12 +63,8 @@ class ForegroundService : Service() {
* Whether the app is currently exempted from battery optimization.
* @return true if battery optimization is not applied to the current app; false if battery optimization is applied
*/
fun batteryOptimizationWhitelisted(context: Context) =
if (Build.VERSION.SDK_INT >= 23) { // battery optimization exists since Android 6 (SDK level 23)
val powerManager = context.getSystemService(PowerManager::class.java)
powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)
} else
true
private fun batteryOptimizationWhitelisted(context: Context) =
context.getSystemService<PowerManager>()!!.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)
/**
* Whether the foreground service is enabled (checked) in the app settings.

View file

@ -11,10 +11,12 @@ import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.runBlocking
import org.xbill.DNS.EDNSOption
import org.xbill.DNS.Message
import org.xbill.DNS.Resolver
import org.xbill.DNS.ResolverListener
import org.xbill.DNS.TSIG
import java.time.Duration
/**
* dnsjava Resolver that uses Android's [DnsResolver] API, which is available since Android 10.
@ -42,6 +44,7 @@ object Android10Resolver: Resolver {
future.await()
}
@Deprecated("Deprecated in dnsjava")
override fun sendAsync(query: Message, listener: ResolverListener) =
// currently not used by dnsjava, so no need to implement it
throw NotImplementedError()
@ -63,7 +66,12 @@ object Android10Resolver: Resolver {
// not applicable
}
override fun setEDNS(level: Int, payloadSize: Int, flags: Int, options: MutableList<Any?>?) {
override fun setEDNS(
version: Int,
payloadSize: Int,
flags: Int,
options: MutableList<EDNSOption>?
) {
// not applicable
}
@ -71,12 +79,18 @@ object Android10Resolver: Resolver {
// not applicable
}
@Deprecated("Deprecated in dnsjava")
override fun setTimeout(secs: Int, msecs: Int) {
// not applicable
}
@Deprecated("Deprecated in dnsjava")
override fun setTimeout(secs: Int) {
// not applicable
}
override fun setTimeout(timeout: Duration?) {
// not applicable
}
}

View file

@ -5,7 +5,11 @@ package at.bitfire.davdroid.resource
import android.accounts.Account
import android.accounts.AccountManager
import android.content.*
import android.content.ContentProviderClient
import android.content.ContentResolver
import android.content.ContentUris
import android.content.ContentValues
import android.content.Context
import android.os.Build
import android.os.Bundle
import android.os.RemoteException
@ -22,9 +26,13 @@ import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.syncadapter.AccountUtils
import at.bitfire.davdroid.util.DavUtils
import at.bitfire.davdroid.util.setAndVerifyUserData
import at.bitfire.vcard4android.*
import at.bitfire.vcard4android.AndroidAddressBook
import at.bitfire.vcard4android.AndroidContact
import at.bitfire.vcard4android.AndroidGroup
import at.bitfire.vcard4android.Constants
import at.bitfire.vcard4android.GroupMethod
import java.io.ByteArrayOutputStream
import java.util.*
import java.util.LinkedList
import java.util.logging.Level
/**
@ -266,11 +274,7 @@ open class LocalAddressBook(
fun delete() {
val accountManager = AccountManager.get(context)
@Suppress("DEPRECATION")
if (Build.VERSION.SDK_INT >= 22)
accountManager.removeAccount(account, null, null, null)
else
accountManager.removeAccount(account, null, null)
accountManager.removeAccount(account, null, null, null)
}
@ -375,8 +379,8 @@ open class LocalAddressBook(
* @throws RemoteException on content provider errors
*/
fun verifyDirty(): Int {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
throw IllegalStateException("verifyDirty() should not be called on Android != 7")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
throw IllegalStateException("verifyDirty() should not be called on Android != 7.0")
var reallyDirty = 0
for (contact in findDirtyContacts()) {

View file

@ -12,12 +12,21 @@ import android.provider.ContactsContract.CommonDataKinds.GroupMembership
import android.provider.ContactsContract.RawContacts.Data
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.contactrow.*
import at.bitfire.vcard4android.*
import at.bitfire.davdroid.resource.contactrow.CachedGroupMembershipHandler
import at.bitfire.davdroid.resource.contactrow.GroupMembershipBuilder
import at.bitfire.davdroid.resource.contactrow.GroupMembershipHandler
import at.bitfire.davdroid.resource.contactrow.UnknownPropertiesBuilder
import at.bitfire.davdroid.resource.contactrow.UnknownPropertiesHandler
import at.bitfire.vcard4android.AndroidAddressBook
import at.bitfire.vcard4android.AndroidContact
import at.bitfire.vcard4android.AndroidContactFactory
import at.bitfire.vcard4android.BatchOperation
import at.bitfire.vcard4android.CachedGroupMembership
import at.bitfire.vcard4android.Contact
import ezvcard.Ezvcard
import org.apache.commons.lang3.StringUtils
import java.io.FileNotFoundException
import java.util.*
import java.util.UUID
class LocalContact: AndroidContact, LocalAddress {
@ -91,7 +100,7 @@ class LocalContact: AndroidContact, LocalAddress {
values.put(COLUMN_ETAG, eTag)
values.put(ContactsContract.RawContacts.DIRTY, 0)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
// workaround for Android 7 which sets DIRTY flag when only meta-data is changed
val hashCode = dataHashCode()
values.put(COLUMN_HASHCODE, hashCode)
@ -132,7 +141,7 @@ class LocalContact: AndroidContact, LocalAddress {
* @return hash code of contact data (including group memberships)
*/
internal fun dataHashCode(): Int {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
throw IllegalStateException("dataHashCode() should not be called on Android != 7")
// reset contact so that getContact() reads from database
@ -146,7 +155,7 @@ class LocalContact: AndroidContact, LocalAddress {
}
fun updateHashCode(batch: BatchOperation?) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
throw IllegalStateException("updateHashCode() should not be called on Android != 7")
val hashCode = dataHashCode()
@ -163,7 +172,7 @@ class LocalContact: AndroidContact, LocalAddress {
}
fun getLastHashCode(): Int {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
throw IllegalStateException("getLastHashCode() should not be called on Android != 7")
addressBook.provider!!.query(rawContactSyncURI(), arrayOf(COLUMN_HASHCODE), null, null, null)?.use { c ->

View file

@ -15,9 +15,16 @@ import android.provider.ContactsContract.Groups
import android.provider.ContactsContract.RawContacts
import android.provider.ContactsContract.RawContacts.Data
import at.bitfire.davdroid.log.Logger
import at.bitfire.vcard4android.*
import at.bitfire.vcard4android.AndroidAddressBook
import at.bitfire.vcard4android.AndroidContact
import at.bitfire.vcard4android.AndroidGroup
import at.bitfire.vcard4android.AndroidGroupFactory
import at.bitfire.vcard4android.BatchOperation
import at.bitfire.vcard4android.CachedGroupMembership
import at.bitfire.vcard4android.Contact
import org.apache.commons.lang3.StringUtils
import java.util.*
import java.util.LinkedList
import java.util.UUID
class LocalGroup: AndroidGroup, LocalAddress {
@ -80,7 +87,7 @@ class LocalGroup: AndroidGroup, LocalAddress {
changeContactIDs += missingMember.id!!
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
// workaround for Android 7 which sets DIRTY flag when only meta-data is changed
changeContactIDs
.map { addressBook.findContactById(it) }

View file

@ -24,7 +24,6 @@ import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.resource.LocalTask
import at.bitfire.davdroid.resource.TaskUtils
import at.bitfire.davdroid.syncadapter.SyncUtils
import at.bitfire.davdroid.util.closeCompat
import at.bitfire.davdroid.util.setAndVerifyUserData
import at.bitfire.ical4android.AndroidCalendar
import at.bitfire.ical4android.AndroidEvent
@ -216,7 +215,7 @@ class AccountSettingsMigrations(
}
}
} finally {
provider.closeCompat()
provider.close()
}
}
}
@ -256,7 +255,7 @@ class AccountSettingsMigrations(
provider.update(
CalendarContract.Calendars.CONTENT_URI.asSyncAdapter(account),
AndroidCalendar.calendarBaseValues, null, null)
provider.closeCompat()
provider.close()
}
}
@ -313,7 +312,7 @@ class AccountSettingsMigrations(
try {
AndroidCalendar.insertColors(provider, account)
} finally {
provider.closeCompat()
provider.close()
}
}
@ -377,7 +376,7 @@ class AccountSettingsMigrations(
throw ContactsStorageException("Couldn't migrate contacts to new address book", e)
} finally {
parcel.recycle()
provider.closeCompat()
provider.close()
}
}

View file

@ -19,7 +19,6 @@ import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.settings.Settings
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.util.closeCompat
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
@ -115,7 +114,7 @@ class AddressBookSyncer(context: Context): Syncer(context) {
LocalAddressBook.create(context, contactsProvider, account, info, forceAllReadOnly)
}
} finally {
contactsProvider?.closeCompat()
contactsProvider?.close()
}
return true

View file

@ -109,7 +109,7 @@ class ContactsSyncManager(
override fun prepare(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
// workaround for Android 7 which sets DIRTY flag when only meta-data is changed
val reallyDirty = localCollection.verifyDirty()
val deleted = localCollection.findDeleted().size
@ -371,7 +371,7 @@ class ContactsSyncManager(
syncResult.stats.numInserts++
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
// workaround for Android 7 which sets DIRTY flag when only meta-data is changed
(local as? LocalContact)?.updateHashCode(null)
}

View file

@ -13,7 +13,6 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.os.Build
import android.provider.CalendarContract
import android.provider.ContactsContract
import androidx.annotation.WorkerThread
@ -78,10 +77,7 @@ object SyncUtils {
}
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=${e.provider.packageName}"))
var flags = PendingIntent.FLAG_UPDATE_CURRENT
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
flags = flags or PendingIntent.FLAG_IMMUTABLE
val flags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
if (intent.resolveActivity(pm) != null)
notify.setContentIntent(PendingIntent.getActivity(context, 0, intent, flags))

View file

@ -47,7 +47,6 @@ import at.bitfire.davdroid.ui.NotificationUtils
import at.bitfire.davdroid.ui.NotificationUtils.notifyIfPossible
import at.bitfire.davdroid.ui.account.WifiPermissionsActivity
import at.bitfire.davdroid.util.PermissionUtils
import at.bitfire.davdroid.util.closeCompat
import at.bitfire.ical4android.TaskProvider
import com.google.common.util.concurrent.ListenableFuture
import dagger.assisted.Assisted
@ -312,7 +311,7 @@ class SyncWorker @AssistedInject constructor(
// Check internet connection
val ignoreVpns = AccountSettings(applicationContext, account).getIgnoreVpns()
val connectivityManager = applicationContext.getSystemService<ConnectivityManager>()!!
if (Build.VERSION.SDK_INT >= 23 && !internetAvailable(connectivityManager, ignoreVpns)) {
if (!internetAvailable(connectivityManager, ignoreVpns)) {
Logger.log.info("WorkManager started SyncWorker without Internet connection. Aborting.")
return Result.failure()
}
@ -368,7 +367,7 @@ class SyncWorker @AssistedInject constructor(
} catch (e: SecurityException) {
Logger.log.log(Level.WARNING, "Security exception when opening content provider for $authority")
} finally {
provider.closeCompat()
provider.close()
}
// Check for errors

View file

@ -15,7 +15,6 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.LayoutInflater
@ -108,14 +107,12 @@ class AccountListFragment: Fragment() {
}
model.dataSaverOn.observe(viewLifecycleOwner) { datasaverOn ->
binding.datasaverOnInfo.visibility = if (Build.VERSION.SDK_INT >= 24 && datasaverOn) View.VISIBLE else View.GONE
binding.datasaverOnInfo.visibility = if (datasaverOn) View.VISIBLE else View.GONE
}
binding.manageDatasaver.setOnClickListener {
if (Build.VERSION.SDK_INT >= 24) {
val intent = Intent(Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS, Uri.parse("package:" + requireActivity().packageName))
if (intent.resolveActivity(requireActivity().packageManager) != null)
startActivity(intent)
}
val intent = Intent(Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS, Uri.parse("package:" + requireActivity().packageName))
if (intent.resolveActivity(requireActivity().packageManager) != null)
startActivity(intent)
}
// Accounts adapter

View file

@ -15,6 +15,7 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.UiThread
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.getSystemService
import androidx.preference.*
import at.bitfire.cert4android.CustomCertStore
import at.bitfire.davdroid.BuildConfig
@ -148,21 +149,18 @@ class AppSettingsActivity: AppCompatActivity() {
// debug settings
findPreference<SwitchPreferenceCompat>(Settings.BATTERY_OPTIMIZATION)!!.apply {
// battery optimization exists since Android 6 (API level 23)
if (Build.VERSION.SDK_INT >= 23) {
val powerManager = requireActivity().getSystemService(PowerManager::class.java)
val whitelisted = powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)
isChecked = whitelisted
isEnabled = !whitelisted
onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, nowChecked ->
if (nowChecked as Boolean)
onBatteryOptimizationResult.launch(Intent(
android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
Uri.parse("package:" + BuildConfig.APPLICATION_ID)
))
false
}
} else
isVisible = false
val powerManager = requireActivity().getSystemService<PowerManager>()!!
val whitelisted = powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)
isChecked = whitelisted
isEnabled = !whitelisted
onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, nowChecked ->
if (nowChecked as Boolean)
onBatteryOptimizationResult.launch(Intent(
android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
Uri.parse("package:" + BuildConfig.APPLICATION_ID)
))
false
}
}
findPreference<SwitchPreferenceCompat>(Settings.FOREGROUND_SERVICE)!!.apply {

View file

@ -4,7 +4,12 @@
package at.bitfire.davdroid.ui
import android.content.*
import android.content.BroadcastReceiver
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SyncStatusObserver
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
@ -62,17 +67,15 @@ class AppWarningsManager @Inject constructor(
watchConnectivity()
// Data saver
if (Build.VERSION.SDK_INT >= 24) {
val listener = object: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
checkDataSaver()
}
val listener = object: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
checkDataSaver()
}
val dataSaverChangedFilter = IntentFilter(ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED)
context.registerReceiver(listener, dataSaverChangedFilter)
dataSaverChangedListener = listener
}
val dataSaverChangedFilter = IntentFilter(ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED)
context.registerReceiver(listener, dataSaverChangedFilter)
dataSaverChangedListener = listener
checkDataSaver()
}
@ -81,61 +84,39 @@ class AppWarningsManager @Inject constructor(
}
private fun watchConnectivity() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // API level <26
networkReceiver = object: BroadcastReceiver() {
init {
update()
}
networkAvailable.postValue(false)
override fun onReceive(context: Context?, intent: Intent?) = update()
// check for working (e.g. WiFi after captive portal login) Internet connection
val networkRequest = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
.build()
val callback = object: ConnectivityManager.NetworkCallback() {
val availableNetworks = hashSetOf<Network>()
private fun update() {
networkAvailable.postValue(connectivityManager.allNetworkInfo.any { it.isConnected })
}
override fun onAvailable(network: Network) {
availableNetworks += network
update()
}
@Suppress("DEPRECATION")
context.registerReceiver(networkReceiver,
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
)
} else { // API level >= 26
networkAvailable.postValue(false)
// check for working (e.g. WiFi after captive portal login) Internet connection
val networkRequest = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
.build()
val callback = object: ConnectivityManager.NetworkCallback() {
val availableNetworks = hashSetOf<Network>()
override fun onAvailable(network: Network) {
availableNetworks += network
update()
}
override fun onLost(network: Network) {
availableNetworks -= network
update()
}
private fun update() {
networkAvailable.postValue(availableNetworks.isNotEmpty())
}
override fun onLost(network: Network) {
availableNetworks -= network
update()
}
private fun update() {
networkAvailable.postValue(availableNetworks.isNotEmpty())
}
connectivityManager.registerNetworkCallback(networkRequest, callback)
networkCallback = callback
}
connectivityManager.registerNetworkCallback(networkRequest, callback)
networkCallback = callback
}
private fun checkDataSaver() {
dataSaverEnabled.postValue(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
context.getSystemService<ConnectivityManager>()?.let { connectivityManager ->
connectivityManager.restrictBackgroundStatus == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED
}
else
false
context.getSystemService<ConnectivityManager>()?.let { connectivityManager ->
connectivityManager.restrictBackgroundStatus == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED
}
)
}

View file

@ -43,7 +43,6 @@ import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.syncadapter.PeriodicSyncWorker
import at.bitfire.davdroid.syncadapter.SyncWorker
import at.bitfire.davdroid.util.closeCompat
import at.bitfire.ical4android.TaskProvider
import at.bitfire.ical4android.TaskProvider.ProviderName
import at.techbee.jtx.JtxContract
@ -375,10 +374,7 @@ class DebugInfoActivity : AppCompatActivity() {
}
// system info
val locales: Any = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
LocaleList.getAdjustedDefault()
else
Locale.getDefault()
val locales: Any = LocaleList.getAdjustedDefault()
writer.append(
"\nSYSTEM INFORMATION\n\n" +
"Android version: ${Build.VERSION.RELEASE} (${Build.DISPLAY})\n" +
@ -397,7 +393,7 @@ class DebugInfoActivity : AppCompatActivity() {
// connectivity
context.getSystemService<ConnectivityManager>()?.let { connectivityManager ->
writer.append("\nCONNECTIVITY\n\n")
val activeNetwork = if (Build.VERSION.SDK_INT >= 23) connectivityManager.activeNetwork else null
val activeNetwork = connectivityManager.activeNetwork
connectivityManager.allNetworks.sortedByDescending { it == activeNetwork }.forEach { network ->
val properties = connectivityManager.getLinkProperties(network)
connectivityManager.getNetworkCapabilities(network)?.let { capabilities ->
@ -417,19 +413,17 @@ class DebugInfoActivity : AppCompatActivity() {
}
writer.append('\n')
if (Build.VERSION.SDK_INT >= 23)
connectivityManager.defaultProxy?.let { proxy ->
writer.append("System default proxy: ${proxy.host}:${proxy.port}\n")
connectivityManager.defaultProxy?.let { proxy ->
writer.append("System default proxy: ${proxy.host}:${proxy.port}\n")
}
writer.append("Data saver: ").append(
when (connectivityManager.restrictBackgroundStatus) {
ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED -> "enabled"
ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED -> "whitelisted"
ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED -> "disabled"
else -> connectivityManager.restrictBackgroundStatus.toString()
}
if (Build.VERSION.SDK_INT >= 24)
writer.append("Data saver: ").append(
when (connectivityManager.restrictBackgroundStatus) {
ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED -> "enabled"
ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED -> "whitelisted"
ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED -> "disabled"
else -> connectivityManager.restrictBackgroundStatus.toString()
}
).append('\n')
).append('\n')
writer.append('\n')
}
@ -443,12 +437,11 @@ class DebugInfoActivity : AppCompatActivity() {
writer.append(" (RESTRICTED!)")
writer.append('\n')
}
if (Build.VERSION.SDK_INT >= 23)
context.getSystemService<PowerManager>()?.let { powerManager ->
writer.append("Power saving disabled: ")
.append(if (powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)) "yes" else "no")
.append('\n')
}
context.getSystemService<PowerManager>()?.let { powerManager ->
writer.append("Power saving disabled: ")
.append(if (powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)) "yes" else "no")
.append('\n')
}
// system-wide sync
writer.append("System-wide synchronization: ")
.append(if (ContentResolver.getMasterSyncAutomatically()) "automatically" else "manually")
@ -648,7 +641,7 @@ class DebugInfoActivity : AppCompatActivity() {
} catch (e: Exception) {
nrEntries = e.toString()
} finally {
client?.closeCompat()
client?.close()
}
val accountSettings = AccountSettings(context, account)
table.addLine(

View file

@ -15,7 +15,6 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.getSystemService
import androidx.core.content.res.ResourcesCompat
import at.bitfire.davdroid.App
import at.bitfire.davdroid.R
import at.bitfire.davdroid.log.Logger
import java.util.logging.Level
@ -77,15 +76,9 @@ object NotificationUtils {
}
}
fun newBuilder(context: Context, channel: String): NotificationCompat.Builder {
val builder = NotificationCompat.Builder(context, channel)
.setColor(ResourcesCompat.getColor(context.resources, R.color.primaryColor, null))
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
builder.setLargeIcon(App.getLauncherBitmap(context))
return builder
}
fun newBuilder(context: Context, channel: String): NotificationCompat.Builder =
NotificationCompat.Builder(context, channel)
.setColor(ResourcesCompat.getColor(context.resources, R.color.primaryColor, null))
fun NotificationManagerCompat.notifyIfPossible(tag: String?, id: Int, notification: Notification) {

View file

@ -9,7 +9,6 @@ import android.accounts.AccountManager
import android.accounts.OnAccountsUpdateListener
import android.app.Application
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
@ -141,28 +140,16 @@ class AccountActivity: AppCompatActivity() {
private fun deleteAccount() {
val accountManager = AccountManager.get(this)
if (Build.VERSION.SDK_INT >= 22)
accountManager.removeAccount(model.account, this, { future ->
try {
if (future.result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT))
Handler(Looper.getMainLooper()).post {
finish()
}
} catch(e: Exception) {
Logger.log.log(Level.SEVERE, "Couldn't remove account", e)
}
}, null)
else
accountManager.removeAccount(model.account, { future ->
try {
if (future.result)
Handler(Looper.getMainLooper()).post {
finish()
}
} catch (e: Exception) {
Logger.log.log(Level.SEVERE, "Couldn't remove account", e)
}
}, null)
accountManager.removeAccount(model.account, this, { future ->
try {
if (future.result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT))
Handler(Looper.getMainLooper()).post {
finish()
}
} catch(e: Exception) {
Logger.log.log(Level.SEVERE, "Couldn't remove account", e)
}
}, null)
}

View file

@ -35,7 +35,6 @@ import at.bitfire.davdroid.resource.LocalTaskList
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.syncadapter.AccountsCleanupWorker
import at.bitfire.davdroid.syncadapter.SyncWorker
import at.bitfire.davdroid.util.closeCompat
import at.bitfire.ical4android.TaskProvider
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
@ -211,7 +210,7 @@ class RenameAccountFragment: DialogFragment() {
addressBook.mainAccount = Account(newName, oldAccount.type)
}
} finally {
provider.closeCompat()
provider.close()
}
}
} catch (e: Exception) {

View file

@ -221,7 +221,6 @@ class SettingsActivity: AppCompatActivity() {
model.ignoreVpns.observe(viewLifecycleOwner) { ignoreVpns ->
it.isEnabled = true
it.isChecked = ignoreVpns
it.isVisible = Build.VERSION.SDK_INT >= 23
it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, prefValue ->
model.updateIgnoreVpns(prefValue as Boolean)
false

View file

@ -22,13 +22,12 @@ import androidx.lifecycle.*
import androidx.room.Transaction
import at.bitfire.dav4jvm.UrlUtils
import at.bitfire.davdroid.Constants
import at.bitfire.davdroid.util.PermissionUtils
import at.bitfire.davdroid.R
import at.bitfire.davdroid.util.closeCompat
import at.bitfire.davdroid.databinding.AccountCaldavItemBinding
import at.bitfire.davdroid.db.AppDatabase
import at.bitfire.davdroid.db.Collection
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.util.PermissionUtils
import com.google.android.material.snackbar.Snackbar
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@ -204,7 +203,7 @@ class WebcalFragment: CollectionsFragment() {
}
fun disconnect() {
value?.closeCompat()
value?.close()
value = null
}
}

View file

@ -21,15 +21,15 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.app.TaskStackBuilder
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.getSystemService
import androidx.core.content.getSystemService
import androidx.core.location.LocationManagerCompat
import androidx.core.text.HtmlCompat
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import at.bitfire.davdroid.util.PermissionUtils
import at.bitfire.davdroid.R
import at.bitfire.davdroid.databinding.ActivityWifiPermissionsBinding
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.util.PermissionUtils
class WifiPermissionsActivity: AppCompatActivity() {
@ -148,7 +148,7 @@ class WifiPermissionsActivity: AppCompatActivity() {
// Android 9+: location service
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
getSystemService(getApplication(), LocationManager::class.java)?.let { locationManager ->
getApplication<Application>().getSystemService<LocationManager>()?.let { locationManager ->
val locationEnabled = LocationManagerCompat.isLocationEnabled(locationManager)
isLocationEnabled.value = locationEnabled
needLocationEnabled.value = locationEnabled

View file

@ -55,14 +55,14 @@ class BatteryOptimizationsFragment: Fragment() {
binding.lifecycleOwner = viewLifecycleOwner
binding.model = model
model.shouldBeWhitelisted.observe(viewLifecycleOwner, { shouldBeWhitelisted ->
model.shouldBeWhitelisted.observe(viewLifecycleOwner) { shouldBeWhitelisted ->
@SuppressLint("BatteryLife")
if (shouldBeWhitelisted && !model.isWhitelisted.value!! && Build.VERSION.SDK_INT >= 23)
startActivityForResult(Intent(
android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
Uri.parse("package:" + BuildConfig.APPLICATION_ID)
), REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
})
if (shouldBeWhitelisted && !model.isWhitelisted.value!!)
startActivityForResult(Intent(
android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
Uri.parse("package:" + BuildConfig.APPLICATION_ID)
), REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
}
binding.batteryText.text = getString(R.string.intro_battery_text, getString(R.string.app_name))
binding.autostartHeading.text = getString(R.string.intro_autostart_title, WordUtils.capitalize(Build.MANUFACTURER))
@ -135,11 +135,7 @@ class BatteryOptimizationsFragment: Fragment() {
(evilManufacturers.contains(Build.MANUFACTURER.lowercase(Locale.ROOT)) || BuildConfig.DEBUG)
fun isWhitelisted(context: Context) =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val powerManager = context.getSystemService<PowerManager>()!!
powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)
} else
true
context.getSystemService<PowerManager>()!!.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)
}
val shouldBeWhitelisted = MutableLiveData<Boolean>()

View file

@ -5,7 +5,6 @@
package at.bitfire.davdroid.ui.intro
import android.content.Context
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -30,10 +29,6 @@ class TasksIntroFragment : Fragment() {
): IntroFragmentFactory {
override fun getOrder(context: Context): Int {
// On Android <6, OpenTasks must be installed before DAVx5, so this fragment is not useful.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
return IntroFragmentFactory.DONT_SHOW
return if (!TaskUtils.isAvailable(context) && settingsManager.getBooleanOrNull(TasksFragment.Model.HINT_OPENTASKS_NOT_INSTALLED) != false)
10
else
@ -44,4 +39,4 @@ class TasksIntroFragment : Fragment() {
}
}
}

View file

@ -6,8 +6,6 @@ package at.bitfire.davdroid.util
import android.accounts.Account
import android.accounts.AccountManager
import android.content.ContentProviderClient
import android.os.Build
import at.bitfire.davdroid.log.Logger
/**
@ -26,12 +24,4 @@ fun AccountManager.setAndVerifyUserData(account: Account, key: String, value: St
Thread.sleep(100)
}
Logger.log.warning("AccountManager failed to set $account user data $key := $value")
}
@Suppress("DEPRECATION")
fun ContentProviderClient.closeCompat() {
if (Build.VERSION.SDK_INT >= 24)
close()
else
release()
}

View file

@ -15,6 +15,7 @@ import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.location.LocationManagerCompat
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.R
@ -61,7 +62,7 @@ object PermissionUtils {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)
true // Android <9 doesn't require active location services
else
ContextCompat.getSystemService(context, LocationManager::class.java)?.let { locationManager ->
context.getSystemService<LocationManager>()?.let { locationManager ->
LocationManagerCompat.isLocationEnabled(locationManager)
} ?: /* location feature not available on this device */ false

View file

@ -15,7 +15,7 @@ import android.system.ErrnoException
import android.system.OsConstants
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import at.bitfire.dav4jvm.DavResource
import at.bitfire.dav4jvm.HttpUtils
import at.bitfire.dav4jvm.exception.DavException
@ -63,7 +63,7 @@ class RandomAccessCallback private constructor(
Logger.log.info("Creating memory cache")
val maxHeapSizeMB = ContextCompat.getSystemService(context, ActivityManager::class.java)!!.memoryClass
val maxHeapSizeMB = context.getSystemService<ActivityManager>()!!.memoryClass
val cacheSize = maxHeapSizeMB * FileUtils.ONE_MB.toInt() / 2
val newCache = MemorySegmentCache(cacheSize)

View file

@ -9,14 +9,15 @@ import android.graphics.Point
import android.os.Build
import android.os.storage.StorageManager
import androidx.annotation.WorkerThread
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import at.bitfire.davdroid.db.WebDavDocument
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.webdav.cache.CacheUtils
import at.bitfire.davdroid.webdav.cache.DiskCache
import org.apache.commons.io.FileUtils
import java.io.File
import java.util.*
import java.util.LinkedList
import java.util.UUID
@WorkerThread
class ThumbnailCache(context: Context) {
@ -24,7 +25,7 @@ class ThumbnailCache(context: Context) {
val cache: DiskCache
init {
val storageManager = ContextCompat.getSystemService(context, StorageManager::class.java)!!
val storageManager = context.getSystemService<StorageManager>()!!
val cacheDir = File(context.cacheDir, "webdav/thumbnail")
val maxBytes = if (Build.VERSION.SDK_INT >= 26)
storageManager.getCacheQuotaBytes(storageManager.getUuidForPath(cacheDir)) / 2

View file

@ -13,10 +13,10 @@ buildscript {
okhttp: '4.11.0',
room: '2.5.2',
workManager: '2.8.1',
// latest Apache Commons versions that don't require Java 8 (Android 7)
commonsCollections: '4.2',
commonsLang: '3.8.1',
commonsText: '1.3',
// Apache Commons versions
commonsCollections: '4.4',
commonsLang: '3.13.0',
commonsText: '1.10.0',
// own libraries
cert4android: '2bb3898',
dav4jvm: 'da94a8b',