¿Cómo accedo al registro de llamadas para Android?

95

Me gustaría recibir el registro de llamadas. Por ejemplo, la cantidad de llamadas realizadas por el usuario, la cantidad de minutos llamados, etc.

¿Cómo logro esto en Android?

3cruzar
fuente
puede ser que esta sea una solución para U developer.android.com/reference/android/database/…
Nikunj Patel
Recuerdo que era un solucionador de contenido, sin embargo, no tengo idea de cómo comenzar.
3cross

Respuestas:

69

Esto es para acceder al historial de llamadas telefónicas:

A partir de Jellybean (4.1) necesita el siguiente permiso:
<uses-permission android:name="android.permission.READ_CALL_LOG" />

Código:

 Uri allCalls = Uri.parse("content://call_log/calls");
 Cursor c = managedQuery(allCalls, null, null, null, null);

String num= c.getString(c.getColumnIndex(CallLog.Calls.NUMBER));// for  number
String name= c.getString(c.getColumnIndex(CallLog.Calls.CACHED_NAME));// for name
String duration = c.getString(c.getColumnIndex(CallLog.Calls.DURATION));// for duration
int type = Integer.parseInt(c.getString(c.getColumnIndex(CallLog.Calls.TYPE)));// for call type, Incoming or out going.
Abhinav Singh Maurya
fuente
11
No olvide habilitar este permiso: <uses-allow android: name = "android.permission.READ_CALL_LOG" /> este es el método para obtener el registro de llamadas:
Aziz
No lo sé pero teóricamente puedo decir que todos los mensajes están almacenados en la misma base de datos. Entonces, sí, puede acceder a todos los mensajes del dispositivo, independientemente de la SIM dual o SIM única. Verifique este código y avíseme si no funciona con dual sim. Haré algo de I + D y te proporcionaré un código para eso.
Abhinav Singh Maurya
1
get name siempre devolverá nulo, tenga cuidado
vuhung3990
@Abhinav Singh Maurya, ¿pueden ayudarme a obtener el registro de llamadas photo_uri de los registros de llamadas porque no puedo obtener photo_uri del registro de llamadas?
Sagar
1
managedQuery () obsoleto use esto en su lugar Cursor cursor = context.getContentResolver (). query (CallLog.Calls.CONTENT_URI, null, null, null, CallLog.Calls.DATE + "DESC");
Sai Gopi Me
67

Este es el método utilizado para obtener el registro de llamadas. Simplemente coloque este método en su clase y obtenga la Lista del registro de llamadas.

Mira esto

private String getCallDetails() {

        StringBuffer sb = new StringBuffer();
        Cursor managedCursor = managedQuery(CallLog.Calls.CONTENT_URI, null,
                null, null, null);
        int number = managedCursor.getColumnIndex(CallLog.Calls.NUMBER);
        int type = managedCursor.getColumnIndex(CallLog.Calls.TYPE);
        int date = managedCursor.getColumnIndex(CallLog.Calls.DATE);
        int duration = managedCursor.getColumnIndex(CallLog.Calls.DURATION);
        sb.append("Call Details :");
        while (managedCursor.moveToNext()) {
            String phNumber = managedCursor.getString(number);
            String callType = managedCursor.getString(type);
            String callDate = managedCursor.getString(date);
            Date callDayTime = new Date(Long.valueOf(callDate));
            String callDuration = managedCursor.getString(duration);
            String dir = null;
            int dircode = Integer.parseInt(callType);
            switch (dircode) {
            case CallLog.Calls.OUTGOING_TYPE:
                dir = "OUTGOING";
                break;

            case CallLog.Calls.INCOMING_TYPE:
                dir = "INCOMING";
                break;

            case CallLog.Calls.MISSED_TYPE:
                dir = "MISSED";
                break;
            }
            sb.append("\nPhone Number:--- " + phNumber + " \nCall Type:--- "
                    + dir + " \nCall Date:--- " + callDayTime
                    + " \nCall duration in sec :--- " + callDuration);
            sb.append("\n----------------------------------");
        }
        managedCursor.close();
        return sb.toString();

    }

la salida se ve

ingrese la descripción de la imagen aquí

Dwivedi Ji
fuente
Recibo un error en managedQuery (CallLog.Calls.CONTENT_URI, null, null, null, null);
Sunil Parmar
5
Usé contentResolver.query (CallLog.Calls.CONTENT_URI, null, null, null, null);
Sunil Parmar
@Dwivedi Ji: es una publicación un poco antigua: su método funciona, pero tarda al menos 10 segundos en cargar todos mis registros de llamadas.
TheDevMan
@TheDevMan, perdón por su inconveniente, sí, tiene razón, actualizaré mi respuesta pronto,
Dwivedi Ji
Gracias esperaré tu respuesta!
TheDevMan
48

use este método desde cualquier lugar con un contexto

private static String getCallDetails(Context context) {
    StringBuffer stringBuffer = new StringBuffer();
    Cursor cursor = context.getContentResolver().query(CallLog.Calls.CONTENT_URI,
            null, null, null, CallLog.Calls.DATE + " DESC");
    int number = cursor.getColumnIndex(CallLog.Calls.NUMBER);
    int type = cursor.getColumnIndex(CallLog.Calls.TYPE);
    int date = cursor.getColumnIndex(CallLog.Calls.DATE);
    int duration = cursor.getColumnIndex(CallLog.Calls.DURATION);       
    while (cursor.moveToNext()) {
        String phNumber = cursor.getString(number);
        String callType = cursor.getString(type);
        String callDate = cursor.getString(date);
        Date callDayTime = new Date(Long.valueOf(callDate));
        String callDuration = cursor.getString(duration);
        String dir = null;
        int dircode = Integer.parseInt(callType);
        switch (dircode) {
        case CallLog.Calls.OUTGOING_TYPE:
            dir = "OUTGOING";
            break;
        case CallLog.Calls.INCOMING_TYPE:
            dir = "INCOMING";
            break;

        case CallLog.Calls.MISSED_TYPE:
            dir = "MISSED";
            break;
        }
        stringBuffer.append("\nPhone Number:--- " + phNumber + " \nCall Type:--- "
                + dir + " \nCall Date:--- " + callDayTime
                + " \nCall duration in sec :--- " + callDuration);
        stringBuffer.append("\n----------------------------------");
    }
    cursor.close();
    return stringBuffer.toString();
}
ingyesid
fuente
7
Dado que managedQuery ahora está en desuso, esta respuesta es la más relevante.
abhi
16

Esta publicación es un poco antigua, pero aquí hay otra solución fácil para obtener datos relacionados con el Callproveedor de contenido de registros en Android:

Utilice esta biblioteca: https://github.com/EverythingMe/easy-content-providers

Recibe todas las llamadas:

CallsProvider callsProvider = new CallsProvider(context);
List<Call> calls = callsProvider.getCalls().getList();

Cada llamada tiene todos los campos, por lo que puede obtener cualquier información que necesite:
callDate, duración, número, tipo (ENTRANTE, SALIENTE, PERDIDA), isRead, ...

Funciona con Listo Cursory hay una aplicación de muestra para ver cómo se ve y funciona.

De hecho, hay soporte para todos los proveedores de contenido de Android como: Contactos, SMS, Calendario, ... Documento completo con todas las opciones: https://github.com/EverythingMe/easy-content-providers/wiki/Android-providers

Espero que también haya ayudado :)

sromku
fuente
Oye, verifiqué tu solución, es buena. El único problema al que me enfrento es cómo agregar la dependencia en mi proyecto de eclipse.
Aradhna
@aradhna, la biblioteca usa gradle y se creó a partir de Android Studio. Creo que tendrás que modificarlo un poco para que se ejecute en Eclipse
sromku
9

en Mi proyecto recibo el error int htc device. Ahora este código es universal. Creo que esto es de ayuda para ti.

    public class CustomContentObserver extends ContentObserver {        
    public CustomContentObserver(Handler handler) {
        super(handler);
        System.out.println("Content obser");
    }     

    public void onChange(boolean selfChange) {
         super.onChange(selfChange);
         String lastCallnumber;

         currentDate = sdfcur.format(calender.getTime());
         System.out.println("Content obser onChange()");
         Log.d("PhoneService", "custom StringsContentObserver.onChange( " + selfChange + ")");
        //if(!callFlag){                   
         String[] projection = new String[]{CallLog.Calls.NUMBER,
                    CallLog.Calls.TYPE,
                    CallLog.Calls.DURATION,
                    CallLog.Calls.CACHED_NAME,
                    CallLog.Calls._ID};

            Cursor c;   
            c=mContext.getContentResolver().query(CallLog.Calls.CONTENT_URI, projection, null, null, CallLog.Calls._ID + " DESC");
            if(c.getCount()!=0){
                c.moveToFirst();
                 lastCallnumber = c.getString(0);
                 String type=c.getString(1);
                 String duration=c.getString(2);
                 String name=c.getString(3);
                 String id=c.getString(4);
                 System.out.println("CALLLLing:"+lastCallnumber+"Type:"+type);

                 Database db=new Database(mContext);
                 Cursor cur =db.getFirstRecord(lastCallnumber);
                 final String endCall=lastCallnumber;
                 //checking incoming/outgoing call
                 if(type.equals("3")){
                    //missed call
                    }else if(type.equals("1")){
                    //incoming call

                 }else if(type.equals("2")){
                    //outgoing call
                 }                  

            }
            c.close();
    }

}
Harshid
fuente
2

Para obtener solo el historial de llamadas entrantes, el código a continuación lo ayudará :)

private void getCallDetailsAgil() {

    StringBuffer sb = new StringBuffer();
    Cursor managedCursor = managedQuery(CallLog.Calls.CONTENT_URI, null, null, null, null);
    int number = managedCursor.getColumnIndex(CallLog.Calls.NUMBER);
    int type = managedCursor.getColumnIndex(CallLog.Calls.TYPE);
    int date = managedCursor.getColumnIndex(CallLog.Calls.DATE);
    int duration = managedCursor.getColumnIndex(CallLog.Calls.DURATION);
    sb.append("Call Details :");
    while (managedCursor.moveToNext()) {
        String phNumber = managedCursor.getString(number);
        String callType = managedCursor.getString(type);
        String callDate = managedCursor.getString(date);
        Date callDayTime = new Date(Long.valueOf(callDate));
        String callDuration = managedCursor.getString(duration);
        String dir = null;
        int dircode = Integer.parseInt(callType);


        switch (dircode) {
            case CallLog.Calls.OUTGOING_TYPE:
                dir = "OUTGOING";
                break;

            case CallLog.Calls.INCOMING_TYPE:
                dir = "INCOMING";
                sb.append("\nPhone Number:--- " + phNumber + " \nCall Type:--- " + dir + " \nCall Date:--- " + callDayTime + " \nCall duration in sec :--- " + callDuration);
                sb.append("\n----------------------------------");
                miss_cal.setText(sb);
                break;

            case CallLog.Calls.MISSED_TYPE:
                dir = "MISSED";
                break;
        }
    }

    managedCursor.close();
} 
Agilanbu
fuente
2

Para obtener el historial de llamadas entrantes, salientes y perdidas, espero que este código le ayude :)

Llame a este código en su hilo de fondo.

StringBuffer sb = new StringBuffer();

String[] projection = new String[] {
    CallLog.Calls.CACHED_NAME,
    CallLog.Calls.NUMBER,
    CallLog.Calls.TYPE,
    CallLog.Calls.DATE,
    CallLog.Calls.DURATION
};

sb.append("Call Details :");

// String strOrder = android.provider.CallLog.Calls.DATE + " DESC";

Cursor managedCursor =  getApplicationContext().getContentResolver().query(CallLog.Calls.CONTENT_URI, projection, null, null, null);
while (managedCursor.moveToNext()) {
    String name = managedCursor.getString(0); //name
    String number = managedCursor.getString(1); // number
    String type = managedCursor.getString(2); // type 
    String date = managedCursor.getString(3); // time 
    @SuppressLint("SimpleDateFormat") 
    SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm");
    String dateString = formatter.format(new Date(Long.parseLong(date)));

    String duration = managedCursor.getString(4); // duration

    String dir = null;
    int dircode = Integer.parseInt(type);
    switch (dircode) {
        case CallLog.Calls.OUTGOING_TYPE:
            dir = "OUTGOING";
            break;
        case CallLog.Calls.INCOMING_TYPE:
            dir = "INCOMING";
            break;
        case CallLog.Calls.MISSED_TYPE:
            dir = "MISSED";
            break;
    }

sb.append("\nPhone Name :-- "+name+"  Number:--- " + number + " \nCall Type:--- " + dir + " \nCall Date:--- " + dateString + " \nCall duration in sec :--- " + duration);
sb.append("\n----------------------------------");
Saurabh Gaddelpalliwar
fuente
1

Utilice el siguiente código:

private void getCallDeatils() {
    StringBuffer stringBuffer = new StringBuffer();
    Cursor managedCursor = getActivity().managedQuery(CallLog.Calls.CONTENT_URI, null, null, null, null);
    int number = managedCursor.getColumnIndex(CallLog.Calls.NUMBER);
    int type = managedCursor.getColumnIndex(CallLog.Calls.TYPE);
    int date = managedCursor.getColumnIndex(CallLog.Calls.DATE);

    int duration = managedCursor.getColumnIndex(CallLog.Calls.DURATION);
    stringBuffer.append("Call Deatils");
    while (managedCursor.moveToNext()) {
        String phNumber = managedCursor.getString(number);
        String callType = managedCursor.getString(type);
        String callDate = managedCursor.getString(date);
        Date callDayTime = new Date(Long.valueOf(callDate));
        DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
        String reportDate = df.format(callDayTime);
        String callDuration = managedCursor.getString(duration);
        String dir = null;
        int dircode = Integer.parseInt(callType);
        switch (dircode) {
            case CallLog.Calls.OUTGOING_TYPE:
                dir = "OUTGOING";
                break;

            case CallLog.Calls.INCOMING_TYPE:
                dir = "INCOMING";

                break;

            case CallLog.Calls.MISSED_TYPE:
                dir = "MISSED";
                break;

        }
        stringBuffer.append("\nPhone Number:--- " + phNumber + " \nCall Type:--- " + dir + " \nCall Date:--- " +callDate + " \nCall duration in sec :--- " + callDuration);
        stringBuffer.append("\n----------------------------------");

        logs.add(new LogClass(phNumber,dir,reportDate,callDuration));




    }
Rohan Lodhi
fuente
0

Si usamos Kotlin es más corto. Ejemplo de clase que responde para proporcionar registros de llamadas:

import android.content.Context
import android.database.Cursor
import android.provider.CallLog.Calls.*

class CallsLoader {

    fun getCallLogs(context: Context): List<List<String?>> {
        val c = context.applicationContext
        val projection = arrayOf(CACHED_NAME, NUMBER, TYPE, DATE, DURATION)

        val cursor = c.contentResolver.query(
             CONTENT_URI,
             projection,
             null,
             null,
             null,
             null
          )

         return cursorToMatrix(cursor)
     }

    private fun cursorToMatrix(cursor: Cursor?): List<List<String?>> {
        val matrix = mutableListOf<List<String?>>()
        cursor?.use {
             while (it.moveToNext()) {
                 val list = listOf(
                    it.getStringFromColumn(CACHED_NAME),
                    it.getStringFromColumn(NUMBER),
                    it.getStringFromColumn(TYPE),
                    it.getStringFromColumn(DATE),
                    it.getStringFromColumn(DURATION)
                 )

                 matrix.add(list.toList())
             }
          }

          return matrix
      }

     private fun Cursor.getStringFromColumn(columnName: String) =
        getString(getColumnIndex(columnName))
}

También podemos convertir cursor a mapa:

fun getCallLogs(context: Context): Map<String, Array<String?>> {
    val c = context.applicationContext
    val projection = arrayOf(CACHED_NAME, NUMBER, TYPE, DATE, DURATION)

    val cursor = c.contentResolver.query(
        CONTENT_URI,
        projection,
        null,
        null,
        null,
        null
    )

    return cursorToMap(cursor)
}

private fun cursorToMap(cursor: Cursor?): Map<String, Array<String?>> {
    val arraySize = cursor?.count ?: 0
    val map = mapOf(
        CACHED_NAME to Array<String?>(arraySize) { "" },
        NUMBER to Array<String?>(arraySize) { "" },
        TYPE to Array<String?>(arraySize) { "" },
        DATE to Array<String?>(arraySize) { "" },
        DURATION to Array<String?>(arraySize) { "" }
    )

    cursor?.use {
        for (i in 0 until arraySize) {
            it.moveToNext()

            map[CACHED_NAME]?.set(i, it.getStringFromColumn(CACHED_NAME))
            map[NUMBER]?.set(i, it.getStringFromColumn(NUMBER))
            map[TYPE]?.set(i, it.getStringFromColumn(TYPE))
            map[DATE]?.set(i, it.getStringFromColumn(DATE))
            map[DURATION]?.set(i, it.getStringFromColumn(DURATION))
        }
    }

    return map
}
Artem Botnev
fuente
0

Antes de considerar hacer que los permisos Leer registro de llamadas o Leer SMS sean parte de su aplicación, le recomiendo encarecidamente que consulte esta política de Google Play Market: https://support.google.com/googleplay/android-developer/answer/9047303 ? hl = en

Esos permisos son muy confidenciales y tendrá que demostrar que su aplicación los necesita. Pero incluso si realmente los necesita, el equipo de soporte de Google Play puede rechazar fácilmente su solicitud sin las explicaciones adecuadas.

Esto es lo que me pasó. Después de proporcionar toda la información necesaria junto con el video de demostración de mi solicitud, se rechazó con la explicación de que " mi cuenta no está autorizada para proporcionar una determinada solución de caso de uso en mi aplicación" (la lista de casos de uso que pueden considerar como una excepción aparece en esa página de Política). No se proporcionó ningún enlace a ninguna declaración de política para explicar lo que significa. Básicamente, simplemente juzgaron que mi aplicación no iba sin una explicación adecuada.

Les deseo buena suerte con sus aplicaciones chicos, pero tengan cuidado.

dpetruha
fuente