diff --git a/app/build.gradle b/app/build.gradle index b0156352..c9654edf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -56,6 +56,6 @@ android { } dependencies { - implementation 'com.simplemobiletools:commons:5.28.21' + implementation 'com.simplemobiletools:commons:5.28.25' implementation 'com.github.tibbi:IndicatorFastScroll:08f512858a' } diff --git a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/RecentsHelper.kt b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/RecentsHelper.kt index 0bb73e0d..977b0aa8 100644 --- a/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/RecentsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/dialer/helpers/RecentsHelper.kt @@ -4,76 +4,108 @@ import android.annotation.SuppressLint import android.content.Context import android.provider.CallLog.Calls import com.simplemobiletools.commons.extensions.* -import com.simplemobiletools.commons.helpers.PERMISSION_READ_CALL_LOG -import com.simplemobiletools.commons.helpers.ensureBackgroundThread -import com.simplemobiletools.commons.helpers.getQuestionMarks -import com.simplemobiletools.dialer.extensions.config +import com.simplemobiletools.commons.helpers.* +import com.simplemobiletools.commons.models.SimpleContact import com.simplemobiletools.dialer.extensions.getAvailableSIMCardLabels import com.simplemobiletools.dialer.models.RecentCall class RecentsHelper(private val context: Context) { + private val COMPARABLE_PHONE_NUMBER_LENGTH = 9 + @SuppressLint("MissingPermission") fun getRecentCalls(callback: (ArrayList) -> Unit) { + val privateCursor = context.getMyContactsContentProviderCursorLoader().loadInBackground() ensureBackgroundThread { - var recentCalls = ArrayList() if (!context.hasPermission(PERMISSION_READ_CALL_LOG)) { - callback(recentCalls) + callback(ArrayList()) return@ensureBackgroundThread } - val uri = Calls.CONTENT_URI - val projection = arrayOf( - Calls._ID, - Calls.NUMBER, - Calls.CACHED_NAME, - Calls.CACHED_PHOTO_URI, - Calls.DATE, - Calls.DURATION, - Calls.TYPE, - "phone_account_address" - ) - - val numberToSimIDMap = HashMap() - context.getAvailableSIMCardLabels().forEach { - numberToSimIDMap[it.phoneNumber] = it.id - } - - val sortOrder = "${Calls._ID} DESC LIMIT 100" - - var previousRecentCallFrom = "" - context.queryCursor(uri, projection, sortOrder = sortOrder, showErrors = true) { cursor -> - val id = cursor.getIntValue(Calls._ID) - val number = cursor.getStringValue(Calls.NUMBER) - var name = cursor.getStringValue(Calls.CACHED_NAME) - if (name == null || name.isEmpty()) { - name = number + SimpleContactsHelper(context).getAvailableContacts(false) { contacts -> + val privateContacts = MyContactsContentProvider.getSimpleContacts(context, privateCursor) + if (privateContacts.isNotEmpty()) { + contacts.addAll(privateContacts) } - val photoUri = cursor.getStringValue(Calls.CACHED_PHOTO_URI) ?: "" - val startTS = (cursor.getLongValue(Calls.DATE) / 1000L).toInt() - val duration = cursor.getIntValue(Calls.DURATION) - val type = cursor.getIntValue(Calls.TYPE) - val accountAddress = cursor.getStringValue("phone_account_address") - val simID = numberToSimIDMap[accountAddress] ?: 1 - val neighbourIDs = ArrayList() - val recentCall = RecentCall(id, number, name, photoUri, startTS, duration, type, neighbourIDs, simID) - - // if we have 3 missed calls from the same number, show it just once - if ("$number$name" != previousRecentCallFrom) { - recentCalls.add(recentCall) - } else { - recentCalls.lastOrNull()?.neighbourIDs?.add(id) - } - - previousRecentCallFrom = "$number$name" + getRecents(contacts, callback) } - - val blockedNumbers = context.getBlockedNumbers() - recentCalls = recentCalls.filter { !context.isNumberBlocked(it.phoneNumber, blockedNumbers) }.toMutableList() as ArrayList - callback(recentCalls) } } + private fun getRecents(contacts: ArrayList, callback: (ArrayList) -> Unit) { + var recentCalls = ArrayList() + val uri = Calls.CONTENT_URI + val projection = arrayOf( + Calls._ID, + Calls.NUMBER, + Calls.CACHED_NAME, + Calls.CACHED_PHOTO_URI, + Calls.DATE, + Calls.DURATION, + Calls.TYPE, + "phone_account_address" + ) + + val numberToSimIDMap = HashMap() + context.getAvailableSIMCardLabels().forEach { + numberToSimIDMap[it.phoneNumber] = it.id + } + + val sortOrder = "${Calls._ID} DESC LIMIT 100" + var previousRecentCallFrom = "" + val contactsNumbersMap = HashMap() + context.queryCursor(uri, projection, sortOrder = sortOrder, showErrors = true) { cursor -> + val id = cursor.getIntValue(Calls._ID) + val number = cursor.getStringValue(Calls.NUMBER) + var name = cursor.getStringValue(Calls.CACHED_NAME) + if (name == null || name.isEmpty()) { + name = number + } + + if (name == number) { + if (contactsNumbersMap.containsKey(number)) { + name = contactsNumbersMap[number]!! + } else { + val normalizedNumber = number.normalizePhoneNumber() + if (normalizedNumber!!.length >= COMPARABLE_PHONE_NUMBER_LENGTH) { + name = contacts.firstOrNull { contact -> + val curNumber = contact.phoneNumber.normalizePhoneNumber() + if (curNumber!!.length >= COMPARABLE_PHONE_NUMBER_LENGTH) { + if (curNumber.substring(curNumber.length - COMPARABLE_PHONE_NUMBER_LENGTH) == normalizedNumber.substring(normalizedNumber.length - COMPARABLE_PHONE_NUMBER_LENGTH)) { + contactsNumbersMap[number] = contact.name + return@firstOrNull true + } + } + false + }?.name ?: number + } + } + } + + val photoUri = cursor.getStringValue(Calls.CACHED_PHOTO_URI) ?: "" + val startTS = (cursor.getLongValue(Calls.DATE) / 1000L).toInt() + val duration = cursor.getIntValue(Calls.DURATION) + val type = cursor.getIntValue(Calls.TYPE) + val accountAddress = cursor.getStringValue("phone_account_address") + val simID = numberToSimIDMap[accountAddress] ?: 1 + val neighbourIDs = ArrayList() + val recentCall = RecentCall(id, number, name, photoUri, startTS, duration, type, neighbourIDs, simID) + + // if we have multiple missed calls from the same number, show it just once + if ("$number$name" != previousRecentCallFrom) { + recentCalls.add(recentCall) + } else { + recentCalls.lastOrNull()?.neighbourIDs?.add(id) + } + + previousRecentCallFrom = "$number$name" + } + + val blockedNumbers = context.getBlockedNumbers() + recentCalls = recentCalls.filter { !context.isNumberBlocked(it.phoneNumber, blockedNumbers) }.toMutableList() as ArrayList + callback(recentCalls) + } + @SuppressLint("MissingPermission") fun removeRecentCalls(ids: ArrayList, callback: () -> Unit) { ensureBackgroundThread {