Query, backup, delete, insert Contacts in Android - android

This question should be a starting point to all of us who want to manipulate contacts in Android.
First things first
As I am aware, since API level 5 the Contacts API has changed, so in order to make the application work correct I need to check what android os is on the phone and if prior 5 use one content provider or else use the newer one. The only annoyance in this case is the warnings of deprecated I get. The application is build against Android 2.3.3 but needs to work from 1.5+
1. Querying contacts
This is the easiest part to do. Usually querying means getting data like Contact name, phones, picture, email and displaying it on a listview. For instance here is how I've done it in API prior 5
String[] projectionPeople = new String[] {People._ID, People.NAME,};
String[] projectionPhone = new String[] {Phones.NUMBER};
try {
// Get the base URI for People table in Contacts content provider.
// which is: content://contacts/people/
Uri contactUri = People.CONTENT_URI;
ContentResolver resolver = getContentResolver();
Cursor phonesCursor = null;
Cursor peopleCursor = resolver.query (contactUri,
projectionPeople, //Which columns to return.
"People.NAME is not null", // WHERE clause--we won't specify.
null, // Selection Args??
People.DEFAULT_SORT_ORDER); // Order-by name
if (peopleCursor != null && peopleCursor.getCount() >0)
{
// go to the beginning of the list
peopleCursor.moveToFirst();
do
{
//do something with current contact info
phoneUri= Uri.withAppendedPath(personUri, Contacts.People.Phones.CONTENT_DIRECTORY);
phonesCursor = resolver.query(phoneUri,
projectionPhone,
null,
null,
Phones.DEFAULT_SORT_ORDER);
if (phonesCursor!=null && phonesCursor.getCount()>0)
{
phonesCursor.moveToFirst();
lstPhones = new ArrayList<String>();
do
{
//add phone numbers to a List<String> for instance
} while (phonesCursor.moveToNext());
if (phonesCursor != null && !phonesCursor.isClosed())
phonesCursor.close();
} while (peopleCursor.moveToNext());
if (peopleCursor != null && !peopleCursor.isClosed())
peopleCursor.close();
}
}
catch (Exception ex)
{
}
}
Haven't tried it yet on the new api but the cursor should be like
final String[] projection = new String[] {
RawContacts.CONTACT_ID, // the contact id column
RawContacts.DELETED // column if this contact is deleted
};
final Cursor rawContacts = managedQuery(RawContacts.CONTENT_URI, // the URI for raw contact provider
projection
null, // selection = null, retrieve all entries
null, // selection is without parameters
null); // do not order
Sure, this needs to be elaborated a bit more, but it should provide the basics of simple query against Contacts content provider
2. Backup
My first thought on this was: if I know the Id of a Contact, I create tables in a sqlite database exactly how the cursor columns are and insert all the data into my tables. This is not an easy task as it requires a lot of codding not to mention that different apis have different table structures. What would be the best solution to backup one contact or multiple contacts ?
3. Delete
This should work on all apis using content providers, but data is spread on many packages and uris and I'm not sure from where to delete
4. Insert
After a contact is backed up, I may need to restore/insert it again. As in case of deletion, on which uris do I need to insert ?
Please, let's try to elaborate this issues so in the futures, who needs to use Contacts in Android apps could take this question as a solid starting point. Thank you stackoverflow community.

Here is a good starting point
http://developer.android.com/resources/samples/BusinessCard/index.html

Related

Getting details of edited contact back using ACTION_EDIT and startActivityForResult()

I am maintaining a list of contacts for my application. First I pick contact using ACTION_PICK with an intent. I am saving these contacts in my local database along with CONTACT_ID. Now user may choose to edit any contact to add some extra information that my app needs. I fire that edit intent with ACTION_EDIT. I have two questions here
I am saving CONTACT_ID to my database in order to use in edit intent. First question is does this id changes after edition ? because It so happens that I am unable to open contact editor for same contact again.
Second question is how can I read back all the details of this edited contact ? I am getting this back in my onActivityResult(). I have tried to use same code which i am using in case of picking but data structure returned in case of edit is different it seems.
you can get any data from contacts using a cursor like
String[] projection = new String[] {
ContactsContract.PhoneLookup.DISPLAY_NAME,
ContactsContract.PhoneLookup._ID};
// query time
Cursor cursor = _context.getContentResolver()
.query("ContactsContract.Contacts.CONTENT_URI",
projection, null, null, null);
if(cursor != null) {
while ( cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(
ContactsContract.PhoneLookup.DISPLAY_NAME));
// do other stuff
}
}
cursor.close();
take a look at https://developer.android.com/training/contacts-provider/retrieve-details.html

How to aggregate the rawContacts using aggregationException content correclty

I'm backing up and restoring contacts, I'm able to do it, but while aggregation of rawcontacts for linked contacts(joined contacts) using ContactsContract.AggregationExceptions
If i join 3 contacts, say Contact A (master) and Contact B (linked) and C (linked)
I do the backup ,and restore,for the newly created id's with correct mapping, I'm updating the ContactsContract.AggregationExceptions.CONTENT_URI with following code:
private boolean aggregateContactLinks() {
ContentResolver cr = context.getContentResolver();
int listCount = linkList.size();
ContentValues values = new ContentValues(3);
Log.i(tag, "aggregating contacts");
for (int i=0; i<listCount; i++) {
values.put(AggregationExceptions.RAW_CONTACT_ID1,
linkList.get(i).newId1);
values.put(AggregationExceptions.RAW_CONTACT_ID2,
linkList.get(i).newId2);
values.put(AggregationExceptions.TYPE,
AggregationExceptions.TYPE_KEEP_TOGETHER);
Log.i(tag," new master id(id1) :"+linkList.get(i).newId+"\nlinkid2 :"+newId2);
Log.i(tag,
"result :"
+ cr.update(AggregationExceptions.CONTENT_URI,
values, null, null));
Log.i(tag, "\nupdated one contact");
}
values.clear();
return true;
}
output , on phone i can see the linked content but in display name of contact is c instead of a
before backup
after backup, deleting the contacts and after restore
can anyone know where exactly im going wrong,thanks in advance
If you want to tell Android contact provider that it should use the specific raw contact name for aggregated contact (not display names of linked contacts B and C but the display name of master contact A), you may use RawContactsColumn.NAME_VERIFIED. Simply set it to "1" for your master raw contact after updating aggregation exceptions.
I found this trick in the standard Contacts application's
code:
// Mark the original contact as "name verified" to make sure that the contact
// display name does not change as a result of the join
if (verifiedNameRawContactId != -1) {
Builder builder = ContentProviderOperation.newUpdate(
ContentUris.withAppendedId(RawContacts.CONTENT_URI, verifiedNameRawContactId));
builder.withValue(RawContacts.NAME_VERIFIED, 1);
operations.add(builder.build());
}
RawContactsColumn interface is protected, so you should use "name_verified" as column name. Because of the fact that RawContactsColumn isn't open, maybe you should also check if "name_verified" column exists before updating to avoid crashes.

Is there an accepted/received way of checking to see if a person (phone number) is in the Contact List?

Is there an accepted/received way of checking to see if a person (phone number) is in the Contact List?
I'm hoping there's something I can call like this:
bool bInContactList = InContactList("1415922353");
It is not as simple as you want but you can query a Contacts content provider for the contact associated with a phone number:
Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
Cursor c = getContentResolver().query(lookupUri, new String[] {PhoneLookup._ID}, null, null, null);
if (c.getCount() > 0) {
// there is some contact
} else {
// there is no contacts with phoneNumber
}
The application needs android.permission.READ_CONTACTS permission to access contacts data.
You can check Android Developer site for further references about content providers and android.providers package documentation for the list of available standard providers in Android.
I am afraid you did not provide enough information about the language you are talking about. If you use Java -for example- you have a contains method (common to all collections) so, if you want to know if a certain String is contained in a collection you could do it by invoking this method:
boolean found = someCollection.conmtains("1415922353");

Hook some regular tasks?

I'm wondering if the following is possible:
I've an app (service) that stays in background, and gets triggered whenever the user
Adds/deletes/updates a contact
Installs/uninstalls an app
Adds/deletes/renames a file on the FS
Do you think this is possible guys? (in a proper way of course, if it's possible to do it by hacking and dirty stuff I'd pass)
I tried to look over the internet a bit but didn't find discussions related to this point.
What's your guess ?
Haven't tried any of this myself, but:
http://mylifewithandroid.blogspot.com/2008/03/observing-content.html seems to deal with detecting contact data changes. Basically you need to register a ContentObserver and handle the changes you are notified of.
Check out http://developer.android.com/reference/android/content/Intent.html - from that you can register a BroadcastReceiver to be notified of applications being installed or uninstalled. Look for ACTION_PACKAGE_ADDED and ACTION_PACKAGE_REMOVED
Please refer to How to detect file or folder changes in Android? for how to detect when files are changed in the filesystem. You may be limited to your sandbox with a FileObserver, I'm not sure. Also - a rename doesn't seem to be explicitly notified, but you will probably detect it from a MOVED_FROM followed by MOVED_TO, or possibly a DELETE followed by CREATE
Found in the SDK sample for SDK version 5+:
/**
* Retrieves the contact information.
*/
#Override
public ContactInfo loadContact(ContentResolver contentResolver, Uri contactUri) {
ContactInfo contactInfo = new ContactInfo();
long contactId = -1;
// Load the display name for the specified person
Cursor cursor = contentResolver.query(contactUri,
new String[]{Contacts._ID, Contacts.DISPLAY_NAME}, null, null, null);
try {
if (cursor.moveToFirst()) {
contactId = cursor.getLong(0);
contactInfo.setDisplayName(cursor.getString(1));
}
} finally {
cursor.close();
}
// Load the phone number (if any).
cursor = contentResolver.query(Phone.CONTENT_URI,
new String[]{Phone.NUMBER},
Phone.CONTACT_ID + "=" + contactId, null, Phone.IS_SUPER_PRIMARY + " DESC");
try {
if (cursor.moveToFirst()) {
contactInfo.setPhoneNumber(cursor.getString(0));
}
} finally {
cursor.close();
}
return contactInfo;
}
You can specify the contact columns you want to retreive with Cursor cursor = contentResolver.query(contactUri, new String[]{Contacts._ID, Contacts.DISPLAY_NAME}, null, null, null); The column names are described at http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html and looking at the sample, it seems cursor.getLong(0) here is the contact ID you're looking for. It also seems that it is volatile depending on how the contact is edited and how others are added, but you're catching those too so you should be able to handle those cases.

For Android, is there a way to determine how many text messages have been sent to a contact?

I'm reading contact data from ContractContacts, and can lookup TIMES_CONTACTED (which is useful to me), but this field only applies to calls to that contact. I'm also interested in the number of times a contact has been contacted via SMS or email.
Does anyone know if this information is available? I've been searching but haven't come across anything.
For SMS, you'll want to access the inbox located at content://sms/inbox directly and perform a database query to count the number of rows corresponding to the matching contact.
Something like:
String personAddress = addressFromContact();
Uri smsUri = new Uri("content://sms");
if (smsUri != null) {
Cursor smsCursor = getContentResolver().query(smsUri, null, "address=?", new String[] {personAddress}, null);
int smsCount = smsCursor.getCount();
}

Categories

Resources