Skip to content

Commit

Permalink
feat: add caller name and thumbnail
Browse files Browse the repository at this point in the history
  • Loading branch information
SuhasDissa committed Apr 22, 2024
1 parent 8bbf71e commit 3dac001
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 7 deletions.
74 changes: 67 additions & 7 deletions app/src/main/java/com/bnyro/contacts/services/CallService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,37 @@ package com.bnyro.contacts.services
import android.annotation.SuppressLint
import android.app.Notification
import android.app.PendingIntent
import android.content.ContentResolver
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.provider.ContactsContract.PhoneLookup
import android.telecom.Call
import android.telecom.InCallService
import android.view.View
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.bnyro.contacts.R
import com.bnyro.contacts.ext.stringValue
import com.bnyro.contacts.receivers.CallActionReceiver
import com.bnyro.contacts.receivers.CallActionReceiver.Companion.ACCEPT_CALL
import com.bnyro.contacts.receivers.CallActionReceiver.Companion.DECLINE_CALL
import com.bnyro.contacts.ui.activities.CallActivity
import com.bnyro.contacts.util.CallManager
import com.bnyro.contacts.util.ContactsHelper
import com.bnyro.contacts.util.NotificationHelper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext


class CallService : InCallService() {

private lateinit var acceptPendingIntent: PendingIntent
private lateinit var declinePendingIntent: PendingIntent
val scope = CoroutineScope(Dispatchers.Main)

override fun onCreate() {
super.onCreate()
Expand Down Expand Up @@ -50,32 +62,80 @@ class CallService : InCallService() {
call.registerCallback(callCallback)
CallManager.setCall(call)

val notification = buildNotification(call)
NotificationManagerCompat.from(this).notify(CALL_NOTIFICATION_ID, notification)
scope.launch {
val callerNumber = CallManager.callerDisplayNumber
val (thumbnailUri, contactName) = withContext(Dispatchers.IO) {
getContactName(callerNumber)
}
val contactPhoto = if (thumbnailUri != null) {
withContext(Dispatchers.IO) {
ContactsHelper.getContactPhotoThumbnail(this@CallService, thumbnailUri)
}
} else {
null
}

val notification = buildNotification(call, callerNumber, contactName, contactPhoto)
NotificationManagerCompat.from(this@CallService)
.notify(CALL_NOTIFICATION_ID, notification)

}
val intent = Intent(applicationContext, CallActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent)
}

private fun getContactName(phoneNumber: String): Pair<String?, String?> {
val cr: ContentResolver = this.contentResolver
val uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber))
val query =
cr.query(
uri,
arrayOf(PhoneLookup.DISPLAY_NAME, PhoneLookup.PHOTO_THUMBNAIL_URI),
null,
null,
null
)

query?.use { cursor ->
if (cursor.moveToFirst()) {
return cursor.stringValue(PhoneLookup.PHOTO_THUMBNAIL_URI) to cursor.stringValue(
PhoneLookup.DISPLAY_NAME
)
}
}
return null to null
}

override fun onCallRemoved(call: Call) {
super.onCallRemoved(call)
NotificationManagerCompat.from(this).cancel(CALL_NOTIFICATION_ID)
call.unregisterCallback(callCallback)
CallManager.setCall(null)
}

private fun buildNotification(call: Call): Notification {
private fun buildNotification(
call: Call,
callerNumber: String,
callerName: String?,
callersPhoto: Bitmap?
): Notification {
val collapsedView = RemoteViews(packageName, R.layout.call_notification).apply {
setTextViewText(R.id.notification_caller_name, "TODO: Get Contact Name")
setTextViewText(R.id.notification_call_status, CallManager.callerDisplayNumber)
setTextViewText(
R.id.notification_caller_name,
callerName ?: getString(R.string.unknown_number)
)
setTextViewText(R.id.notification_call_status, callerNumber)
setViewVisibility(
R.id.notification_accept_call,
if (call.state == Call.STATE_RINGING) View.VISIBLE else View.GONE
)

// TODO: Set Contact Photo Bitmap
setImageViewResource(R.id.notification_thumbnail, R.drawable.round_person)
if (callersPhoto != null) {
setImageViewBitmap(R.id.notification_thumbnail, callersPhoto)
} else {
setImageViewResource(R.id.notification_thumbnail, R.drawable.round_person)
}
setOnClickPendingIntent(R.id.notification_decline_call, declinePendingIntent)
setOnClickPendingIntent(R.id.notification_accept_call, acceptPendingIntent)
}
Expand Down
15 changes: 15 additions & 0 deletions app/src/main/java/com/bnyro/contacts/util/ContactsHelper.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.bnyro.contacts.util

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.provider.ContactsContract
import com.bnyro.contacts.R
import com.bnyro.contacts.enums.Addresses
Expand Down Expand Up @@ -139,4 +143,15 @@ object ContactsHelper {

return stringProperties.none { !it.isNullOrBlank() } && listProperties.flatten().isEmpty()
}

fun getContactPhotoThumbnail(context: Context, uri: String): Bitmap? {
val contentResolver = context.contentResolver
val photoThumbnailUri = Uri.parse(uri)
val assetFileDescriptor =
contentResolver.openAssetFileDescriptor(photoThumbnailUri, "r") ?: return null
val fileDescriptor = assetFileDescriptor.fileDescriptor
val bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor)
assetFileDescriptor.close()
return bitmap
}
}
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,5 @@
<string name="calls">Calls</string>
<string name="decline">Decline</string>
<string name="accept">Accept</string>
<string name="unknown_number">Unknown Number</string>
</resources>

0 comments on commit 3dac001

Please sign in to comment.