Skip to content

Commit d497edd

Browse files
committed
Enhance calls performance
1 parent d9846cc commit d497edd

4 files changed

Lines changed: 67 additions & 16 deletions

File tree

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.ismartcoding.plain.data
22

3-
import com.ismartcoding.lib.phonegeo.PhoneNumberLookup
4-
import com.ismartcoding.lib.phonegeo.algo.LookupAlgorithm
3+
import com.ismartcoding.plain.features.call.PhoneGeoCache
54
import com.ismartcoding.plain.web.models.PhoneGeo
65
import kotlin.time.Instant
76

@@ -15,11 +14,5 @@ data class DCall(
1514
var type: Int,
1615
val accountId: String,
1716
) : IData {
18-
fun getGeo(): PhoneGeo? {
19-
var geo: PhoneGeo? = null
20-
PhoneNumberLookup.instance().with(LookupAlgorithm.IMPL.BINARY_SEARCH).lookup(number)?.let {
21-
geo = PhoneGeo(it.geoInfo.province, it.geoInfo.city, it.geoInfo.zipCode, it.geoInfo.areaCode, it.isp.code)
22-
}
23-
return geo
24-
}
17+
fun getGeo(): PhoneGeo? = PhoneGeoCache.lookup(number)
2518
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.ismartcoding.plain.features.call
2+
3+
import androidx.collection.LruCache
4+
import com.ismartcoding.lib.phonegeo.PhoneNumberLookup
5+
import com.ismartcoding.lib.phonegeo.algo.LookupAlgorithm
6+
import com.ismartcoding.plain.web.models.PhoneGeo
7+
8+
/**
9+
* LRU cache for phone-number -> PhoneGeo lookups.
10+
*
11+
* `PhoneNumberLookup` does an in-memory binary search on a 4MB phone.dat
12+
* (avg ~19 comparisons, 1-5ms per call). For a 200-row calls page the
13+
* same numbers repeat heavily, so caching by raw number string —
14+
* including misses for short or unknown numbers — collapses that cost
15+
* to one lookup per unique number.
16+
*
17+
* `LruCache` rejects nullable value types, so a single shared sentinel
18+
* stands in for the "not found" case.
19+
*/
20+
object PhoneGeoCache {
21+
private const val MAX_SIZE = 1024
22+
private val MISS: PhoneGeo = PhoneGeo("", "", "", "", 0)
23+
private val cache = object : LruCache<String, PhoneGeo>(MAX_SIZE) {
24+
override fun sizeOf(key: String, value: PhoneGeo): Int = 1
25+
}
26+
27+
fun lookup(number: String): PhoneGeo? {
28+
cache[number]?.let { return it.takeIf { it !== MISS } }
29+
val geo = lookupFresh(number)
30+
cache.put(number, geo ?: MISS)
31+
return geo
32+
}
33+
34+
private fun lookupFresh(number: String): PhoneGeo? =
35+
PhoneNumberLookup.instance()
36+
.with(LookupAlgorithm.IMPL.BINARY_SEARCH)
37+
.lookup(number)
38+
?.let { PhoneGeo(it.geoInfo.province, it.geoInfo.city, it.geoInfo.zipCode, it.geoInfo.areaCode, it.isp.code) }
39+
}

app/src/main/java/com/ismartcoding/plain/features/media/CallMediaStoreHelper.kt

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ import android.net.Uri
66
import android.provider.BaseColumns
77
import android.provider.CallLog
88
import com.ismartcoding.lib.content.ContentWhere
9-
import com.ismartcoding.lib.data.SortBy
10-
import com.ismartcoding.lib.data.enums.SortDirection
119
import com.ismartcoding.lib.extensions.getIntValue
12-
import com.ismartcoding.lib.extensions.getPagingCursor
1310
import com.ismartcoding.lib.extensions.getStringValue
1411
import com.ismartcoding.lib.extensions.getTimeValue
1512
import com.ismartcoding.lib.extensions.map
@@ -75,9 +72,17 @@ object CallMediaStoreHelper : BaseContentHelper() {
7572
limit: Int,
7673
offset: Int,
7774
): List<DCall> {
78-
return context.contentResolver.getPagingCursor(
79-
uriExternal, getProjection(), buildWhereAsync(query),
80-
limit, offset, SortBy(CallLog.Calls._ID, SortDirection.DESC)
75+
if (limit <= 0) {
76+
return emptyList()
77+
}
78+
79+
val where = buildWhereAsync(query)
80+
return context.contentResolver.query(
81+
uriExternal.withCallLogPaging(limit, offset),
82+
getProjection(),
83+
where.toSelection(),
84+
where.args.toTypedArray(),
85+
"${CallLog.Calls._ID} DESC",
8186
)?.map { cursor, cache ->
8287
val id = cursor.getStringValue(CallLog.Calls._ID, cache)
8388
val number = cursor.getStringValue(CallLog.Calls.NUMBER, cache)
@@ -91,6 +96,20 @@ object CallMediaStoreHelper : BaseContentHelper() {
9196
} ?: emptyList()
9297
}
9398

99+
private fun Uri.withCallLogPaging(
100+
limit: Int,
101+
offset: Int,
102+
): Uri {
103+
return buildUpon()
104+
.appendQueryParameter(CallLog.Calls.LIMIT_PARAM_KEY, limit.toString())
105+
.apply {
106+
if (offset > 0) {
107+
appendQueryParameter(CallLog.Calls.OFFSET_PARAM_KEY, offset.toString())
108+
}
109+
}
110+
.build()
111+
}
112+
94113
fun call(
95114
context: Context,
96115
number: String,

app/src/main/java/com/ismartcoding/plain/web/schemas/CallGraphQL.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ fun SchemaBuilder.addCallSchema() {
3535
query("callCount") {
3636
resolver { query: String ->
3737
val context = MainApp.instance
38-
if (Permission.WRITE_CALL_LOG.enabledAndCanAsync(context)) {
38+
if (Permission.READ_CALL_LOG.enabledAndCanAsync(context)) {
3939
CallMediaStoreHelper.countAsync(context, query)
4040
} else {
4141
0

0 commit comments

Comments
 (0)