Catch StaleDataException in ContactLoader
This commit is contained in:
parent
ae04a06e42
commit
4d6f614df8
1 changed files with 120 additions and 108 deletions
|
@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue