Catch StaleDataException in ContactLoader

This commit is contained in:
Sylvain Berfini 2022-04-12 15:31:02 +02:00
parent ae04a06e42
commit 4d6f614df8

View file

@ -21,6 +21,7 @@ package org.linphone.contact
import android.content.ContentUris import android.content.ContentUris
import android.database.Cursor import android.database.Cursor
import android.database.StaleDataException
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.provider.ContactsContract import android.provider.ContactsContract
@ -31,6 +32,7 @@ import androidx.loader.content.CursorLoader
import androidx.loader.content.Loader import androidx.loader.content.Loader
import java.lang.Exception import java.lang.Exception
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
@ -79,127 +81,137 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
val friends = HashMap<String, Friend>() val friends = HashMap<String, Friend>()
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
while (!cursor.isClosed && cursor.moveToNext()) { try {
try { while (!cursor.isClosed && cursor.moveToNext()) {
val id: String = try {
cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Data.CONTACT_ID)) val id: String =
val displayName: String? = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Data.CONTACT_ID))
cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Data.DISPLAY_NAME_PRIMARY)) val displayName: String? =
val mime: String? = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Data.DISPLAY_NAME_PRIMARY))
cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Data.MIMETYPE)) val mime: String? =
val data1: String? = cursor.getString(cursor.getColumnIndexOrThrow("data1")) cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Data.MIMETYPE))
val data2: String? = cursor.getString(cursor.getColumnIndexOrThrow("data2")) val data1: String? =
val data3: String? = cursor.getString(cursor.getColumnIndexOrThrow("data3")) cursor.getString(cursor.getColumnIndexOrThrow("data1"))
val data4: String? = cursor.getString(cursor.getColumnIndexOrThrow("data4")) val data2: String? =
val starred = cursor.getString(cursor.getColumnIndexOrThrow("data2"))
cursor.getInt(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.STARRED)) == 1 val data3: String? =
val lookupKey = cursor.getString(cursor.getColumnIndexOrThrow("data3"))
cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.LOOKUP_KEY)) val data4: String? =
cursor.getString(cursor.getColumnIndexOrThrow("data4"))
val starred =
cursor.getInt(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.STARRED)) == 1
val lookupKey =
cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.LOOKUP_KEY))
val friend = friends[id] ?: core.createFriend() val friend = friends[id] ?: core.createFriend()
friend.refKey = id friend.refKey = id
if (friend.name.isNullOrEmpty()) { if (friend.name.isNullOrEmpty()) {
friend.name = displayName friend.name = displayName
friend.photo = Uri.withAppendedPath( friend.photo = Uri.withAppendedPath(
ContentUris.withAppendedId( ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI, ContactsContract.Contacts.CONTENT_URI,
id.toLong() id.toLong()
), ),
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY ContactsContract.Contacts.Photo.CONTENT_DIRECTORY
).toString()
friend.starred = starred
friend.nativeUri =
"${ContactsContract.Contacts.CONTENT_LOOKUP_URI}/$lookupKey"
}
when (mime) {
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
val typeLabel = ContactsContract.CommonDataKinds.Phone.getTypeLabel(
loader.context.resources,
data2?.toInt() ?: 0,
data3
).toString() ).toString()
friend.starred = starred
friend.nativeUri =
"${ContactsContract.Contacts.CONTENT_LOOKUP_URI}/$lookupKey"
}
val number = when (mime) {
if (corePreferences.preferNormalizedPhoneNumbersFromAddressBook || ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
data1.isNullOrEmpty() || val typeLabel =
!Patterns.PHONE.matcher(data1).matches() ContactsContract.CommonDataKinds.Phone.getTypeLabel(
) { loader.context.resources,
data4 ?: data1 data2?.toInt() ?: 0,
} else { data3
data1 ).toString()
}
if (number != null) { val number =
var duplicate = false if (corePreferences.preferNormalizedPhoneNumbersFromAddressBook ||
for (pn in friend.phoneNumbersWithLabel) { data1.isNullOrEmpty() ||
if (pn.label == typeLabel && LinphoneUtils.arePhoneNumberWeakEqual( !Patterns.PHONE.matcher(data1).matches()
pn.phoneNumber,
number
)
) { ) {
duplicate = true data4 ?: data1
break } else {
data1
}
if (number != null) {
var duplicate = false
for (pn in friend.phoneNumbersWithLabel) {
if (pn.label == typeLabel && LinphoneUtils.arePhoneNumberWeakEqual(
pn.phoneNumber,
number
)
) {
duplicate = true
break
}
}
if (!duplicate) {
val phoneNumber = Factory.instance()
.createFriendPhoneNumber(number, typeLabel)
friend.addPhoneNumberWithLabel(phoneNumber)
} }
} }
if (!duplicate) { }
val phoneNumber = Factory.instance() linphoneMime, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE -> {
.createFriendPhoneNumber(number, typeLabel) if (data1 == null) continue
friend.addPhoneNumberWithLabel(phoneNumber) val address = core.interpretUrl(data1) ?: continue
} friend.addAddress(address)
}
ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE -> {
if (data1 == null) continue
val vCard = friend.vcard
vCard?.organization = data1
}
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE -> {
if (data2 == null && data3 == null) continue
val vCard = friend.vcard
vCard?.givenName = data2
vCard?.familyName = data3
} }
} }
linphoneMime, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE -> {
if (data1 == null) continue
val address = core.interpretUrl(data1) ?: continue
friend.addAddress(address)
}
ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE -> {
if (data1 == null) continue
val vCard = friend.vcard
vCard?.organization = data1
}
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE -> {
if (data2 == null && data3 == null) continue
val vCard = friend.vcard
vCard?.givenName = data2
vCard?.familyName = data3
}
}
friends[id] = friend friends[id] = friend
} catch (e: Exception) { } catch (e: Exception) {
Log.e("[Contacts Loader] Exception: $e") Log.e("[Contacts Loader] Exception: $e")
}
}
withContext(Dispatchers.Main) {
Log.i("[Contacts Loader] Friends created")
val contactId = coreContext.contactsManager.contactIdToWatchFor
if (contactId.isNotEmpty()) {
val friend = friends[contactId]
Log.i("[Contacts Loader] Manager was asked to monitor contact id $contactId")
if (friend != null) {
Log.i("[Contacts Loader] Found new contact matching id $contactId, notifying listeners")
coreContext.contactsManager.notifyListeners(friend)
} }
} }
val fl = core.defaultFriendList ?: core.createFriendList() withContext(Dispatchers.Main) {
for (friend in fl.friends) { Log.i("[Contacts Loader] Friends created")
fl.removeFriend(friend) val contactId = coreContext.contactsManager.contactIdToWatchFor
if (contactId.isNotEmpty()) {
val friend = friends[contactId]
Log.i("[Contacts Loader] Manager was asked to monitor contact id $contactId")
if (friend != null) {
Log.i("[Contacts Loader] Found new contact matching id $contactId, notifying listeners")
coreContext.contactsManager.notifyListeners(friend)
}
}
val fl = core.defaultFriendList ?: core.createFriendList()
for (friend in fl.friends) {
fl.removeFriend(friend)
}
if (fl != core.defaultFriendList) core.addFriendList(fl)
val friendsList = friends.values
for (friend in friendsList) {
fl.addLocalFriend(friend)
}
fl.updateSubscriptions()
Log.i("[Contacts Loader] Friends added & subscription updated")
coreContext.contactsManager.fetchFinished()
} }
} catch (sde: StaleDataException) {
if (fl != core.defaultFriendList) core.addFriendList(fl) Log.e("[Contacts Loader] State Data Exception: $sde")
cancel()
val friendsList = friends.values
for (friend in friendsList) {
fl.addLocalFriend(friend)
}
fl.updateSubscriptions()
Log.i("[Contacts Loader] Friends added & subscription updated")
coreContext.contactsManager.fetchFinished()
} }
} }
} }