I want to retrieve a user's profile and it's image, but this is not working. I always get an empty cursor (cursor.getCount() == 0). Can someone help?
I have a profile with an image and a phone number on my phone but I can't read it. Permissions (read and write contacts permissions) are granted and I can retrieve all my phone contacts, but not the own profile.
Any ideas?
Code
void loadUser() {
Uri dataUri = Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI, ContactsContract.Contacts.Data.CONTENT_DIRECTORY);
String[] selection = new String[]
{
ContactsContract.Data.RAW_CONTACT_ID,
ContactsContract.Data._ID,
ContactsContract.Profile.DISPLAY_NAME,
ContactsContract.Profile.PHOTO_URI,
ContactsContract.Profile.LOOKUP_KEY,
ContactsContract.Data.DATA_VERSION
};
Cursor cursor = MainApp.get().getContentResolver().query(
dataUri,
selection,
null,
null,
null);
if (cursor != null) {
L.d("MY PROFILE - cursor size: %d", cursor.getCount());
int rawId = cursor.getColumnIndex(ContactsContract.Data.RAW_CONTACT_ID);
int id = cursor.getColumnIndex(ContactsContract.Data._ID);
int name = cursor.getColumnIndex(ContactsContract.Profile.DISPLAY_NAME);
int photoUri = cursor.getColumnIndex(ContactsContract.Profile.PHOTO_URI);
int lookupKey = cursor.getColumnIndex(ContactsContract.Profile.LOOKUP_KEY);
int version = cursor.getColumnIndex(ContactsContract.Data.DATA_VERSION);
try {
if (cursor.moveToFirst()) {
long phRawId = cursor.getLong(rawId);
int phId = cursor.getInt(id);
String phName = cursor.getString(name);
String phImageUri = cursor.getString(photoUri);
String phLookupKey = cursor.getString(lookupKey);
int phVersion = cursor.getInt(version);
boolean phExists = true;
L.d("MY PROFILE - RawID: %d, ID: %d", phRawId, phId);
// ... profile successfully retrieved
} else {
L.d("MY PROFILE - cursor is EMPTY");
}
} finally {
cursor.close();
}
} else {
L.d("MY PROFILE - cursor = NULL");
}
}
Additional info
I think this code worked on my S6 with android 7 but it's not working on my new S9 with android 8 on it (can't test it on my old phone anymore as it's not working anymore). So this may be an android version specific problem...
This appears to be bad implementation of Samsung's Contacts app, I've opened a bug report on their developer's forum here: https://developer.samsung.com/forum/thread/contacts-app-profile-is-not-accessible-via-contactscontractprofile-api/201/354874
Related
I have an app that reads the contact details of the phone. This code returns 744 as the id of a particular contact's row when accessed through Email.ContentUri.
var uriEmail = ContactsContract.CommonDataKinds.Email.ContentUri;
string[] projectionEmail = { ContactsContract.Contacts.InterfaceConsts.Id, ContactsContract.Contacts.InterfaceConsts.DisplayName, ContactsContract.Contacts.InterfaceConsts.PhotoUri, ContactsContract.CommonDataKinds.Email.Address };
var cursorEmail = this.Activity.ContentResolver.Query(uriEmail, projectionEmail, null, null, null);
// var contactList = new List<string>();
contacts = new ObservableCollection<Contact>();
if (cursorEmail.MoveToFirst())
{
do
{
//contactList.Add(cursor.GetString(cursor.GetColumnIndex(projection[2])));
contacts.Add(new Contact()
{
Id = cursorEmail.GetInt(cursorEmail.GetColumnIndex(projectionEmail[0])),
Name = cursorEmail.GetString(cursorEmail.GetColumnIndex(projectionEmail[1])),
Photo = cursorEmail.GetString(cursorEmail.GetColumnIndex(projectionEmail[2])),
Email = cursorEmail.GetString(cursorEmail.GetColumnIndex(projectionEmail[3])),
});
}
while (cursorEmail.MoveToNext());
}
ListView listEmail = v.FindViewById<ListView>(Resource.Id.listViewSelect);
listEmail.Adapter = new ContactAdapter(v.Context, contacts);
listEmail.ItemClick += OnClientListClick;
This code returns 752 as the id of the same contact when accessed through StructuredPostal.ContentUri.
var uriAddress = ContactsContract.CommonDataKinds.StructuredPostal.ContentUri;
string[] projectionAddress = { ContactsContract.Contacts.InterfaceConsts.Id, ContactsContract.Contacts.InterfaceConsts.DisplayName, ContactsContract.Contacts.InterfaceConsts.PhotoUri, ContactsContract.CommonDataKinds.StructuredPostal.Street, ContactsContract.CommonDataKinds.StructuredPostal.Postcode };
var cursorAddress = this.Activity.ContentResolver.Query(uriAddress, projectionAddress, null, null, null);
// var contactList = new List<string>();
properties = new ObservableCollection<Property>();
if (cursorAddress.MoveToFirst())
{
do
{
int n = cursorAddress.GetInt(cursorAddress.GetColumnIndex(projectionAddress[0]));
string str = cursorAddress.GetString(cursorAddress.GetColumnIndex(projectionAddress[1]));
if (n == nId)
{
//contactList.Add(cursor.GetString(cursor.GetColumnIndex(projection[2])));
properties.Add(new Property()
{
Id = cursorAddress.GetInt(cursorAddress.GetColumnIndex(projectionAddress[0])),
Name = cursorAddress.GetString(cursorAddress.GetColumnIndex(projectionAddress[1])),
Photo = cursorAddress.GetString(cursorAddress.GetColumnIndex(projectionAddress[2])),
Street = cursorAddress.GetString(cursorAddress.GetColumnIndex(projectionAddress[3])),
Postcode = cursorAddress.GetString(cursorAddress.GetColumnIndex(projectionAddress[4])),
});
}
}
while (cursorAddress.MoveToNext());
}
ListView listAddress = v.FindViewById<ListView>(Resource.Id.listViewSelect);
listAddress.Adapter = new PropertyAdapter(v.Context, properties);
listAddress.ItemClick += OnPropertyListClick;
Is there a unique identifier that's allocated to the contact in the Android phone?
If you wanna a unique id, you could use CONTACT_ID which is a reference to _ID of each contact.
CONTACT_ID:
https://developer.android.com/reference/android/provider/ContactsContract.RawContactsColumns.html#CONTACT_ID
_ID:https://developer.android.com/reference/android/provider/BaseColumns#_ID
If you want to use the unique id cross device, you could try to use the LOOKUP_KEY.
LOOKUP_KEY:
https://developer.android.google.cn/reference/android/provider/ContactsContract.ContactsColumns.html#LOOKUP_KEY
For more code details, you could check the link below. Get cross-device unique ID for Android phone contacts
I want to get an int with the number of unread emails in the accounts of the device. I have seen that there is a new way to do this using the "Gmail Labels Public API"
http://android-developers.blogspot.in/2012/04/gmail-public-labels-api.html
I have read the documentation and downloaded the sample application and it really works. But I have two problems: (
My intention is to get an int with the number of unread conversations, i try this:
public static int getUnreadGmailCount(Context context) {
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(GmailContract.Labels.getLabelsUri("ensisinfo102#gmail.com"),
null,
null, null,
null);
if (cursor == null || cursor.isAfterLast()) {
Log.d(TAG, "No Gmail inbox information found for account.");
if (cursor != null) {
cursor.close();
}
return 0;
}
int count = 0;
while (cursor.moveToNext()) {
if (CANONICAL_NAME_INBOX_CATEGORY_PRIMARY.equals(cursor.getString(cursor.getColumnIndex(CANONICAL_NAME)))) {
count = cursor.getInt(cursor.getColumnIndex(NUM_UNREAD_CONVERSATIONS));
System.out.println("count is====>"+count);
break;
}
}
cursor.close();
return count;
}
but not works, always returns "0",But in gmail i have 3 unread messages
really appreciate any help
thanks and regards
You can get a label and check the messagesUnread. The INBOX label is probably what you want:
Request
GET https://www.googleapis.com/gmail/v1/users/me/labels/INBOX?access_token={ACCESS_TOKEN}
Response
{
"id": "INBOX",
"name": "INBOX",
"messageListVisibility": "hide",
"labelListVisibility": "labelShow",
"type": "system",
"messagesTotal": 4527,
"messagesUnread": 4498,
"threadsTotal": 4168,
"threadsUnread": 4154
}
Please read carefully this document and also check this one
I want to load several contacts via Xamarin.Contacts.AddressBook, at the moment I have something like:
var loookupIDs = /* load 10 saved contact IDs */
var addressBook = new AddressBook(context) { PreferContactAggregation = true };
foreach(var id in loookupIDs)
{
var contact = addressBook.Load(id);
names.Add(contact.DisplayName);
}
However, this is really slow (tested on Android device) - even just loading 10 contacts. Is there a way to batch up the loading so it's faster? Or is the only option to use platform specific APIs instead of the Xamarin wrapper.
Yes, Xamarin.Mobile is kind of slow. It combines all possible contacts (phones, mails, etc) and all possible fields, which is not recommended by Android reference manual.
I recommend you to use native way to query your contacts with Cursor and filter it for your needs. Sadly, Xamarin dev mixed up all constants, so it is not trivial task.
Here is complete example
public class PhoneContactInfo
{
public string PhoneContactID { get; set; }
public string ContactName { get; set; }
public string ContactNumber { get; set; }
}
public IEnumerable<PhoneContactInfo> GetAllPhoneContacts(IEnumerable<int> filterIds = null)
{
Log.Debug("GetAllPhoneContacts", "Getting all Contacts");
var arrContacts = new System.Collections.Generic.List<PhoneContactInfo>();
PhoneContactInfo phoneContactInfo = null;
var uri = ContactsContract.CommonDataKinds.Phone.ContentUri;
string[] projection = { ContactsContract.Contacts.InterfaceConsts.Id,
ContactsContract.Contacts.InterfaceConsts.DisplayName,
ContactsContract.CommonDataKinds.Phone.Number
};
//String[] strings = filterIds.Select(k => Convert.ToString(k)).ToArray();
//string whereClause = ContactsContract.Contacts.InterfaceConsts.Id + " = ? ";
var cursor = MainActivity.ContextHolder.ContentResolver.Query(uri, projection,
null,
null,
null);
cursor.MoveToFirst();
while (cursor.IsAfterLast == false)
{
int phoneContactID = cursor.GetInt(cursor.GetColumnIndex(ContactsContract.Contacts.InterfaceConsts.Id));
if (filterIds.Contains(phoneContactID))
{
String contactNumber = cursor.GetString(cursor.GetColumnIndex(ContactsContract.CommonDataKinds.Phone.Number));
String contactName = cursor.GetString(cursor.GetColumnIndex(ContactsContract.Contacts.InterfaceConsts.DisplayName));
phoneContactInfo = new PhoneContactInfo()
{
PhoneContactID = Convert.ToString(phoneContactID),
ContactName = contactName,
ContactNumber = contactNumber
};
arrContacts.Add(phoneContactInfo);
}
cursor.MoveToNext();
}
cursor.Close();
cursor = null;
Log.Debug("GetAllPhoneContacts", "Got all Contacts");
return arrContacts;
}
If you wish to add some fancy async
public Task<IEnumerable<PhoneContactInfo>> GetAllPhoneContactsAsync(IEnumerable<int> filterIds)
{
return Task.FromResult(GetAllPhoneContacts(filterIds));
}
Also take a look at commented whereClause. You possibly can construct 'SQL like' where clause to make this query even more faster. Just build a string with several '=' and 'or'
P.S.
I didn't measure performance differences, if anyone has decent statistics i will be grateful
It looks like you access AdressBook for each loookupID, this might cause your speed issue.
Try:
1) Fetch all contacts, or only those you might be interested in. (Use Linq)
2) Do further work with found contacts
Example from Xamarin docs:
http://blog.xamarin.com/introducing-xamarin-contacts/
var book = new AddressBook (this) {
PreferContactAggregation = true
};
foreach (Contact c in book.Where (c => c.LastName == "Smith")) {
print (c.DisplayName);
foreach (Phone p in c.Phones)
print ("Phone: " + p.Number);
foreach (Email e in c.Emails)
print ("Email: " + e.Address);
}
I tried to get sms list and below code works well in some devices but not working in other devices. Details tested with four devices using below code.
LG optimus one[android 2.2] - works well. SS galaxy s3[android4.0.4] - works well. SS galaxy s2[android
2.3.5] - not working. SS galaxy s2[android 4.0.4] - not working.
It seems that result depends on devices not android version because two devices with same android version[4.0.4] show differently. Symptom in the devices not working is that c.getCount() = 0 even if they have many sms. The query returns nothing. Why these are? How can I get sms list in galaxy s2 as well?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String smsMsgBody = null;
String smsMsgAddress = null;
String smsMsgDirection = null;
Uri uri = Uri.parse("content://sms");
// Uri uri = Uri.parse("content://sms/inbox");
// Uri uri = Uri.parse("content://sms/conversations/");
Cursor c= getContentResolver().query(uri, null, null,null,null);
// startManagingCursor(c);
if (c.getCount() > 0)
{
String count = Integer.toString(c.getCount());
while (c.moveToNext())
{
smsMsgBody = c.getString(c.getColumnIndex("body"));
smsMsgAddress = c.getString(c.getColumnIndex("address"));
smsMsgDirection = c.getString(c.getColumnIndex("type"));
// Do things using above sms data
}
}
c.close();
}
The content://sms/ is not a supported content provider. It is a hidden method, and may not be available in all devices. In Android 4.4 KitKat devices, you can use the code in this answer to do it:
public List<String> getAllSms() {
List<String> lstSms = new ArrayList<String>();
ContentResolver cr = mActivity.getContentResolver();
Cursor c = cr.query(Telephony.Sms.Inbox.CONTENT_URI, // Official CONTENT_URI from docs
new String[] { Telephony.Sms.Inbox.BODY }, // Select body text
null,
null,
Telephony.Sms.Inbox.DEFAULT_SORT_ORDER // Default sort order);
int totalSMS = c.getCount();
if (c.moveToFirst()) {
for (int i = 0; i < totalSMS; i++) {
lstSms.add(c.getString(0));
c.moveToNext();
}
}
else {
throw new RuntimeException("You have no SMS in Inbox");
}
c.close();
return lstSms;
}
I don't believe that there is a documented method that will work across all devices right now.
I want to get the information about the messages from the inbox on the basis of a particular number.I am using following code for achieving the goal but it is not working in the expected way:
public void SendTheSmsToTheFolder(String NameOfContact,String Number,String FolderAddress,long TimeLimit)
{
m_NameOfContact = NameOfContact;
String SMS_URI_INBOX = "content://sms/inbox";
Uri l_uri = Uri.parse(SMS_URI_INBOX);
Cursor l_SendTheSmsToTheFolderCursor = getContentResolver().query(l_uri, null, "address=?",new String[]{Number.trim()},null);
if (l_SendTheSmsToTheFolderCursor.moveToFirst())
{
int l_index_Address = l_SendTheSmsToTheFolderCursor.getColumnIndex("address");
int l_index_Person = l_SendTheSmsToTheFolderCursor.getColumnIndex("person");
int l_index_Body = l_SendTheSmsToTheFolderCursor.getColumnIndex("body");
int l_index_Date = l_SendTheSmsToTheFolderCursor.getColumnIndex("date");
do
{
String l_strAddress = l_SendTheSmsToTheFolderCursor.getString(l_index_Address);
String l_strbody = l_SendTheSmsToTheFolderCursor.getString(l_index_Body);
long l_longDate = l_SendTheSmsToTheFolderCursor.getLong(l_index_Date);
Log.v("Message: ","Body of the message is "+l_strbody);
} while (l_SendTheSmsToTheFolderCursor.moveToNext());
}
}
I am quite sure that the message having that particular phone number is present in the box and i have cross checked this fact.But the here,i cursor count is always showing 0.I don't know what is the problem.I have searched a lot but am not able to figure it out.Please help me.Thanks in advance.
If you want to search messages from a particular number, you can try this code.
Uri uri = Uri.parse("content://sms/inbox");
ContentResolver contentResolver = context.getContentResolver();
String where = "address="+ phNum; //here you can use that particular number
Cursor cursor = contentResolver.query(uri, new String[] { "_id", "thread_id"}, where, null,null);
It has worked for me. let me know if it solved your issue.