Cómo grabar llamadas telefónicas en Android?

Quiero crear una aplicación que registre las llamadas entrantes y salientes y se ejecute automáticamente cuando el usuario recibe o realiza una llamada.

    Ok, para esto primero debes usar Device Policy Manager, y necesitas hacer que tu dispositivo administre tu dispositivo. Después de eso, debe crear un receptor BroadCast y un servicio. Estoy publicando código aquí y está funcionando bien.

    Actividad principal:

    public class MainActivity extends Activity { private static final int REQUEST_CODE = 0; private DevicePolicyManager mDPM; private ComponentName mAdminName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); try { // Initiate DevicePolicyManager. mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); mAdminName = new ComponentName(this, DeviceAdminDemo.class); if (!mDPM.isAdminActive(mAdminName)) { Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdminName); intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "Click on Activate button to secure your application."); startActivityForResult(intent, REQUEST_CODE); } else { // mDPM.lockNow(); // Intent intent = new Intent(MainActivity.this, // TrackDeviceService.class); // startService(intent); } } catch (Exception e) { e.printStackTrace(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (REQUEST_CODE == requestCode) { Intent intent = new Intent(MainActivity.this, TService.class); startService(intent); } } } 

    // clase DeviceAdminDemo

     public class DeviceAdminDemo extends DeviceAdminReceiver { @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); } public void onEnabled(Context context, Intent intent) { }; public void onDisabled(Context context, Intent intent) { }; } 

    // TService Class

     public class TService extends Service { MediaRecorder recorder; File audiofile; String name, phonenumber; String audio_format; public String Audio_Type; int audioSource; Context context; private Handler handler; Timer timer; Boolean offHook = false, ringing = false; Toast toast; Boolean isOffHook = false; private boolean recordstarted = false; private static final String ACTION_IN = "android.intent.action.PHONE_STATE"; private static final String ACTION_OUT = "android.intent.action.NEW_OUTGOING_CALL"; private CallBr br_call; @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } @Override public void onDestroy() { Log.d("service", "destroy"); super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // final String terminate =(String) // intent.getExtras().get("terminate");// // intent.getStringExtra("terminate"); // Log.d("TAG", "service started"); // // TelephonyManager telephony = (TelephonyManager) // getSystemService(Context.TELEPHONY_SERVICE); // TelephonyManager // // object // CustomPhoneStateListener customPhoneListener = new // CustomPhoneStateListener(); // telephony.listen(customPhoneListener, // PhoneStateListener.LISTEN_CALL_STATE); // context = getApplicationContext(); final IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_OUT); filter.addAction(ACTION_IN); this.br_call = new CallBr(); this.registerReceiver(this.br_call, filter); // if(terminate != null) { // stopSelf(); // } return START_NOT_STICKY; } public class CallBr extends BroadcastReceiver { Bundle bundle; String state; String inCall, outCall; public boolean wasRinging = false; @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(ACTION_IN)) { if ((bundle = intent.getExtras()) != null) { state = bundle.getString(TelephonyManager.EXTRA_STATE); if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) { inCall = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER); wasRinging = true; Toast.makeText(context, "IN : " + inCall, Toast.LENGTH_LONG).show(); } else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) { if (wasRinging == true) { Toast.makeText(context, "ANSWERED", Toast.LENGTH_LONG).show(); String out = new SimpleDateFormat("dd-MM-yyyy hh-mm-ss").format(new Date()); File sampleDir = new File(Environment.getExternalStorageDirectory(), "/TestRecordingDasa1"); if (!sampleDir.exists()) { sampleDir.mkdirs(); } String file_name = "Record"; try { audiofile = File.createTempFile(file_name, ".amr", sampleDir); } catch (IOException e) { e.printStackTrace(); } String path = Environment.getExternalStorageDirectory().getAbsolutePath(); recorder = new MediaRecorder(); // recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL); recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION); recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.setOutputFile(audiofile.getAbsolutePath()); try { recorder.prepare(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } recorder.start(); recordstarted = true; } } else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) { wasRinging = false; Toast.makeText(context, "REJECT || DISCO", Toast.LENGTH_LONG).show(); if (recordstarted) { recorder.stop(); recordstarted = false; } } } } else if (intent.getAction().equals(ACTION_OUT)) { if ((bundle = intent.getExtras()) != null) { outCall = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); Toast.makeText(context, "OUT : " + outCall, Toast.LENGTH_LONG).show(); } } } } } 

    // Permiso en el archivo de manifiesto

          

    //my_admin.xml

          

    // Declaro lo siguiente en manifiesto:

    Declarar la clase DeviceAdminDemo para manifestar:

                

    El siguiente código me funciona para grabar una llamada telefónica saliente

     //Call Recording varibales private static final String AUDIO_RECORDER_FILE_EXT_3GP = ".3gp"; private static final String AUDIO_RECORDER_FILE_EXT_MP4 = ".mp4"; private static final String AUDIO_RECORDER_FOLDER = "AudioRecorder"; private MediaRecorder recorder = null; private int currentFormat = 0; private int output_formats[] = { MediaRecorder.OutputFormat.MPEG_4, MediaRecorder.OutputFormat.THREE_GPP }; private String file_exts[] = { AUDIO_RECORDER_FILE_EXT_MP4, AUDIO_RECORDER_FILE_EXT_3GP }; AudioManager audioManager; 

    // pone estos métodos fuera del método oncreate ()

     private String getFilename() { String filepath = Environment.getExternalStorageDirectory().getPath(); File file = new File(filepath, AUDIO_RECORDER_FOLDER); if (!file.exists()) { file.mkdirs(); } return (file.getAbsolutePath() + "/" + System.currentTimeMillis() + file_exts[currentFormat]); } private MediaRecorder.OnErrorListener errorListener = new MediaRecorder.OnErrorListener() { @Override public void onError(MediaRecorder mr, int what, int extra) { Toast.makeText(CallActivity.this, "Error: " + what + ", " + extra, Toast.LENGTH_SHORT).show(); } }; private MediaRecorder.OnInfoListener infoListener = new MediaRecorder.OnInfoListener() { @Override public void onInfo(MediaRecorder mr, int what, int extra) { Toast.makeText(CallActivity.this, "Warning: " + what + ", " + extra, Toast.LENGTH_SHORT) .show(); } }; 

    // parte inferior del código para hacer que su dispositivo esté en el altavoz

      audioManager = (AudioManager)getApplicationContext().getSystemService(Context.AUDIO_SERVICE); audioManager.setMode(AudioManager.MODE_IN_CALL); audioManager.setSpeakerphoneOn(true); 

    // parte inferior del código para comenzar a grabar

     recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(output_formats[currentFormat]); //recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.setOutputFile(getFilename()); recorder.setOnErrorListener(errorListener); recorder.setOnInfoListener(infoListener); try { recorder.prepare(); recorder.start(); } catch (IllegalStateException e) { Log.e("REDORDING :: ",e.getMessage()); e.printStackTrace(); } catch (IOException e) { Log.e("REDORDING :: ",e.getMessage()); e.printStackTrace(); } 

    // Para detener la grabación y tener en cuenta para desactivar el altavoz mientras finaliza o finaliza la llamada

     audioManager.setSpeakerphoneOn(false); try{ if (null != recorder) { recorder.stop(); recorder.reset(); recorder.release(); recorder = null; } }catch(RuntimeException stopException){ } 

    Y dar permiso para manifestar el archivo,

           

    Me gustaría comentar sobre esto, incluso es difícil Su vieja publicación. Entonces, básicamente, quiero combinar 2 respuestas, una de esta publicación y otra de otra publicación que leí, no conozco al autor, así que disculpe el uso de sus métodos.

    Entonces, aquí están mis clases para lograr el resultado deseado:

      public class StartActivity extends Activity { public static final int REQUEST_CODE = 5912; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); PackageManager p = getPackageManager(); ComponentName componentName = new ComponentName(this, StartActivity.class); // activity which is first time open in manifiest file which is declare as  p.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); startService(new Intent(this, StartService.class)); startService(new Intent(this, SmsOutgoingService.class)); try { // Initiate DevicePolicyManager. DevicePolicyManager mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); ComponentName mAdminName = new ComponentName(this, DeviceAdminReciever.class); if (!mDPM.isAdminActive(mAdminName)) { Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdminName); intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "Click on Activate button to secure your application."); startActivityForResult(intent, REQUEST_CODE); } else { mDPM.lockNow(); finish(); // Intent intent = new Intent(MainActivity.this, // TrackDeviceService.class); // startService(intent); } } catch (Exception e) { e.printStackTrace(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (REQUEST_CODE == requestCode) { startService(new Intent(StartActivity.this, TService.class)); finish(); } super.onActivityResult(requestCode, resultCode, data); } } 

    Y mi clase TService :

      public class TService extends Service { private MediaRecorder recorder; private File audiofile; private boolean recordstarted = false; private static final String ACTION_IN = "android.intent.action.PHONE_STATE"; private static final String ACTION_OUT = "android.intent.action.NEW_OUTGOING_CALL"; @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } @Override public void onDestroy() { Log.d("service", "destroy"); super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d("StartService", "TService"); final IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_OUT); filter.addAction(ACTION_IN); this.registerReceiver(new CallReceiver(), filter); return super.onStartCommand(intent, flags, startId); } private void startRecording() { File sampleDir = new File(Environment.getExternalStorageDirectory(), "/TestRecordingDasa1"); if (!sampleDir.exists()) { sampleDir.mkdirs(); } String file_name = "Record"; try { audiofile = File.createTempFile(file_name, ".amr", sampleDir); } catch (IOException e) { e.printStackTrace(); } String path = Environment.getExternalStorageDirectory().getAbsolutePath(); recorder = new MediaRecorder(); // recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL); recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION); recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.setOutputFile(audiofile.getAbsolutePath()); try { recorder.prepare(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } recorder.start(); recordstarted = true; } private void stopRecording() { if (recordstarted) { recorder.stop(); recordstarted = false; } } public abstract class PhonecallReceiver extends BroadcastReceiver { //The receiver will be recreated whenever android feels like it. We need a static variable to remember data between instantiations private int lastState = TelephonyManager.CALL_STATE_IDLE; private Date callStartTime; private boolean isIncoming; private String savedNumber; //because the passed incoming is only valid in ringing @Override public void onReceive(Context context, Intent intent) { // startRecording(); //We listen to two intents. The new outgoing call only tells us of an outgoing call. We use it to get the number. if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) { savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER"); } else { String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE); String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER); int state = 0; if (stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) { state = TelephonyManager.CALL_STATE_IDLE; } else if (stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) { state = TelephonyManager.CALL_STATE_OFFHOOK; } else if (stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) { state = TelephonyManager.CALL_STATE_RINGING; } onCallStateChanged(context, state, number); } } //Derived classes should override these to respond to specific events of interest protected abstract void onIncomingCallReceived(Context ctx, String number, Date start); protected abstract void onIncomingCallAnswered(Context ctx, String number, Date start); protected abstract void onIncomingCallEnded(Context ctx, String number, Date start, Date end); protected abstract void onOutgoingCallStarted(Context ctx, String number, Date start); protected abstract void onOutgoingCallEnded(Context ctx, String number, Date start, Date end); protected abstract void onMissedCall(Context ctx, String number, Date start); //Deals with actual events //Incoming call- goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up //Outgoing call- goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up public void onCallStateChanged(Context context, int state, String number) { if (lastState == state) { //No change, debounce extras return; } switch (state) { case TelephonyManager.CALL_STATE_RINGING: isIncoming = true; callStartTime = new Date(); savedNumber = number; onIncomingCallReceived(context, number, callStartTime); break; case TelephonyManager.CALL_STATE_OFFHOOK: //Transition of ringing->offhook are pickups of incoming calls. Nothing done on them if (lastState != TelephonyManager.CALL_STATE_RINGING) { isIncoming = false; callStartTime = new Date(); startRecording(); onOutgoingCallStarted(context, savedNumber, callStartTime); } else { isIncoming = true; callStartTime = new Date(); startRecording(); onIncomingCallAnswered(context, savedNumber, callStartTime); } break; case TelephonyManager.CALL_STATE_IDLE: //Went to idle- this is the end of a call. What type depends on previous state(s) if (lastState == TelephonyManager.CALL_STATE_RINGING) { //Ring but no pickup- a miss onMissedCall(context, savedNumber, callStartTime); } else if (isIncoming) { stopRecording(); onIncomingCallEnded(context, savedNumber, callStartTime, new Date()); } else { stopRecording(); onOutgoingCallEnded(context, savedNumber, callStartTime, new Date()); } break; } lastState = state; } } public class CallReceiver extends PhonecallReceiver { @Override protected void onIncomingCallReceived(Context ctx, String number, Date start) { Log.d("onIncomingCallReceived", number + " " + start.toString()); } @Override protected void onIncomingCallAnswered(Context ctx, String number, Date start) { Log.d("onIncomingCallAnswered", number + " " + start.toString()); } @Override protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end) { Log.d("onIncomingCallEnded", number + " " + start.toString() + "\t" + end.toString()); } @Override protected void onOutgoingCallStarted(Context ctx, String number, Date start) { Log.d("onOutgoingCallStarted", number + " " + start.toString()); } @Override protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) { Log.d("onOutgoingCallEnded", number + " " + start.toString() + "\t" + end.toString()); } @Override protected void onMissedCall(Context ctx, String number, Date start) { Log.d("onMissedCall", number + " " + start.toString()); // PostCallHandler postCallHandler = new PostCallHandler(number, "janskd" , "") } } } 

    dentro de la clase TService encontrarás la clase CallReceiever que manejará todo lo que necesites de la llamada. Puede agregar parámetros según su voluntad, pero el punto principal es importante.

    Desde su Servicio de llamadas de MainActvitiy, comenzará su Receiver. Si quiere grabar medios del receptor directamente, obtendrá errores, por lo tanto, debe registrar Receiever del servicio. Después de eso, puedes llamar a iniciar la grabación y finalizar la grabación donde quieras. Llamando return super.onStartCommand(intent, flags, startId); tendrá ese servicio durando más de una llamada, así que tenlo en cuenta.

    Finalmente, el archivo AndroidManifest.xml :

                                      

    Por lo tanto, esto es todo, está funcionando perfectamente con mi Samsung Galaxy s6 Edge +, lo he probado en Galaxy Note 4 y en Samsung J5, muchas gracias a los autores de esta publicación y la publicación sobre la recepción de llamadas telefónicas.

    La respuesta de pratt es un poco incompleta, porque cuando reinicies tu dispositivo, tu aplicación se detendrá, la grabación se detendrá, se volverá inútil.

    Estoy agregando alguna línea que copiar en su proyecto para completar el trabajo de la respuesta de Pratt.

               

    poner este código enRecibir DeviceAdminDemo

     @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); context.stopService(new Intent(context, TService.class)); Intent myIntent = new Intent(context, TService.class); context.startService(myIntent); } 

    La respuesta aceptada es perfecta, excepto que no registra las llamadas salientes. Tenga en cuenta que para las llamadas salientes no es posible (tan cerca como puedo deducir de la búsqueda en varias publicaciones) detectar cuándo realmente se responde la llamada (si alguien puede encontrar una forma diferente a las notificaciones de rastreo o los registros, por favor avísenme). La solución más sencilla es comenzar a grabar inmediatamente cuando se realiza la llamada saliente y detener la grabación cuando se detecta IDLE. Simplemente agregando la misma clase que la anterior con la grabación saliente de esta manera para que esté completa:

     private void startRecord(String seed) { String out = new SimpleDateFormat("dd-MM-yyyy hh-mm-ss").format(new Date()); File sampleDir = new File(Environment.getExternalStorageDirectory(), "/TestRecordingDasa1"); if (!sampleDir.exists()) { sampleDir.mkdirs(); } String file_name = "Record" + seed; try { audiofile = File.createTempFile(file_name, ".amr", sampleDir); } catch (IOException e) { e.printStackTrace(); } String path = Environment.getExternalStorageDirectory().getAbsolutePath(); recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION); recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.setOutputFile(audiofile.getAbsolutePath()); try { recorder.prepare(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } recorder.start(); recordstarted = true; } @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(ACTION_IN)) { if ((bundle = intent.getExtras()) != null) { state = bundle.getString(TelephonyManager.EXTRA_STATE); if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) { inCall = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER); wasRinging = true; Toast.makeText(context, "IN : " + inCall, Toast.LENGTH_LONG).show(); } else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) { if (wasRinging == true) { Toast.makeText(context, "ANSWERED", Toast.LENGTH_LONG).show(); startRecord("incoming"); } } else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) { wasRinging = false; Toast.makeText(context, "REJECT || DISCO", Toast.LENGTH_LONG).show(); if (recordstarted) { recorder.stop(); recordstarted = false; } } } } else if (intent.getAction().equals(ACTION_OUT)) { if ((bundle = intent.getExtras()) != null) { outCall = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); Toast.makeText(context, "OUT : " + outCall, Toast.LENGTH_LONG).show(); startRecord("outgoing"); if ((bundle = intent.getExtras()) != null) { state = bundle.getString(TelephonyManager.EXTRA_STATE); if (state != null) { if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) { wasRinging = false; Toast.makeText(context, "REJECT || DISCO", Toast.LENGTH_LONG).show(); if (recordstarted) { recorder.stop(); recordstarted = false; } } } } } } }