Как мне получить доступ к журналу вызовов для Android?

95

Я хочу получить журнал звонков. Например, количество звонков, сделанных пользователем, количество минут разговора и т. Д.

Как мне этого добиться в android?

3кросс
источник
может быть это решение для U developer.android.com/reference/android/database/…
Никундж Патель,
Я помню, что это был преобразователь контента, однако я не знаю, с чего начать.
3cross

Ответы:

69

Это для доступа к истории телефонных звонков:

Начиная с Jellybean (4.1) вам необходимо следующее разрешение:
<uses-permission android:name="android.permission.READ_CALL_LOG" />

Код:

 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.
Абхинав Сингх Маурья
источник
11
Не забудьте включить это разрешение: <uses-permission android: name = "android.permission.READ_CALL_LOG" /> это метод для получения журнала вызовов:
Азиз,
Я не знаю, но теоретически могу сказать, что все сообщения хранятся в одной базе данных. Так что да, он может получить доступ ко всем сообщениям устройства, независимо от двух или одной SIM-карты. Проверьте этот код и дайте мне знать, если он не работает с двумя SIM-картами. Я проведу некоторые исследования и разработки и предоставлю вам код для этого.
Абхинав Сингх Маурья
1
get name всегда будет возвращать null, будьте осторожны
vuhung3990 02
@Abhinav Singh Maurya, не могли бы вы помочь мне получить журнал вызовов photo_uri из журнала вызовов, потому что я не могу получить photo_uri из журнала вызовов
Сагар
1
ManagedQuery () не рекомендуется использовать вместо этого Cursor cursor = context.getContentResolver (). query (CallLog.Calls.CONTENT_URI, null, null, null, CallLog.Calls.DATE + "DESC");
Саи Гопи Ме
67

Этот метод используется для получения журнала вызовов. Просто поместите этот метод в свой класс и получите список журнала вызовов.

Проверить это

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

    }

результат выглядит

введите описание изображения здесь

Двиведи Джи
источник
Я получаю сообщение об ошибке в managedQuery (CallLog.Calls.CONTENT_URI, null, null, null, null);
Сунил Пармар,
5
Я использовал contentResolver.query (CallLog.Calls.CONTENT_URI, null, null, null, null);
Сунил Пармар,
@Dwivedi Ji - Это немного старый пост - ваш метод работает, но для загрузки всех моих журналов вызовов требуется не менее 10 секунд.
TheDevMan
@TheDevMan, извините за неудобства, да, вы правы, я скоро обновлю свой ответ,
Двиведи Джи
Спасибо, буду ждать вашего ответа!
TheDevMan
48

используйте этот метод отовсюду с контекстом

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
источник
7
Поскольку managedQuery устарел, этот ответ наиболее актуален.
abhi
16

Этот пост немного устарел, но вот еще одно простое решение для получения данных, связанных с Callпоставщиком содержимого журналов в Android:

Используйте эту библиотеку: https://github.com/EverythingMe/easy-content-providers

Получать все звонки:

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

Каждый вызов имеет все поля, поэтому вы можете получить любую необходимую информацию:
дата вызова, продолжительность, номер, тип (ВХОДЯЩИЙ, ИСХОДЯЩИЙ, ПРОПУЩЕННЫЙ), isRead, ...

Он работает с Listили, Cursorи есть образец приложения, чтобы увидеть, как оно выглядит и работает.

Фактически, есть поддержка для всех поставщиков контента Android, таких как: Контакты, SMS, Календарь, ... Полная документация со всеми опциями: https://github.com/EverythingMe/easy-content-providers/wiki/Android-providers

Надеюсь, это тоже помогло :)

сромку
источник
Привет, я проверил твое решение, оно хорошее. Единственная проблема, с которой я столкнулся, заключается в том, как добавить зависимость в мой проект eclipse?
Aradhna
@aradhna библиотека использует gradle и была создана из Android Studio. Я думаю, вам нужно будет немного изменить его, чтобы он работал на Eclipse
sromku
9

в моем проекте я получаю сообщение об ошибке int htc device. теперь этот код универсален. Думаю, это тебе поможет.

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

}
Харшид
источник
2

Чтобы получить только историю входящих вызовов, код ниже поможет вам :)

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();
} 
Агиланбу
источник
2

Чтобы получить историю входящих, исходящих и пропущенных вызовов, надеюсь, этот код поможет вам :)

Вызовите этот код в фоновом потоке.

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----------------------------------");
Саураб Гаддельпалливар
источник
1

Используйте код ниже:

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




    }
Рохан Лодхи
источник
0

Если мы используем Котлин, он короче. Пример класса, который отвечает за предоставление журналов вызовов:

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

Мы также можем преобразовать курсор в карту:

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
}
Артем Ботнев
источник
0

Прежде чем рассматривать возможность включения разрешений на чтение журнала вызовов или SMS в ваше приложение, я настоятельно рекомендую вам ознакомиться с этой политикой Google Play Market: https://support.google.com/googleplay/android-developer/answer/9047303 ? hl = ru

Эти разрешения очень важны, и вам нужно будет доказать, что они нужны вашему приложению. Но даже если они действительно нужны, служба поддержки Google Play может легко отклонить ваш запрос без объяснения причин.

Вот что случилось со мной. После предоставления всей необходимой информации вместе с демонстрационным видео моего приложения оно было отклонено с объяснением, что моя «учетная запись не авторизована для предоставления определенного решения варианта использования в моем приложении» (список вариантов использования, которые они могут рассматривать как исключение указан на этой странице Политики). Не было предоставлено никакой ссылки на какое-либо заявление о политике, чтобы объяснить, что все это означает. По сути, они просто посчитали, что мое приложение не работает без надлежащих объяснений.

Я желаю вам удачи с вашими приложениями, ребята, но будьте осторожны.

дпетруха
источник