Is it possible to delete only incoming calls from the call log list?
If so how?
I am able to delete all of them easily but not sure how to delete only incoming calls?
Can somebody help me out with this?
Thanks!
In CallLog provider database, android.provider.CallLog.Calls.TYPE ("type") column will have value
android.provider.CallLog.Calls.INCOMING_TYPE (1) for an incoming call record.
Use below method with condition type = 1
public void delete(final String id, final String number) {
Uri uri = Uri.parse("content://call_log/calls");
ContentResolver cr = context.getContentResolver();
Cursor c = cr.query(uri, null, "and type = 1 and _id" + "=?", new String[] { "" + id }, null);
if (c != null && c.moveToFirst()) {
do {
String pid = c.getString(c.getColumnIndex("_id"));
String pnumber = c.getString(c.getColumnIndex("NUMBER"));
if (id.equals(pid) && number.equals(pnumber)) {
context.getContentResolver().delete(CallLog.Calls.CONTENT_URI, CallLog.Calls._ID + " = ?", new String[] { id });
}
} while (c.moveToNext());
}
}
Related
I'm working on a Cordova app that needs to be able to get a list of phone numbers involved in a group text. I'm querying content://mms/[id]/addr for that. I'm testing on a Pixel 2 and for the MMS messages prior to March 10, 2018, this works fine. But for messages on or after that date, it fails (comes back as null). Is there a different address I should be querying? Any other ideas?
Using content://mms/ wil give you MMS conversation list and using content://mms-sms/conversations will give you both the first one or 2nd one you can try both if any of them doesn't work
so first you will have to get a list of MMS only using
ContentResolver contentResolver = getContentResolver();
final String[] projection = new String[]{"_id", "ct_t"};
Uri uri = Uri.parse("content://mms-sms/conversations");
Cursor query = contentResolver.query(uri, projection, null, null, null);
if (query.moveToFirst()) {
do {
String itemId = query.getString(query.getColumnIndex("_id"));
int getRowID = Integer.parseInt(itemId);
String string = query.getString(query.getColumnIndex("ct_t"));
if ("application/vnd.wap.multipart.related".equals(string)) {
// this item is MMS so get the number using function getAddressNumber and log it
Log.d("number","address/number:" + getAddressNumber(getRowID));
} else {
// item is sms do nothing
}
} while (query.moveToNext());
}
private String getAddressNumber(int id) {
String selectionAdd = new String("msg_id=" + id);
String uriStr = MessageFormat.format("content://mms/{0}/addr", id);
Uri uriAddress = Uri.parse(uriStr);
Cursor cAdd = getContentResolver().query(uriAddress, null,
selectionAdd, null, null);
String name = null;
if (cAdd.moveToFirst()) {
do {
String number = cAdd.getString(cAdd.getColumnIndex("address"));
if (number != null) {
try {
Long.parseLong(number.replace("-", ""));
name = number;
} catch (NumberFormatException nfe) {
if (name == null) {
name = number;
}
}
}
} while (cAdd.moveToNext());
}
if (cAdd != null) {
cAdd.close();
}
return name;
}
if above function getAddressNumber doesn't work you can try this one as well with a little bit of changes
public static String getMMSAddress(Context context, String id) {
String addrSelection = "type=137 AND msg_id=" + id;
String uriStr = MessageFormat.format("content://mms/{0}/addr", id);
Uri uriAddress = Uri.parse(uriStr);
String[] columns = { "address" };
Cursor cursor = context.getContentResolver().query(uriAddress, columns,
addrSelection, null, null);
String address = "";
String val;
if (cursor.moveToFirst()) {
do {
val = cursor.getString(cursor.getColumnIndex("address"));
if (val != null) {
address = val;
break;
}
} while (cursor.moveToNext());
}
if (cursor != null) {
cursor.close();
}
return address;
}
here is the defination for line
String addrSelection = "type=137 AND msg_id=" + id;
type constant come from the PduHeadersPduHeaders
class: 0x97 / 151 is PduHeaders.TO and 0x89 / 137 is PduHeaders.FROM you can change FROM or TO what you need.
if its still empty try below part and implement this in your code
Uri uriMms = Uri.parse("content://mms/");
final String[] projection = new String[]{"*"};
Cursor cursor = contentResolver.query(uriMms, projection, null, null, null);
String id = cursor.getString(cursor.getColumnIndex("_id"));
String selectionPart = "mid=" + id;
Uri uri = Uri.parse("content://mms/part");
Cursor cursor2 = getContentResolver().query(uri, null, selectionPart, null, null);
Here's how AOSP's (Android Open Source Project) messaging app does it:
Every message (SMS/ MMS) has a message ID represented as _ID in their respective tables
With this id pull the thread for the respective message
The threads table has a column called recipient_ids, this might be Space separated for group message, something like this:
123 456 789
Where 123 456 etc are the recipient ids.
Get address for respective recipient ids. Now this is a bit tricky, but AOSP uses the following uri: content://mms-sms/canonical-address
So the final method to get an array of addresses looks something likes this:
private fun getAddressFromRecipientId(spaceSepIds: String, context: Context): Array<String?> {
val singleCanonicalAddressUri = Uri.parse("content://mms-sms/canonical-address")
with(spaceSepIds.split(" ")) {
val addressArray: Array<String?> = arrayOfNulls(this.size)
this.forEachIndexed { index, address ->
if (!address.isEmpty()) {
val longId = address.toLong()
context.contentResolver.query(ContentUris.withAppendedId(singleCanonicalAddressUri, longId), null, null, null, null).use { cursor ->
if (cursor != null && cursor.moveToNext())
addressArray[index] = "${cursor.getString(0)} "
}
}
}
return addressArray
}
return arrayOf()
}
Hope this helps. Also the function is in kotlin but it's pretty easy to figure out what's happening there.
Also, you already have ids, so you can just call this method with either the space separated IDs or without them, the function works both ways.
I try to implement a live search over the users contacts, and I want to get the name, thumbnail and address (if there is one) of each matching contact.
The live search is running while the user is typing.
So he types ma and will get 'martin', 'matthews'...
He'll continue with mat and will only see 'matthews'
I try to achieve this with a single query like the following, but I always get the contact number in the FORMATTED_ADRESS field. I guess I have a JOIN problem, because I'm using ContactsContract.CommonDataKinds and ContactsContract.Contacts in the same query?
public static List<ContactModel> getContactsForQuery(Context context, String query) {
String[] projection = new String[] {
ContactsContract.Contacts.DISPLAY_NAME,
Contacts.PHOTO_THUMBNAIL_URI,
ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS
};
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String selection = ContactsContract.Contacts.DISPLAY_NAME + " LIKE '%" + query + "%'";
Cursor cursor = context.getContentResolver().query(uri, projection, selection, null,null);
if (cursor.moveToFirst()) {
do {
String name = cursor.getString(0);
String thumbail = cursor.getString(1);
String formattedADress = cursor.getString(2);
}
while (cursor.moveToNext());
}
I actually solved my issue, with
querying for Contacts._ID, Contacts.DISPLAY_NAME
start a second query with the Contacts._ID like the following
Cursor detailCursor = context.getContentResolver().query(
ContactsContract.Data.CONTENT_URI,
new String[]{
CommonDataKinds.StructuredPostal.STREET,
CommonDataKinds.StructuredPostal.CITY,
CommonDataKinds.StructuredPostal.POSTCODE
},
ContactsContract.Data.CONTACT_ID + "=? AND "
+ CommonDataKinds.StructuredPostal.MIMETYPE + "=?",
new String[]{
String.valueOf(contactID),
CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE
},
null);
but this will start a second query for every contact, which might not be the best approach.
So my final question is: is it possible to get this work with the first query?
Mmmh, very sad, that no one was able to answer my question and grab the bounty points ;-(
For the record, here's my working example. It solves the issue but I still think it's producing a big overload. On every user entry (afterTextchange) I call the getContactsDetailsQuery which first gets all users with their ID containing the query in their name (cursor) and afterwards I start another query (detailCursor) for every user to get the adress. To prevent the overload, i added an limit..
public static List<SearchModel> getContactDetailsForQuery(Context context, String query, int limit) {
final int CONTACT_ID_INDEX = 0;
final int CONTACT_NAME_INDEX = 1;
final int CONTACT_THUMBNAIL_INDEX = 2;
//my custom model to hold my results
List<SearchModel> results = new ArrayList<SearchModel>();
final String[] selectUser = new String[]{
Contacts._ID,
Contacts.DISPLAY_NAME,
Contacts.PHOTO_THUMBNAIL_URI};
String selection = Contacts.DISPLAY_NAME + " LIKE ?";
String[] selectionArgs = new String[]{"%" + query + "%"};
String sortOrder = Contacts.DISPLAY_NAME + " ASC";
Cursor cursor = context.getContentResolver().query(Contacts.CONTENT_URI, selectUser, selection, selectionArgs, sortOrder, null);
int contactCounter = 0;
if (cursor != null && cursor.moveToFirst()) {
do {
String contactID = cursor.getString(CONTACT_ID_INDEX);
String displayName = cursor.getString(CONTACT_NAME_INDEX);
String thumbnail = cursor.getString(CONTACT_THUMBNAIL_INDEX);
//get user details with user id (this is the query i wanted to change in my question!!)
Cursor detailCursor = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI,
new String[]{
CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS},
ContactsContract.Data.CONTACT_ID + "=? AND " +
CommonDataKinds.StructuredPostal.MIMETYPE + "=?",
new String[]{String.valueOf(contactID), CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE},
null);
if (detailCursor != null && detailCursor.moveToFirst()) {
//special case: user has several address, query all of them
do {
String formattedAddress = detailCursor.getString(detailCursor.getColumnIndex(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS));
//user has serveral adress -> init model for each adress
SearchModel contact = new SearchModel();
results.add(contact);
contactCounter++;
} while (detailCursor.moveToNext() && contactCounter < limit);
} else {
//user has no adress -> init model
SearchModel contact = new SearchModel();
results.add(contact);
contactCounter++;
}
detailCursor.close();
} while (cursor.moveToNext() && contactCounter < limit);
}
cursor.close();
return results;
}
I am developing an application, where I need to fetch the phone number from the contacts corresponding to the name provided. I have tried many codes but none of them seem to work.
Here is the code I'm currently using now
public static String getContactPhoneNumber(Context context, String contactName, int type) {
String phoneNumber = null;
String[] whereArgs = new String[] { contactName, String.valueOf(type) };
Log.d(TAG, String.valueOf(contactName));
Cursor cursor = context.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.Contacts.DISPLAY_NAME + " = ? and "
+ ContactsContract.CommonDataKinds.Phone.TYPE + " = ?", whereArgs, null);
int phoneNumberIndex = cursor
.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER);
Log.d(TAG, String.valueOf(cursor.getCount()));
if (cursor != null) {
Log.v(TAG, "Cursor Not null");
try {
if (cursor.moveToNext()) {
Log.v(TAG, "Moved to first");
Log.v(TAG, "Cursor Moved to first and checking");
phoneNumber = cursor.getString(phoneNumberIndex);
}
} finally {
Log.v(TAG, "In finally");
cursor.close();
}
}
Log.v(TAG, "Returning phone number");
return phoneNumber;
}
On passing Contact Name (say: John Doe) and type (2 which is int value for Mobile Type), the phone number returned is null even though the contact "John Doe" exists in my contact list.
Please help!!!
Try this
instead of ContactsContract.CommonDataKinds.Phone.CONTENT_URI Pass
ContactsContract.Contacts.CONTENT_URI parameter to query method.
I am trying to get the address of the sender but I run into a little problem. If the person that sends the message is the first person in any of the conversations to send one, the query of the content://mms/inbox returns with zero rows?? but when someone sends any other mms message it will return back with the _id fine and i dont understand why the first one wont work right?
private String checkMmsMessages(Context context){
String address = "address";
Cursor curPdu = context.getContentResolver ().query(Uri.parse("content://mms/inbox"), null, null, null, null);
if(curPdu.moveToNext()){ //first MMS message curPdu.moveToNext() is false
String id = curPdu.getString (curPdu.getColumnIndex ("_id"));
Log.v("MMS", "ID1: " + id.toString());
Uri uriAddr = Uri.parse ("content://mms/" + id + "/addr");
Cursor curAddr = context.getContentResolver().query(uriAddr,null,"type=137",null,null);
if(curAddr.moveToNext()){
address = curAddr.getString (curAddr.getColumnIndex ("address"));
Log.v("MMS", "Address1: " + address.toString());
if(address.contentEquals("insert-address-token")){
Cursor curAddr2 = context.getContentResolver().query(uriAddr,null,"type=151", null,null);
if(curAddr2.moveToNext()){
address = curAddr2.getString(curAddr2.getColumnIndex("address"));
}
}
}
}
Log.v("MMS", address.toString());
return address;
}
Also something else that does not make sense is when when i have the phone plugged into the computer and step through the that section with the debugger, that problem does not happen and it gets the address every time.... it only happens when the phone is not connected, i just dont understand?
The problem was I was checking the database before the message was put into the database so I had to put a delay on the check
I think the issue is you are passing a value for selectionArgs instead of null to the query() method. I am not actually calling the mCursor's moveToNext() method in my code but instead I am implementing this logic in the getView() method of a SimpleCursorAdapter.
Uri uri = Uri.parse("content://mms-sms/conversations/" + mThreadId);
String[] projection = new String[] { "body", "person", "sub",
"subject", "retr_st", "type", "date", "ct_cls", "sub_cs",
"_id", "read", "ct_l", "st", "msg_box", "reply_path_present",
"m_cls", "read_status", "ct_t", "status", "retr_txt_cs",
"d_rpt", "error_code", "m_id", "date_sent", "m_type", "v",
"exp", "pri", "service_center", "address", "rr", "rpt_a",
"resp_txt", "locked", "resp_st", "m_size" };
String sortOrder = "normalized_date";
Cursor mCursor = getActivity().getContentResolver().query(uri,projection, null, null, sortOrder);
String messageAddress;
int type;
while (mCursor.moveToNext()) {
String messageId = mCursor.getString(mCursor.getColumnIndex("_id"));
Uri.Builder builder = Uri.parse("content://mms").buildUpon();
builder.appendPath(messageId).appendPath("addr");
Cursor c = mContext.getContentResolver().query(builder.build(), new String[] {
"*"
}, null, null, null);
while (c.moveToNext()) {
messageAddress = c.getString(c.getColumnIndex("address"));
if (!messageAddress.equals("insert-address-token")) {
type = c.getInt(c.getColumnIndex("type"));
c.moveToLast();
}
}
c.close();
}
try this...
private String getAddressNumber(String id) {
String selectionAdd = new String("msg_id=" + id);
String uriStr = MessageFormat.format("content://mms/{0}/addr", id);
Uri uriAddress = Uri.parse(uriStr);
Cursor cursor = getContentResolver().query(uriAddress, null, selectionAdd, null, null);
String phoneNum = null;
if (cursor.moveToFirst()) {
do {
String number = cursor.getString(cursor.getColumnIndex("address"));
if (number != null) {
boolean isNumberFormat = true;
try {
Long.parseLong(number.replace("-", ""));
phoneNum = number;
} catch (NumberFormatException e) { // ex) "insert-address-token"
// if (phoneNum == null) {
// phoneNum = number;
// }
isNumberFormat = false;
}
if (isNumberFormat)
break;
}
} while (cursor.moveToNext());
}
if (cursor != null) {
cursor.close();
}
return phoneNum;
}
I would like to retrieve the name of a contact associated with an incoming telephone number. As I process the incoming number in the broascastreceiver having a String with the name of the incoming caller would help my project greatly.
I would think this involves a query using the sql WHERE clause as a filter, but do I need to sort the contacts? An example or hint would be of great assistance.
Although this has already been answered, but here is the complete function to get the contact name from number. Hope it will help others:
public static String getContactName(Context context, String phoneNumber) {
ContentResolver cr = context.getContentResolver();
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
Cursor cursor = cr.query(uri, new String[]{PhoneLookup.DISPLAY_NAME}, null, null, null);
if (cursor == null) {
return null;
}
String contactName = null;
if(cursor.moveToFirst()) {
contactName = cursor.getString(cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME));
}
if(cursor != null && !cursor.isClosed()) {
cursor.close();
}
return contactName;
}
[Updating based on Marcus's comment]
You will have to ask for this permission:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
For that you need to use the optimized PhoneLookup provider as described.
Add the permission to AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
Then:
public String getContactName(final String phoneNumber, Context context)
{
Uri uri=Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,Uri.encode(phoneNumber));
String[] projection = new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME};
String contactName="";
Cursor cursor=context.getContentResolver().query(uri,projection,null,null,null);
if (cursor != null) {
if(cursor.moveToFirst()) {
contactName=cursor.getString(0);
}
cursor.close();
}
return contactName;
}
This was very helpful, here's my final code for retrieving the caller's Name, id, and Photo:
private void uploadContactPhoto(Context context, String number) {
Log.v("ffnet", "Started uploadcontactphoto...");
String name = null;
String contactId = null;
InputStream input = null;
// define the columns I want the query to return
String[] projection = new String[] {
ContactsContract.PhoneLookup.DISPLAY_NAME,
ContactsContract.PhoneLookup._ID};
// encode the phone number and build the filter URI
Uri contactUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
// query time
Cursor cursor = context.getContentResolver().query(contactUri, projection, null, null, null);
if (cursor.moveToFirst()) {
// Get values from contacts database:
contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup._ID));
name = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
// Get photo of contactId as input stream:
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(contactId));
input = ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri);
Log.v("ffnet", "Started uploadcontactphoto: Contact Found # " + number);
Log.v("ffnet", "Started uploadcontactphoto: Contact name = " + name);
Log.v("ffnet", "Started uploadcontactphoto: Contact id = " + contactId);
} else {
Log.v("ffnet", "Started uploadcontactphoto: Contact Not Found # " + number);
return; // contact not found
}
// Only continue if we found a valid contact photo:
if (input == null) {
Log.v("ffnet", "Started uploadcontactphoto: No photo found, id = " + contactId + " name = " + name);
return; // no photo
} else {
this.type = contactId;
Log.v("ffnet", "Started uploadcontactphoto: Photo found, id = " + contactId + " name = " + name);
}
... then just do whatever you want with "input" (their photo as an InputStream), "name", and "contactId".
And here are the docs listing the ~15 or so columns you have access to, just add them to the projection near the start of the code up above:
http://developer.android.com/reference/android/provider/ContactsContract.PhoneLookup.html
This version is the same as Vikram.exe's answer with code to avoid the ANR
interface GetContactNameListener {
void contactName(String name);
}
public void getContactName(final String phoneNumber,final GetContactNameListener listener) {
new Thread(new Runnable() {
#Override
public void run() {
ContentResolver cr = getContentResolver();
Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
Cursor cursor = cr.query(uri, new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME}, null, null, null);
if (cursor == null) {
return;
}
String contactName = null;
if(cursor.moveToFirst()) {
contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
}
if(cursor != null && !cursor.isClosed()) {
cursor.close();
}
listener.contactName(contactName);
}
}).start();
}
Pass the contact number from which you are getting the call in the following method. This Method will check whether the contact is saved in your mobile or not. If the contact is saved then it will return the contact name otherwise it return a string unknown number
Add this code in your Broadcast receiver class
public String getContactDisplayNameByNumber(String number,Context context) {
Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
name = "Incoming call from";
ContentResolver contentResolver = context.getContentResolver();
Cursor contactLookup = contentResolver.query(uri, null, null, null, null);
try {
if (contactLookup != null && contactLookup.getCount() > 0) {
contactLookup.moveToNext();
name = contactLookup.getString(contactLookup.getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
// this.id =
// contactLookup.getString(contactLookup.getColumnIndex(ContactsContract.Data.CONTACT_ID));
// String contactId =
// contactLookup.getString(contactLookup.getColumnIndex(BaseColumns._ID));
}else{
name = "Unknown number";
}
} finally {
if (contactLookup != null) {
contactLookup.close();
}
}
return name;
}
to get Source code visit this link
For that, we can use the PhoneLookup provider to get the names or contact details using the mobile number.
Add the permission to AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
Add the following custom kotlin method in your activity and call the same with the required mobile number.
fun getContactNameByPhoneNumber(context: Context, phoneNumber: String): String? {
var phone = phoneNumber
if(phoneNumber != null && phoneNumber.length > 0 && phoneNumber[0].equals('+'))
phone = phoneNumber.substring(3)
val projection = arrayOf(
ContactsContract.PhoneLookup.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER
)
val cursor = context.contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
projection,
ContactsContract.CommonDataKinds.Phone.NUMBER, null, null
) ?: return ""
for (i in 0 until cursor.count) {
cursor.moveToPosition(i)
val nameFieldColumnIndex = cursor
.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME)
val phoneFieldColumnIndex = cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
if(phone.equals(cursor.getString(phoneFieldColumnIndex)))
return cursor.getString(nameFieldColumnIndex)
}
return "Unknown"
}
For more: https://developer.android.com/training/contacts-provider/retrieve-names