Fixed presence storage in native contacts + prevent duplicated SIP addresses in same contact + improved contact fetching used memory
This commit is contained in:
parent
6222758126
commit
ed03a721a5
4 changed files with 38 additions and 49 deletions
|
@ -119,7 +119,6 @@ class ContactsSettingsFragment : GenericSettingFragment<SettingsContactsFragment
|
||||||
if (granted) {
|
if (granted) {
|
||||||
Log.i("[Contacts Settings] WRITE_CONTACTS permission granted")
|
Log.i("[Contacts Settings] WRITE_CONTACTS permission granted")
|
||||||
corePreferences.storePresenceInNativeContact = true
|
corePreferences.storePresenceInNativeContact = true
|
||||||
coreContext.contactsManager.storePresenceInformationForAllContacts()
|
|
||||||
} else {
|
} else {
|
||||||
Log.w("[Contacts Settings] WRITE_CONTACTS permission denied")
|
Log.w("[Contacts Settings] WRITE_CONTACTS permission denied")
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,7 @@ import kotlinx.coroutines.withContext
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.core.Factory
|
import org.linphone.core.*
|
||||||
import org.linphone.core.Friend
|
|
||||||
import org.linphone.core.GlobalState
|
|
||||||
import org.linphone.core.SubscribePolicy
|
|
||||||
import org.linphone.core.tools.Log
|
import org.linphone.core.tools.Log
|
||||||
import org.linphone.utils.PhoneNumberUtils
|
import org.linphone.utils.PhoneNumberUtils
|
||||||
|
|
||||||
|
@ -76,7 +73,7 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
projection,
|
projection,
|
||||||
selection,
|
selection,
|
||||||
null,
|
null,
|
||||||
null
|
ContactsContract.Data.CONTACT_ID + " ASC"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +98,9 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
// Cursor can be null now that we are on a different dispatcher according to Crashlytics
|
// Cursor can be null now that we are on a different dispatcher according to Crashlytics
|
||||||
val friendsPhoneNumbers = HashMap<String, List<String>>()
|
val friendsPhoneNumbers = arrayListOf<String>()
|
||||||
|
val friendsAddresses = arrayListOf<Address>()
|
||||||
|
var previousId = ""
|
||||||
while (cursor != null && !cursor.isClosed && cursor.moveToNext()) {
|
while (cursor != null && !cursor.isClosed && cursor.moveToNext()) {
|
||||||
try {
|
try {
|
||||||
val id: String =
|
val id: String =
|
||||||
|
@ -123,6 +122,12 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
val lookupKey =
|
val lookupKey =
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.LOOKUP_KEY))
|
cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.LOOKUP_KEY))
|
||||||
|
|
||||||
|
if (previousId.isEmpty() || previousId != id) {
|
||||||
|
friendsPhoneNumbers.clear()
|
||||||
|
friendsAddresses.clear()
|
||||||
|
previousId = id
|
||||||
|
}
|
||||||
|
|
||||||
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()) {
|
||||||
|
@ -143,9 +148,6 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
friend.incSubscribePolicy = SubscribePolicy.SPDeny
|
friend.incSubscribePolicy = SubscribePolicy.SPDeny
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!friendsPhoneNumbers.containsKey(id)) {
|
|
||||||
friendsPhoneNumbers[id] = arrayListOf()
|
|
||||||
}
|
|
||||||
when (mime) {
|
when (mime) {
|
||||||
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
|
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
|
||||||
val label = PhoneNumberUtils.addressBookLabelTypeToVcardParamString(
|
val label = PhoneNumberUtils.addressBookLabelTypeToVcardParamString(
|
||||||
|
@ -165,26 +167,32 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
|
|
||||||
if (number != null) {
|
if (number != null) {
|
||||||
if (
|
if (
|
||||||
friendsPhoneNumbers[id].orEmpty().find {
|
friendsPhoneNumbers.find {
|
||||||
PhoneNumberUtils.arePhoneNumberWeakEqual(it, number)
|
PhoneNumberUtils.arePhoneNumberWeakEqual(it, number)
|
||||||
} == null
|
} == null
|
||||||
) {
|
) {
|
||||||
val phoneNumber = Factory.instance()
|
val phoneNumber = Factory.instance()
|
||||||
.createFriendPhoneNumber(number, label)
|
.createFriendPhoneNumber(number, label)
|
||||||
friend.addPhoneNumberWithLabel(phoneNumber)
|
friend.addPhoneNumberWithLabel(phoneNumber)
|
||||||
friendsPhoneNumbers[id] = friendsPhoneNumbers[id].orEmpty().plus(number)
|
friendsPhoneNumbers.add(number)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
linphoneMime, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE -> {
|
linphoneMime, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE -> {
|
||||||
if (data1 == null) continue
|
if (data1 == null) continue
|
||||||
val address = core.interpretUrl(data1) ?: continue
|
val address = core.interpretUrl(data1) ?: continue
|
||||||
|
if (
|
||||||
|
friendsAddresses.find {
|
||||||
|
it.weakEqual(address)
|
||||||
|
} == null
|
||||||
|
) {
|
||||||
friend.addAddress(address)
|
friend.addAddress(address)
|
||||||
|
friendsAddresses.add(address)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE -> {
|
ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE -> {
|
||||||
if (data1 == null) continue
|
if (data1 == null) continue
|
||||||
val vCard = friend.vcard
|
friend.organization = data1
|
||||||
vCard?.organization = data1
|
|
||||||
}
|
}
|
||||||
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE -> {
|
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE -> {
|
||||||
if (data2 == null && data3 == null) continue
|
if (data2 == null && data3 == null) continue
|
||||||
|
@ -199,7 +207,6 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
Log.e("[Contacts Loader] Exception: $e")
|
Log.e("[Contacts Loader] Exception: $e")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
friendsPhoneNumbers.clear()
|
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
if (core.globalState == GlobalState.Shutdown || core.globalState == GlobalState.Off) {
|
if (core.globalState == GlobalState.Shutdown || core.globalState == GlobalState.Off) {
|
||||||
|
|
|
@ -275,40 +275,19 @@ class ContactsManager(private val context: Context) {
|
||||||
notifyListeners(friend)
|
notifyListeners(friend)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
fun storePresenceInformationForAllContacts() {
|
|
||||||
if (corePreferences.storePresenceInNativeContact && PermissionHelper.get().hasWriteContactsPermission()) {
|
|
||||||
for (list in coreContext.core.friendsLists) {
|
|
||||||
for (friend in list.friends) {
|
|
||||||
val id = friend.refKey
|
|
||||||
if (id != null) {
|
|
||||||
storePresenceInNativeContact(friend)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun storePresenceInNativeContact(friend: Friend) {
|
private fun storePresenceInNativeContact(friend: Friend) {
|
||||||
|
val contactEditor = NativeContactEditor(friend)
|
||||||
for (phoneNumber in friend.phoneNumbers) {
|
for (phoneNumber in friend.phoneNumbers) {
|
||||||
val sipAddress = friend.getContactForPhoneNumberOrAddress(phoneNumber)
|
val sipAddress = friend.getContactForPhoneNumberOrAddress(phoneNumber)
|
||||||
if (sipAddress != null) {
|
if (sipAddress != null) {
|
||||||
Log.d("[Contacts Manager] Found presence information to store in native contact $friend under Linphone sync account")
|
Log.d("[Contacts Manager] Found presence information to store in native contact $friend under Linphone sync account")
|
||||||
val contactEditor = NativeContactEditor(friend)
|
|
||||||
val coroutineScope = CoroutineScope(Dispatchers.Main)
|
|
||||||
coroutineScope.launch {
|
|
||||||
val deferred = async {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
contactEditor.setPresenceInformation(
|
contactEditor.setPresenceInformation(
|
||||||
phoneNumber,
|
phoneNumber,
|
||||||
sipAddress
|
sipAddress
|
||||||
).commit()
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
deferred.await()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
contactEditor.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createFriendFromSearchResult(searchResult: SearchResult): Friend {
|
fun createFriendFromSearchResult(searchResult: SearchResult): Friend {
|
||||||
|
|
|
@ -103,7 +103,7 @@ class NativeContactEditor(val friend: Friend) {
|
||||||
if (rawId == null) {
|
if (rawId == null) {
|
||||||
try {
|
try {
|
||||||
rawId = cursor.getString(cursor.getColumnIndexOrThrow(RawContacts._ID))
|
rawId = cursor.getString(cursor.getColumnIndexOrThrow(RawContacts._ID))
|
||||||
Log.i("[Native Contact Editor] Found raw id $rawId for native contact with id ${friend.refKey}")
|
Log.d("[Native Contact Editor] Found raw id $rawId for native contact with id ${friend.refKey}")
|
||||||
} catch (iae: IllegalArgumentException) {
|
} catch (iae: IllegalArgumentException) {
|
||||||
Log.e("[Native Contact Editor] Exception: $iae")
|
Log.e("[Native Contact Editor] Exception: $iae")
|
||||||
}
|
}
|
||||||
|
@ -484,15 +484,19 @@ class NativeContactEditor(val friend: Friend) {
|
||||||
} else null
|
} else null
|
||||||
cursor?.close()
|
cursor?.close()
|
||||||
|
|
||||||
|
val address = if (sipAddress.endsWith(";user=phone")) {
|
||||||
|
sipAddress.substring(0, sipAddress.length - ";user=phone".length)
|
||||||
|
} else sipAddress
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
Log.i("[Native Contact Editor] No existing presence information found for this phone number & SIP address, let's add it")
|
Log.i("[Native Contact Editor] No existing presence information found for this phone number ($phoneNumber) & SIP address ($address), let's add it")
|
||||||
addPresenceLinphoneSipAddressForPhoneNumber(sipAddress, phoneNumber)
|
addPresenceLinphoneSipAddressForPhoneNumber(address, phoneNumber)
|
||||||
} else {
|
} else {
|
||||||
if (data1 != null && data1 == sipAddress) {
|
if (data1 != null && data1 == address) {
|
||||||
Log.d("[Native Contact Editor] There is already an entry for this phone number and SIP address, skipping")
|
Log.d("[Native Contact Editor] There is already an entry for this phone number and SIP address, skipping")
|
||||||
} else {
|
} else {
|
||||||
Log.w("[Native Contact Editor] There is already an entry for this phone number but not for the same SIP address")
|
Log.w("[Native Contact Editor] There is already an entry for this phone number ($phoneNumber) but not for the same SIP address ($data1 != $address)")
|
||||||
updatePresenceLinphoneSipAddressForPhoneNumber(sipAddress, phoneNumber)
|
updatePresenceLinphoneSipAddressForPhoneNumber(address, phoneNumber)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue