Android Froyo: моя жизнь с call_log
Я застрял с функциональностью call_log в Froyo. Как многие из вас знают, Froyo регистрирует в журнале вызовов не только звонки, но и каждое исходящее и входящее SMS-сообщение. В параметрах можно выбрать отображение всего этого дерьма или только определенных типов (исходящие вызовы, входящие вызовы, отправленные сообщения, полученные сообщения и т. Д.), Но поскольку это переключатель, вы не можете указать, например, только текущие и входящие вызовы. Очень известная и раздражающая функциональность Froyo.
Поэтому я начал писать какой-то простой инструмент для чтения журнала вызовов самостоятельно. Вот фрагмент кода:
try {
mCur = getApplicationContext().getContentResolver()
.query(CallLog.Calls.CONTENT_URI, columns, null, null, null );
mCur.moveToFirst();
io = mCur.getColumnIndex(CallLog.Calls._ID);
bo = mCur.getColumnIndex(CallLog.Calls.NUMBER);
no = mCur.getColumnIndex(CallLog.Calls.CACHED_NAME);
to = mCur.getColumnIndex(CallLog.Calls.TYPE);
while (mCur.isAfterLast() == false) {
i = mCur.getString(io);
b = mCur.getString(bo);
n = mCur.getString(no);
t = mCur.getString(to);
Log.i(TAG, "CallLog: ID="+i+" number="+b+" name="+n+" type="+t);
mCur.moveToNext();
}
} catch (Exception e) {
Log.e(TAG, "updateCallLog", e);
} finally {
if (mCur != null) {
mCur.close();
mCur = null;
}
}
Сюрприз, сюрприз, провайдер call_log пропускает записи смс из журнала вызовов. Таким образом, с помощью кода выше я вижу только записи о вызовах (входящие или исходящие), все остальные записи пропускаются. Немного больше углубившись в это выяснилось, что поставщик CallLog добавляет внутреннюю фильтрацию в базу данных журнала вызовов:
02-03 09:26:42.348 E/CLCService(28244): android.database.sqlite.SQLiteException:
near ")": syntax error: , while compiling:
SELECT _id, name, number, type FROM logs WHERE (logtype=100 OR logtype=500) AND (_ID=)
Не ищите синтаксическую ошибку, она была создана специально для того, чтобы заставить провайдера сбросить SQL-запрос, вызвав query(CallLog.Calls.CONTENT_URI, columns, "_ID=", null, null ))
, (_ID=)
это то, что предусмотрено в запросе, остальные (logtype=100 OR logtype=500)
видимо добавляется самим провайдером журнала звонков.
Итак, у меня есть два вопроса:
- Где я могу найти в коде Android, как провайдер добавляет фильтр logtype? Я искал в CallLog.java и CallLogProvider.java и не могу найти его.
- Как я могу прочитать все записи из журнала вызовов в Froyo? Я не могу обойти провайдера журнала вызовов и использовать свой собственный помощник SQL для этого, пока я не буду рутировать телефон, который не вариант. Есть ли другой способ сделать это?
1 ответ
Я не уверен, что происходит не так, но чтение журнала вызовов для получения только входящих или исходящих вызовов достаточно просто. Приведенный ниже пример добавляет ограничения к запросу, чтобы он возвращал данные только для исходящих вызовов, совершенных после определенной даты. where
Строка использует вопросительные знаки, чтобы указать, где значения из wargs
массив должен быть подставлен для формирования запроса SQL.
О том, где происходит дополнительное предложение WHERE. Почти наверняка в реализации провайдера calllog. У провайдеров обычно есть оператор switch, который использует URI, который вы используете для открытия провайдера, а затем добавляет ограничения на основе URI. Кажется, что один из журналов находится в пакетах / провайдеров /ContactsProvider.
public static int getMinutesUsedSince(Context context, Date date) {
Uri uri = CallLog.Calls.CONTENT_URI;
String columns[] = new String[] { CallLog.Calls.DURATION };
String where = CallLog.Calls.TYPE + "=? AND " + CallLog.Calls.DATE + ">?";
String wargs[] = new String[] {
String.valueOf(CallLog.Calls.OUTGOING_TYPE),
String.valueOf(date.getTime())
};
String sortOrder = "date DESC";
Cursor c = context.getContentResolver().query(uri, columns, where, wargs, sortOrder);
long sum = 0;
int durationIndex = c.getColumnIndex(CallLog.Calls.DURATION);
if (c.moveToFirst()) {
do {
/* for each individual call, round up to the nearest minute */
long duration = c.getLong(durationIndex);
long minutes = (long)Math.ceil(duration / 60.0);
sum += minutes;
} while (c.moveToNext());
}
c.close();
return (int)sum;
}