skip to Main Content

BroadcastReceiver File

class CallReceiver : BroadcastReceiver() {
private var mediaRecorder : MediaRecorder? = null

override fun onReceive(context: Context?, intent: Intent?) {
    val state : String
  if(intent?.action.equals("android.intent.action.PHONE_STATE")){
      if(intent?.extras != null){
          state = intent.getStringExtra(TelephonyManager.EXTRA_STATE).toString()
          when(state){
              TelephonyManager.EXTRA_STATE_RINGING -> {
                  Log.d("CallRec", "Ringing......")
              }

              TelephonyManager.EXTRA_STATE_OFFHOOK -> {
                  startRecording(context)
              }

              TelephonyManager.EXTRA_STATE_IDLE ->{
                  stopRecording()
              }
          }
      }
  }
}


private fun startRecording(context: Context?) {
    if(context != null){
        mediaRecorder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) MediaRecorder(context) else MediaRecorder()
    }

    mediaRecorder?.apply {
        setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
        setOutputFormat(MediaRecorder.OutputFormat.AMR_NB)
        setOutputFile(getRecordingFilePath())
        setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
    }

    try {
        mediaRecorder?.prepare()
        mediaRecorder?.start()
    }
    catch (e : IOException){
        Log.d("CallError", e.toString())
    }


    Log.d("CallRec", "Call Recording Start......")
}


private fun stopRecording(){
    try {
        mediaRecorder?.stop()
        mediaRecorder?.release()
    }
    catch (e : Exception){
        Log.d("CallError", e.toString())
    }
    mediaRecorder = null
    Log.d("CallRec", "Call Recording Stopped......")
}


private fun getRecordingFilePath(): String {
    val directory = File(Environment.getExternalStorageDirectory(), "TestRecording")
    if(!directory.exists()){
        directory.mkdir()
    }
    val filePath = File(directory, "testing_${System.currentTimeMillis()}" + ".amr")
    return filePath.path
}

}
MainActivity Class

class MainActivity : AppCompatActivity() {

private var callReceiver = CallReceiver()
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
  
  allowPermission()

    val makeCall: Button = findViewById(R.id.makeCall)
    makeCall.setOnClickListener {
        val intent = Intent(Intent.ACTION_DIAL)
        startActivity(intent)
    }

    if(hasPermission()) {
        val intentFilter = IntentFilter()
        intentFilter.addAction("android.intent.action.PHONE_STATE")
        this.registerReceiver(callReceiver, intentFilter)
    }
    else{
        allowPermission()
    }
}

override fun onDestroy() {
    super.onDestroy()
    this.unregisterReceiver(callReceiver)
}

private fun allowPermission() {
    ActivityCompat.requestPermissions(
        this, arrayOf(
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_PHONE_STATE,
            Manifest.permission.RECORD_AUDIO
        ), 2
    )
}

private fun hasPermission() : Boolean{
    val phoneStatePermission = Manifest.permission.READ_PHONE_STATE
    val writeFilePermission = Manifest.permission.WRITE_EXTERNAL_STORAGE
    val recordAudioPermission = Manifest.permission.RECORD_AUDIO
    return ContextCompat.checkSelfPermission(this, phoneStatePermission) == PackageManager.PERMISSION_GRANTED
            &&   ContextCompat.checkSelfPermission(this, writeFilePermission) == PackageManager.PERMISSION_GRANTED
            &&   ContextCompat.checkSelfPermission(this, recordAudioPermission) == PackageManager.PERMISSION_GRANTED

}

}

Manifest File

<uses-feature
    android:name="android.hardware.telephony"
    android:required="false" />

<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28"
    />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />





<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.CallRecording"
    tools:targetApi="31">
    <activity
        android:name=".MainActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

</application>

LogCat

java.io.FileNotFoundException: /storage/emulated/0/TestRecording/testing_1694590203887.amr: open failed: ENOENT (No such file or directory)

I am building a call recording app and I want to store recorded audio file in a custom directory. When I run this app on android 8, it is working perfectly. But for android 13, it is giving EPERM (Operation not permitted) exception. I think the issue is related to permissions.

2

Answers


  1. Google restricted call recording feature to only system apps. It won’t work above Android 8.
    [https://support.google.com/googleplay/android-developer/answer/9888170]

    Login or Signup to reply.
  2. On an Android 13 device you should not request the usual WRITE permission as you have it by default.

    But you cannot create your folder "TestRecording" in root of external storage.

    Instead create your folder in one of the public directiries that are already there like Download, Documents, DCIM, Pictures, Video..

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search