I'm working on an Android app that detects incoming calls using a BroadcastReceiver. When an incoming call is detected, I want to perform a task, but I'm facing an issue with handling null phone numbers.
Here's the current flow of my app:
ACTION_PHONE_STATE_CHANGED
intent action to detect incoming calls.However, this approach leads to two same tasks being done for the same incoming call, which is undesirable.
FYI, I need to call the method while the Telephony state == TelephonyManager.EXTRA_STATE_RINGING
, not after the call is ended.
My goal is to call logCall only once per incoming call, regardless of whether I receive a null value initially.
Here's what I've tried:
CallDetectionService.kt
private val detectedNumbers = mutableListOf<String?>()
private val broadcastReceiver = object : BroadcastReceiver() {
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == TelephonyManager.ACTION_PHONE_STATE_CHANGED) {
val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
val number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)
if (state == TelephonyManager.EXTRA_STATE_RINGING) {
Log.d(TAG, "Incoming call from $number at ${LocalDate.now()}")
Log.d(TAG, "Sending broadcast to the activity from $CLASS")
detectedNumbers.add(number)
if (detectedNumbers.any { it != null && it.isNotBlank() }) {
logCall(number)
}
}
}
}
}
private fun logCall(number: String?) {
// Update detected numbers array
detectedNumbers.add(number)
// Check if any actual number or specific values are present
if (detectedNumbers.any { it != null && (it != "Unknown" && it != "Private") }) {
// Call logCall only once with the first non-null, non-specific value
val actualNumber = detectedNumbers.firstOrNull { it != null && (it != "Unknown" && it != "Private") }
logCall(actualNumber ?: "Unknown") // Use "Unknown" as default if no valid number found
// Clear the detected numbers array for the next call
detectedNumbers.clear()
}
}
I believe the issue might be related to the timing of receiving the broadcasts, but I'm not sure how to address it effectively
Your approach doesn't effectively handle the asynchronous nature of receiving call state and number information, leading to multiple log entries for the same call or nulls.
you can try this to keep track of last number
private var lastNumber: String? = null
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (TelephonyManager.ACTION_PHONE_STATE_CHANGED == intent.action) {
val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
if (TelephonyManager.EXTRA_STATE_RINGING == state) {
val number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)
if (number != null && number != lastNumber) {
logCall(number)
lastNumber = number
}
}
}
}
}
private fun logCall(number: String?) {
// your logcall code
}