Wie greife ich auf das Anrufprotokoll für Android zu?

95

Ich möchte das Anrufprotokoll erhalten. Zum Beispiel die Anzahl der vom Benutzer getätigten Anrufe, die Anzahl der angerufenen Minuten usw.

Wie erreiche ich das in Android?

3cross
quelle
Möglicherweise ist dies eine Lösung für U developer.android.com/reference/android/database/…
Nikunj Patel
Ich erinnere mich, dass es Content Resolver ist, aber ich habe keine Ahnung, wie ich das Ding starten soll.
3cross

Antworten:

69

Dies ist für den Zugriff auf den Anrufverlauf:

Ab Jellybean (4.1) benötigen Sie folgende Erlaubnis:
<uses-permission android:name="android.permission.READ_CALL_LOG" />

Code:

 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
quelle
11
Vergessen Sie nicht, diese Berechtigung zu aktivieren: <Verwendungsberechtigung android: name = "android.permission.READ_CALL_LOG" /> Dies ist die Methode, um das Anrufprotokoll abzurufen:
Aziz
Ich weiß das nicht, aber theoretisch kann ich sagen, dass alle Nachrichten in derselben Datenbank gespeichert sind. Also ja, es kann auf alle Nachrichten des Geräts zugreifen, unabhängig von Dual-Sim oder Single-Sim. Überprüfen Sie diesen Code und lassen Sie mich wissen, wenn er nicht mit Dual-Sim funktioniert. Ich werde etwas Forschung und Entwicklung betreiben und Ihnen einen Code dafür zur Verfügung stellen.
Abhinav Singh Maurya
1
get name wird immer null zurückgeben, seien Sie vorsichtig
vuhung3990
@ Abhinav Singh Maurya können Sie mir helfen, Anrufprotokoll photo_uri aus Anrufprotokollen zu erhalten, weil ich photo_uri nicht aus Anrufprotokoll erhalten kann
Sagar
1
verwalteteQuery () veraltet verwenden Sie dies stattdessen Cursor cursor = context.getContentResolver (). query (CallLog.Calls.CONTENT_URI, null, null, null, CallLog.Calls.DATE + "DESC");
Sai Gopi Me
67

Mit dieser Methode wird das Anrufprotokoll abgerufen. Fügen Sie diese Methode einfach in Ihre Klasse ein und erhalten Sie die Liste des Anrufprotokolls.

Schau dir das an

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();

    }

Die Ausgabe sieht aus

Geben Sie hier die Bildbeschreibung ein

Dwivedi Ji
quelle
Ich erhalte eine Fehlermeldung bei manageQuery (CallLog.Calls.CONTENT_URI, null, null, null, null);
Sunil Parmar
5
Ich habe contentResolver.query verwendet (CallLog.Calls.CONTENT_URI, null, null, null, null);
Sunil Parmar
@ Dwivedi Ji - Es ist ein bisschen ein alter Beitrag - Ihre Methode funktioniert, aber es dauert mindestens 10 Sekunden, um alle meine Anrufprotokolle zu laden.
TheDevMan
@ TheDevMan, entschuldigen Sie Ihre Unannehmlichkeiten. Ja, Sie haben Recht, ich werde meine Antwort bald aktualisieren.
Dwivedi Ji
Danke ich werde auf deine Antwort warten!
TheDevMan
48

Verwenden Sie diese Methode von überall mit einem Kontext

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
quelle
7
Da ManagedQuery jetzt veraltet ist, ist diese Antwort am relevantesten.
Abhi
16

Dieser Beitrag ist ein bisschen alt, aber hier ist eine weitere einfache Lösung, um Daten zum CallAnbieter von Protokollinhalten in Android abzurufen:

Verwenden Sie diese Bibliothek: https://github.com/EverythingMe/easy-content-providers

Erhalten Sie alle Anrufe:

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

Jeder Anruf verfügt über alle Felder, sodass Sie alle erforderlichen Informationen erhalten können:
Anrufdatum, Dauer, Nummer, Typ (EINGEHEND, AUSGANG, VERPASST), isRead, ...

Es funktioniert mit Listoder Cursorund es gibt eine Beispiel-App, um zu sehen, wie es aussieht und funktioniert.

In der Tat gibt es eine Unterstützung für alle Android-Inhaltsanbieter wie: Kontakte, SMS, Kalender, ... Vollständiges Dokument mit allen Optionen: https://github.com/EverythingMe/easy-content-providers/wiki/Android-providers

Hoffe es hat auch geholfen :)

sromku
quelle
Hey, ich habe deine Lösung überprüft, es ist gut. Das einzige Problem, mit dem ich konfrontiert bin, ist, wie ich die Abhängigkeit in mein Eclipse-Projekt einfügen kann.
Aradhna
@aradhna Die Bibliothek verwendet Gradle und wurde aus Android Studio erstellt. Ich denke, Sie müssen es ein wenig ändern, damit es auf Eclipse
sromku
9

In meinem Projekt erhalte ich eine Fehlermeldung im HTC-Gerät. Jetzt ist dieser Code universell. Ich denke, das ist Hilfe für dich.

    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
quelle
2

Um nur den Verlauf eingehender Anrufe zu erhalten, hilft Ihnen der folgende Code :)

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
quelle
2

Hoffen Sie, dass dieser Code Ihnen hilft, um den Verlauf eingehender, ausgehender und verpasster Anrufe zu erhalten :)

Rufen Sie diesen Code in Ihrem Hintergrund-Thread auf.

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
quelle
1

Verwenden Sie den folgenden Code:

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
quelle
0

Wenn wir Kotlin verwenden, ist es kürzer. Beispiel einer Klasse, die auf Bereitstellungsprotokolle reagiert:

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))
}

Wir können den Cursor auch in eine Karte konvertieren:

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
quelle
0

Bevor Sie erwägen, die Berechtigungen "Anrufprotokoll lesen" oder "SMS lesen" zu einem Teil Ihrer Anwendung zu machen, empfehlen wir Ihnen dringend, sich diese Richtlinie von Google Play Market anzusehen: https://support.google.com/googleplay/android-developer/answer/9047303 hl = en

Diese Berechtigungen sind sehr vertraulich und Sie müssen nachweisen, dass Ihre Anwendung sie benötigt. Aber selbst wenn es wirklich benötigt wird, kann das Google Play Support-Team Ihre Anfrage ohne entsprechende Erklärungen leicht ablehnen.

Das ist mir passiert. Nachdem ich alle erforderlichen Informationen zusammen mit dem Demonstrationsvideo meiner Bewerbung bereitgestellt hatte, wurde diese mit der Erklärung abgelehnt, dass mein "Konto nicht berechtigt ist, eine bestimmte Anwendungsfalllösung in meiner Bewerbung bereitzustellen". (die Liste der Anwendungsfälle, die sie möglicherweise als Ausnahme betrachten ist auf dieser Richtlinienseite aufgeführt). Es wurde kein Link zu einer Richtlinienerklärung bereitgestellt, um zu erklären, was dies alles bedeutet. Im Grunde haben sie meine App nur als nicht ohne richtige Erklärung beurteilt.

Ich wünsche Ihnen viel Glück mit Ihren Bewerbungen, aber seien Sie vorsichtig.

Dpetruha
quelle