Created
September 2, 2015 19:08
-
-
Save Sunno/363e6811ec4b2adbc5df to your computer and use it in GitHub Desktop.
Set a custom contact item in android address book
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This code is based in https://github.com/nemezis/SampleContacts | |
* I'm just explaining it, since I lost a lot of time figuring out how it really works | |
* **/ | |
package com.my_app; | |
import java.util.ArrayList; | |
import java.util.List; | |
import android.content.ContentProvider; | |
import android.content.ContentProviderOperation; | |
import android.content.ContentProviderResult; | |
import android.content.ContentResolver; | |
import android.content.ContentValues; | |
import android.content.Context; | |
import android.content.Entity; | |
import android.database.Cursor; | |
import android.net.Uri; | |
import android.provider.Contacts; | |
import android.provider.ContactsContract; | |
import android.provider.ContactsContract.CommonDataKinds.Email; | |
import android.provider.ContactsContract.CommonDataKinds.Im; | |
import android.provider.ContactsContract.CommonDataKinds.Phone; | |
import android.provider.ContactsContract.CommonDataKinds.StructuredName; | |
import android.provider.ContactsContract.Data; | |
import android.provider.ContactsContract.Groups; | |
import android.provider.ContactsContract.RawContacts; | |
import android.provider.ContactsContract.Settings; | |
import android.webkit.WebChromeClient.CustomViewCallback; | |
public class ContactsManager { | |
// this must be exactly mime type defined in contacts.xml | |
private static String MIMETYPE = "vnd.android.cursor.item/com.my_app.contact_item"; | |
public static void addContact(Context context, MyContact contact) { // My Contact object is a custom object made by you | |
ContentResolver resolver = context.getContentResolver(); | |
resolver.delete(RawContacts.CONTENT_URI, RawContacts.ACCOUNT_TYPE + " = ?", new String[] { AccountGeneral.ACCOUNT_TYPE }); | |
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); | |
/** | |
* this is very important, if you want to add this raw contact to a contact (please refer to android contact provider guide in order to get the difference) | |
* my advise is you to add contact id manually, even though most times android does this automatically. | |
* **/ | |
int contact_id = 1234; | |
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(RawContacts.CONTENT_URI, true)) | |
.withValue(RawContacts.ACCOUNT_NAME, AccountGeneral.ACCOUNT_NAME) | |
.withValue(RawContacts.ACCOUNT_TYPE, AccountGeneral.ACCOUNT_TYPE) | |
.withValue(ContactsContract.RawContacts.CONTACT_ID, contact_id) | |
.build()); | |
// this is for display name | |
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Settings.CONTENT_URI, true)) | |
.withValue(RawContacts.ACCOUNT_NAME, AccountGeneral.ACCOUNT_NAME) | |
.withValue(RawContacts.ACCOUNT_TYPE, AccountGeneral.ACCOUNT_TYPE) | |
.withValue(Settings.UNGROUPED_VISIBLE, 1) | |
.build()); | |
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true)) | |
.withValueBackReference(Data.RAW_CONTACT_ID, 0) | |
.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) | |
.withValue(StructuredName.GIVEN_NAME, contact.name) | |
.withValue(StructuredName.FAMILY_NAME, contact.lastName) | |
.build()); | |
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true)) | |
.withValueBackReference(Data.RAW_CONTACT_ID, 0) | |
.withValue(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) | |
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, "12342145") | |
.build()); | |
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true)) | |
.withValueBackReference(Data.RAW_CONTACT_ID, 0) | |
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) | |
.withValue(ContactsContract.CommonDataKinds.Email.DATA, "[email protected]") | |
.build()); | |
//This is our custom data field in our contact | |
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true)) | |
.withValueBackReference(Data.RAW_CONTACT_ID, 0) | |
.withValue(Data.MIMETYPE, MIMETYPE) | |
.withValue(Data.DATA1, 12345) | |
.withValue(Data.DATA2, "sample") | |
.withValue(Data.DATA3, "sample") | |
.build()); | |
try { | |
ContentProviderResult[] results = resolver.applyBatch(ContactsContract.AUTHORITY, ops); | |
if (results.length == 0) | |
; | |
} | |
catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
private static Uri addCallerIsSyncAdapterParameter(Uri uri, boolean isSyncOperation) { | |
if (isSyncOperation) { | |
return uri.buildUpon() | |
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true") | |
.build(); | |
} | |
return uri; | |
} | |
public static List<MyContact> getMyContacts() { | |
return null; | |
} | |
public static void updateMyContact(Context context, String name) { | |
int id = -1; | |
Cursor cursor = context.getContentResolver().query(Data.CONTENT_URI, new String[] { Data.RAW_CONTACT_ID, Data.DISPLAY_NAME, Data.MIMETYPE, Data.CONTACT_ID }, | |
StructuredName.DISPLAY_NAME + "= ?", | |
new String[] {name}, null); | |
if (cursor != null && cursor.moveToFirst()) { | |
do { | |
id = cursor.getInt(0); | |
Log.i(cursor.getString(0)); | |
Log.i(cursor.getString(1)); | |
Log.i(cursor.getString(2)); | |
Log.i(cursor.getString(3)); | |
} while (cursor.moveToNext()); | |
} | |
if (id != -1) { | |
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); | |
ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI) | |
.withValue(Data.RAW_CONTACT_ID, id) | |
.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE) | |
.withValue(Email.DATA, "sample") | |
.build()); | |
ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI) | |
.withValue(Data.RAW_CONTACT_ID, id) | |
.withValue(Data.MIMETYPE, MIMETYPE) | |
.withValue(Data.DATA1, "profile") | |
.withValue(Data.DATA2, "profile") | |
.withValue(Data.DATA3, "profile") | |
.build()); | |
try { | |
context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); | |
} | |
catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
else { | |
Log.i("id not found"); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="com.my_app" > | |
<uses-permission android:name="android.permission.GET_ACCOUNTS" /> | |
<uses-permission android:name="android.permission.READ_CONTACTS" /> | |
<uses-permission android:name="android.permission.READ_PROFILE" /> | |
<uses-permission android:name="android.permission.WRITE_CONTACTS" /> | |
<!-- for syncing --> | |
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> | |
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" /> | |
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" /> | |
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> | |
<application | |
android:allowBackup="true" | |
android:icon="@drawable/my_icon" | |
android:label="@string/app_name" | |
android:theme="@style/AppTheme" | |
> | |
<service | |
android:name=".SyncService" | |
android:exported="true" > | |
<intent-filter> | |
<action android:name="android.content.SyncAdapter" /> | |
</intent-filter> | |
<meta-data android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter" /> | |
<meta-data android:name="android.provider.CONTACTS_STRUCTURE" android:resource="@xml/contacts" /> | |
</service> | |
<!-- IMPORTANT: this activity is mandatory since it will not show your app icon in contact details if you ommit this | |
Actually omiting this made me lose a lot ot time --> | |
<!-- MimeType must be the same you defined in contacts.xml --> | |
<activity android:name=".ViewDataACtivity" > | |
<intent-filter> | |
<action android:name="android.intent.action.VIEW" /> | |
<category android:name="android.intent.category.DEFAULT" /> | |
<data android:mimeType="vnd.android.cursor.item/com.my_app.contact_item" /> | |
</intent-filter> | |
</activity> | |
</application> | |
</manifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<ContactsSource xmlns:android="http://schemas.android.com/apk/res/android"> | |
<ContactsDataKind | |
android:mimeType="vnd.android.cursor.item/com.my_app.contact_item" | |
android:icon="@drawable/ic_launcher" | |
android:summaryColumn="data2" | |
android:detailColumn="data3"/> | |
</ContactsSource> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<sync-adapter | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
android:accountType="com.my_app" | |
android:contentAuthority="com.android.contacts" <!-- mandatory to set exactly this --> | |
android:userVisible="true" | |
android:supportsUploading="false"/> |
Brilliant!! Absolutely brilliant. Thanks!
Guys, correct me if I am wrong but these custom types are not saved on Google account? They are only local?
Have you verified that the custom data is saved on Google?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks!
2017, This works! Read the comments carefully and save time!