Reputation: 4450
I wrote the following code, when I receive a call I should receive a notification whether or not I want to record the call, the problem is that I do not receive any notification.
How do I ensure that the CallReceiver
is always listening?
Furthermore, I don't need MainActivity
to show anything, what can I do?
Can you give me a hand?
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Callrec"
tools:targetApi="31">
<receiver android:name=".CallReceiver" android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Callrec">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
NotificationActionReceiver:
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
class NotificationActionReceiver : BroadcastReceiver() {
companion object {
const val ACTION_RECORD_CALL = "ACTION_RECORD_CALL"
const val ACTION_CANCEL = "ACTION_CANCEL"
const val EXTRA_PHONE_NUMBER = "EXTRA_PHONE_NUMBER"
}
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
ACTION_RECORD_CALL -> {
val phoneNumber = intent.getStringExtra(EXTRA_PHONE_NUMBER)
Log.d("NotificationAction", "Recording call from $phoneNumber")
// Aggiungi qui la logica per iniziare la registrazione
}
ACTION_CANCEL -> {
Log.d("NotificationAction", "Recording cancelled")
// Aggiungi qui la logica per annullare la registrazione
}
}
}
}
CallReceiver:
import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.media.MediaRecorder
import android.os.Build
import android.telephony.TelephonyManager
import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
class CallReceiver : BroadcastReceiver() {
private var mediaRecorder: MediaRecorder? = null
private var isRecording = false
private lateinit var context: Context
override fun onReceive(context: Context?, intent: Intent?) {
this.context = context!!
if (intent?.action.equals("android.intent.action.PHONE_STATE")) {
val state = intent?.getStringExtra(TelephonyManager.EXTRA_STATE)
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
val phoneNumber = intent?.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)
Log.d("CallReceiver", "Incoming call from: $phoneNumber")
showNotification(phoneNumber)
} else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
Log.d("CallReceiver", "Call ended")
stopRecording()
}
}
}
private fun startRecording() {
if (isRecording) {
return
}
if (ActivityCompat.checkSelfPermission(
context,
Manifest.permission.RECORD_AUDIO
) == PackageManager.PERMISSION_GRANTED
) {
try {
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val audioFilePath = context.getExternalFilesDir(null)?.absolutePath + "/$timestamp.3gp"
mediaRecorder = MediaRecorder().apply {
setAudioSource(MediaRecorder.AudioSource.VOICE_CALL)
setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
setOutputFile(audioFilePath)
try {
prepare()
} catch (e: IOException) {
Log.e("CallRecorder", "prepare() failed")
}
start()
}
isRecording = true
Log.d("CallReceiver", "Recording started")
} catch (e: Exception) {
Log.e("CallReceiver", "Error starting recording: ${e.message}")
}
} else {
Log.e("CallReceiver", "Permission to record audio not granted")
}
}
private fun stopRecording() {
if (isRecording) {
mediaRecorder?.apply {
stop()
release()
}
isRecording = false
Log.d("CallReceiver", "Recording stopped")
}
}
private fun showNotification(phoneNumber: String?) {
val channelId = "RecordCallChannel"
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
channelId,
"Record Call Channel",
NotificationManager.IMPORTANCE_HIGH
)
notificationManager.createNotificationChannel(channel)
}
val builder = NotificationCompat.Builder(context, channelId)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle("Incoming Call")
.setContentText("Do you want to record this call?")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.addAction(
android.R.drawable.ic_menu_save,
"Record",
getPendingIntent(true, phoneNumber)
)
.addAction(
android.R.drawable.ic_menu_close_clear_cancel,
"Cancel",
getPendingIntent(false, null)
)
notificationManager.notify(1, builder.build())
}
private fun getPendingIntent(record: Boolean, phoneNumber: String?): PendingIntent {
val intent = Intent(context, NotificationActionReceiver::class.java).apply {
action = if (record) NotificationActionReceiver.ACTION_RECORD_CALL else NotificationActionReceiver.ACTION_CANCEL
putExtra(NotificationActionReceiver.EXTRA_PHONE_NUMBER, phoneNumber)
}
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
}
MainActivity:
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.myapp.callrec.ui.theme.CallrecTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CallrecTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
}
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
CallrecTheme {
Greeting("Android")
}
}
Upvotes: 0
Views: 80