ContactSaveService.java revision 162b7e34fb581d0fa279957af5136d190c40759f
1173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann/* 2173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * Copyright (C) 2010 The Android Open Source Project 3173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * 4173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License"); 5173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * you may not use this file except in compliance with the License. 6173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * You may obtain a copy of the License at 7173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * 8173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * http://www.apache.org/licenses/LICENSE-2.0 9173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * 10173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * Unless required by applicable law or agreed to in writing, software 11173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS, 12173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * See the License for the specific language governing permissions and 14173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann * limitations under the License. 15173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann */ 16173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann 1718ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovpackage com.android.contacts; 18173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann 19a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikovimport com.android.contacts.model.AccountTypeManager; 202b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoroimport com.android.contacts.model.AccountWithDataSet; 21c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoroimport com.android.contacts.model.EntityDelta; 22a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikovimport com.android.contacts.model.EntityDeltaList; 23a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikovimport com.android.contacts.model.EntityModifier; 241ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikovimport com.google.android.collect.Lists; 25caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikovimport com.google.android.collect.Sets; 26caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov 273a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikovimport android.app.Activity; 28173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmannimport android.app.IntentService; 29173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmannimport android.content.ContentProviderOperation; 302b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikovimport android.content.ContentProviderOperation.Builder; 31caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikovimport android.content.ContentProviderResult; 32caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikovimport android.content.ContentResolver; 33e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikovimport android.content.ContentUris; 34caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikovimport android.content.ContentValues; 359d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikovimport android.content.Context; 36173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmannimport android.content.Intent; 372b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikovimport android.content.OperationApplicationException; 382b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikovimport android.database.Cursor; 39caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikovimport android.net.Uri; 40886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikovimport android.os.Handler; 41886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikovimport android.os.Looper; 42a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikovimport android.os.Parcelable; 432b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikovimport android.os.RemoteException; 44173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmannimport android.provider.ContactsContract; 452b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikovimport android.provider.ContactsContract.AggregationExceptions; 461ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.GroupMembership; 479d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikovimport android.provider.ContactsContract.Contacts; 48caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikovimport android.provider.ContactsContract.Data; 49e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikovimport android.provider.ContactsContract.Groups; 50ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelsonimport android.provider.ContactsContract.Profile; 51caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts; 52c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoroimport android.provider.ContactsContract.RawContactsEntity; 53173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmannimport android.util.Log; 542b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikovimport android.widget.Toast; 55173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann 56173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmannimport java.util.ArrayList; 57caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikovimport java.util.HashSet; 58caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikovimport java.util.List; 59a831c0b539cdc120655856074d4621e8e60a843bHugo Hudsonimport java.util.concurrent.CopyOnWriteArrayList; 60173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann 6118ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikov/** 6218ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikov * A service responsible for saving changes to the content provider. 6318ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikov */ 64173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmannpublic class ContactSaveService extends IntentService { 65173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann private static final String TAG = "ContactSaveService"; 66173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann 67a007e442687d3836d6a9f0d0ddcea527fa1481acKatherine Kuan /** Set to true in order to view logs on content provider operations */ 68a007e442687d3836d6a9f0d0ddcea527fa1481acKatherine Kuan private static final boolean DEBUG = false; 69a007e442687d3836d6a9f0d0ddcea527fa1481acKatherine Kuan 70caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov public static final String ACTION_NEW_RAW_CONTACT = "newRawContact"; 71caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov 72caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov public static final String EXTRA_ACCOUNT_NAME = "accountName"; 73caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov public static final String EXTRA_ACCOUNT_TYPE = "accountType"; 742b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro public static final String EXTRA_DATA_SET = "dataSet"; 75caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov public static final String EXTRA_CONTENT_VALUES = "contentValues"; 76caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov public static final String EXTRA_CALLBACK_INTENT = "callbackIntent"; 77caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov 78a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov public static final String ACTION_SAVE_CONTACT = "saveContact"; 79a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov public static final String EXTRA_CONTACT_STATE = "state"; 80a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov public static final String EXTRA_SAVE_MODE = "saveMode"; 81ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson public static final String EXTRA_SAVE_IS_PROFILE = "saveIsProfile"; 82173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann 831ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov public static final String ACTION_CREATE_GROUP = "createGroup"; 84e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov public static final String ACTION_RENAME_GROUP = "renameGroup"; 85e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov public static final String ACTION_DELETE_GROUP = "deleteGroup"; 862d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan public static final String ACTION_UPDATE_GROUP = "updateGroup"; 87e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov public static final String EXTRA_GROUP_ID = "groupId"; 88e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov public static final String EXTRA_GROUP_LABEL = "groupLabel"; 892d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan public static final String EXTRA_RAW_CONTACTS_TO_ADD = "rawContactsToAdd"; 902d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan public static final String EXTRA_RAW_CONTACTS_TO_REMOVE = "rawContactsToRemove"; 91e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov 929d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov public static final String ACTION_SET_STARRED = "setStarred"; 937d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov public static final String ACTION_DELETE_CONTACT = "delete"; 949d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov public static final String EXTRA_CONTACT_URI = "contactUri"; 959d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov public static final String EXTRA_STARRED_FLAG = "starred"; 969d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov 970f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann public static final String ACTION_SET_SUPER_PRIMARY = "setSuperPrimary"; 980f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann public static final String ACTION_CLEAR_PRIMARY = "clearPrimary"; 990f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann public static final String EXTRA_DATA_ID = "dataId"; 1000f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann 1012b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov public static final String ACTION_JOIN_CONTACTS = "joinContacts"; 1022b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov public static final String EXTRA_CONTACT_ID1 = "contactId1"; 1032b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov public static final String EXTRA_CONTACT_ID2 = "contactId2"; 1042b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov public static final String EXTRA_CONTACT_WRITABLE = "contactWritable"; 1052b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 106683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson public static final String ACTION_SET_SEND_TO_VOICEMAIL = "sendToVoicemail"; 107683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson public static final String EXTRA_SEND_TO_VOICEMAIL_FLAG = "sendToVoicemailFlag"; 108683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson 109683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson public static final String ACTION_SET_RINGTONE = "setRingtone"; 110683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson public static final String EXTRA_CUSTOM_RINGTONE = "customRingtone"; 111683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson 112caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov private static final HashSet<String> ALLOWED_DATA_COLUMNS = Sets.newHashSet( 113caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.MIMETYPE, 114caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.IS_PRIMARY, 115caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA1, 116caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA2, 117caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA3, 118caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA4, 119caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA5, 120caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA6, 121caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA7, 122caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA8, 123caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA9, 124caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA10, 125caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA11, 126caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA12, 127caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA13, 128caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA14, 129caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Data.DATA15 130caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov ); 131caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov 132a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov private static final int PERSIST_TRIES = 3; 133a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 1343a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov public interface Listener { 1353a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov public void onServiceCompleted(Intent callbackIntent); 1363a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov } 1373a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov 138a831c0b539cdc120655856074d4621e8e60a843bHugo Hudson private static final CopyOnWriteArrayList<Listener> sListeners = 139a831c0b539cdc120655856074d4621e8e60a843bHugo Hudson new CopyOnWriteArrayList<Listener>(); 1403a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov 1413a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov private Handler mMainHandler; 1423a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov 143173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann public ContactSaveService() { 144173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann super(TAG); 145173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann setIntentRedelivery(true); 1463a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov mMainHandler = new Handler(Looper.getMainLooper()); 1473a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov } 1483a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov 1493a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov public static void registerListener(Listener listener) { 1503a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov if (!(listener instanceof Activity)) { 1513a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov throw new ClassCastException("Only activities can be registered to" 1523a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov + " receive callback from " + ContactSaveService.class.getName()); 1533a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov } 154a831c0b539cdc120655856074d4621e8e60a843bHugo Hudson sListeners.add(0, listener); 1553a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov } 1563a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov 1573a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov public static void unregisterListener(Listener listener) { 158a831c0b539cdc120655856074d4621e8e60a843bHugo Hudson sListeners.remove(listener); 159173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann } 160173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann 161173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann @Override 162a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov public Object getSystemService(String name) { 163a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Object service = super.getSystemService(name); 164a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (service != null) { 165a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov return service; 166a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 167a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 168a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov return getApplicationContext().getSystemService(name); 169a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 170a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 171a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov @Override 172173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann protected void onHandleIntent(Intent intent) { 173caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov String action = intent.getAction(); 174caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov if (ACTION_NEW_RAW_CONTACT.equals(action)) { 175caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov createRawContact(intent); 176a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } else if (ACTION_SAVE_CONTACT.equals(action)) { 177a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov saveContact(intent); 1781ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov } else if (ACTION_CREATE_GROUP.equals(action)) { 1791ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov createGroup(intent); 180e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov } else if (ACTION_RENAME_GROUP.equals(action)) { 181e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov renameGroup(intent); 182e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov } else if (ACTION_DELETE_GROUP.equals(action)) { 183e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov deleteGroup(intent); 1842d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } else if (ACTION_UPDATE_GROUP.equals(action)) { 1852d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan updateGroup(intent); 1869d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov } else if (ACTION_SET_STARRED.equals(action)) { 1879d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov setStarred(intent); 1880f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann } else if (ACTION_SET_SUPER_PRIMARY.equals(action)) { 1890f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann setSuperPrimary(intent); 1900f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann } else if (ACTION_CLEAR_PRIMARY.equals(action)) { 1910f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann clearPrimary(intent); 1927d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov } else if (ACTION_DELETE_CONTACT.equals(action)) { 1937d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov deleteContact(intent); 1942b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } else if (ACTION_JOIN_CONTACTS.equals(action)) { 1952b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov joinContacts(intent); 196683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson } else if (ACTION_SET_SEND_TO_VOICEMAIL.equals(action)) { 197683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson setSendToVoicemail(intent); 198683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson } else if (ACTION_SET_RINGTONE.equals(action)) { 199683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson setRingtone(intent); 200caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov } 201caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov } 202caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov 2039d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov /** 2049d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov * Creates an intent that can be sent to this service to create a new raw contact 2059d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov * using data presented as a set of ContentValues. 2069d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov */ 2079d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov public static Intent createNewRawContactIntent(Context context, 2082b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro ArrayList<ContentValues> values, AccountWithDataSet account, 2092b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro Class<?> callbackActivity, String callbackAction) { 2109d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov Intent serviceIntent = new Intent( 2119d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov context, ContactSaveService.class); 2129d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.setAction(ContactSaveService.ACTION_NEW_RAW_CONTACT); 2139d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov if (account != null) { 2149d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_ACCOUNT_NAME, account.name); 2159d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_ACCOUNT_TYPE, account.type); 2162b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro serviceIntent.putExtra(ContactSaveService.EXTRA_DATA_SET, account.dataSet); 2179d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov } 2189d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.putParcelableArrayListExtra( 2199d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov ContactSaveService.EXTRA_CONTENT_VALUES, values); 2209d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov 2219d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov // Callback intent will be invoked by the service once the new contact is 2229d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov // created. The service will put the URI of the new contact as "data" on 2239d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov // the callback intent. 2249d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov Intent callbackIntent = new Intent(context, callbackActivity); 2259d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov callbackIntent.setAction(callbackAction); 2269d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent); 2279d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov return serviceIntent; 2289d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov } 2299d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov 230caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov private void createRawContact(Intent intent) { 231caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov String accountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME); 232caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov String accountType = intent.getStringExtra(EXTRA_ACCOUNT_TYPE); 2332b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro String dataSet = intent.getStringExtra(EXTRA_DATA_SET); 234caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov List<ContentValues> valueList = intent.getParcelableArrayListExtra(EXTRA_CONTENT_VALUES); 235caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT); 236caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov 237caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(); 238caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov operations.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 239caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov .withValue(RawContacts.ACCOUNT_NAME, accountName) 240caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov .withValue(RawContacts.ACCOUNT_TYPE, accountType) 2412b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro .withValue(RawContacts.DATA_SET, dataSet) 242caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov .build()); 243caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov 244caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov int size = valueList.size(); 245caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov for (int i = 0; i < size; i++) { 246caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov ContentValues values = valueList.get(i); 247caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov values.keySet().retainAll(ALLOWED_DATA_COLUMNS); 248caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov operations.add(ContentProviderOperation.newInsert(Data.CONTENT_URI) 249caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov .withValueBackReference(Data.RAW_CONTACT_ID, 0) 250caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov .withValues(values) 251caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov .build()); 252caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov } 253caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov 254caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov ContentResolver resolver = getContentResolver(); 255caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov ContentProviderResult[] results; 256caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov try { 257caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov results = resolver.applyBatch(ContactsContract.AUTHORITY, operations); 258caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov } catch (Exception e) { 259caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov throw new RuntimeException("Failed to store new contact", e); 260caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov } 261caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov 262caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov Uri rawContactUri = results[0].uri; 263caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov callbackIntent.setData(RawContacts.getContactLookupUri(resolver, rawContactUri)); 264caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov 2653a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov deliverCallback(callbackIntent); 266caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov } 267caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov 268caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov /** 269a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov * Creates an intent that can be sent to this service to create a new raw contact 270a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov * using data presented as a set of ContentValues. 271a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov */ 272a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov public static Intent createSaveContactIntent(Context context, EntityDeltaList state, 273ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson String saveModeExtraKey, int saveMode, boolean isProfile, Class<?> callbackActivity, 274a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov String callbackAction) { 275a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Intent serviceIntent = new Intent( 276a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov context, ContactSaveService.class); 277a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov serviceIntent.setAction(ContactSaveService.ACTION_SAVE_CONTACT); 278a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov serviceIntent.putExtra(EXTRA_CONTACT_STATE, (Parcelable) state); 279ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson serviceIntent.putExtra(EXTRA_SAVE_IS_PROFILE, isProfile); 280a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 281a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov // Callback intent will be invoked by the service once the contact is 282a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov // saved. The service will put the URI of the new contact as "data" on 283a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov // the callback intent. 284a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Intent callbackIntent = new Intent(context, callbackActivity); 285a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov callbackIntent.putExtra(saveModeExtraKey, saveMode); 286a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov callbackIntent.setAction(callbackAction); 287a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent); 288a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov return serviceIntent; 289a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 290a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 291a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov private void saveContact(Intent intent) { 292a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov EntityDeltaList state = intent.getParcelableExtra(EXTRA_CONTACT_STATE); 293a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT); 294ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson boolean isProfile = intent.getBooleanExtra(EXTRA_SAVE_IS_PROFILE, false); 295a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 296a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov // Trim any empty fields, and RawContacts, before persisting 297a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this); 298a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov EntityModifier.trimEmpty(state, accountTypes); 299a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 300a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Uri lookupUri = null; 301a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 302a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov final ContentResolver resolver = getContentResolver(); 303a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 304a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov // Attempt to persist changes 305a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov int tries = 0; 306a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov while (tries++ < PERSIST_TRIES) { 307a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov try { 308a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov // Build operations and try applying 309a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov final ArrayList<ContentProviderOperation> diff = state.buildDiff(); 310a007e442687d3836d6a9f0d0ddcea527fa1481acKatherine Kuan if (DEBUG) { 311a007e442687d3836d6a9f0d0ddcea527fa1481acKatherine Kuan Log.v(TAG, "Content Provider Operations:"); 312a007e442687d3836d6a9f0d0ddcea527fa1481acKatherine Kuan for (ContentProviderOperation operation : diff) { 313a007e442687d3836d6a9f0d0ddcea527fa1481acKatherine Kuan Log.v(TAG, operation.toString()); 314a007e442687d3836d6a9f0d0ddcea527fa1481acKatherine Kuan } 315a007e442687d3836d6a9f0d0ddcea527fa1481acKatherine Kuan } 316a007e442687d3836d6a9f0d0ddcea527fa1481acKatherine Kuan 317a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov ContentProviderResult[] results = null; 318a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (!diff.isEmpty()) { 319a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov results = resolver.applyBatch(ContactsContract.AUTHORITY, diff); 320a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 321a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 322a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov final long rawContactId = getRawContactId(state, diff, results); 323a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (rawContactId == -1) { 324a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov throw new IllegalStateException("Could not determine RawContact ID after save"); 325a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 3267c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro if (isProfile) { 3277c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro // Since the profile supports local raw contacts, which may have been completely 3287c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro // removed if all information was removed, we need to do a special query to 3297c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro // get the lookup URI for the profile contact (if it still exists). 3307c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro Cursor c = resolver.query(Profile.CONTENT_URI, 3317c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro new String[] {Contacts._ID, Contacts.LOOKUP_KEY}, 3327c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro null, null, null); 3337c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro try { 334162b7e34fb581d0fa279957af5136d190c40759fErik if (c.moveToFirst()) { 335162b7e34fb581d0fa279957af5136d190c40759fErik final long contactId = c.getLong(0); 336162b7e34fb581d0fa279957af5136d190c40759fErik final String lookupKey = c.getString(1); 337162b7e34fb581d0fa279957af5136d190c40759fErik lookupUri = Contacts.getLookupUri(contactId, lookupKey); 338162b7e34fb581d0fa279957af5136d190c40759fErik } 3397c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro } finally { 3407c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro c.close(); 3417c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro } 3427c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro } else { 3437c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro final Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, 3447c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro rawContactId); 3457c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro lookupUri = RawContacts.getContactLookupUri(resolver, rawContactUri); 3467c34c0a46434b2669b0fdba2c9e0e4cce5675f94Dave Santoro } 347a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Log.v(TAG, "Saved contact. New URI: " + lookupUri); 348a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov break; 349a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 350a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } catch (RemoteException e) { 351a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov // Something went wrong, bail without success 352a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Log.e(TAG, "Problem persisting user edits", e); 353a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov break; 354a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 355a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } catch (OperationApplicationException e) { 356a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov // Version consistency failed, re-parent change and try again 357a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Log.w(TAG, "Version consistency failed, re-parenting: " + e.toString()); 358a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov final StringBuilder sb = new StringBuilder(RawContacts._ID + " IN("); 359a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov boolean first = true; 360a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov final int count = state.size(); 361a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov for (int i = 0; i < count; i++) { 362a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Long rawContactId = state.getRawContactId(i); 363a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (rawContactId != null && rawContactId != -1) { 364a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (!first) { 365a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov sb.append(','); 366a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 367a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov sb.append(rawContactId); 368a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov first = false; 369a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 370a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 371a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov sb.append(")"); 372a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 373a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (first) { 374a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov throw new IllegalStateException("Version consistency failed for a new contact"); 375a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 376a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 377c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro final EntityDeltaList newState = EntityDeltaList.fromQuery( 378c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro isProfile 379c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro ? RawContactsEntity.PROFILE_CONTENT_URI 380c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro : RawContactsEntity.CONTENT_URI, 381c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro resolver, sb.toString(), null, null); 382a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov state = EntityDeltaList.mergeAfter(newState, state); 383c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro 384c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro // Update the new state to use profile URIs if appropriate. 385c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro if (isProfile) { 386c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro for (EntityDelta delta : state) { 387c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro delta.setProfileQueryUri(); 388c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro } 389c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro } 390a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 391a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 392a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 393a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov callbackIntent.setData(lookupUri); 394a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 3953a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov deliverCallback(callbackIntent); 396a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 397a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 398a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov private long getRawContactId(EntityDeltaList state, 399a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov final ArrayList<ContentProviderOperation> diff, 400a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov final ContentProviderResult[] results) { 401a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov long rawContactId = state.findRawContactId(); 402a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (rawContactId != -1) { 403a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov return rawContactId; 404a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 405a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 406a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov final int diffSize = diff.size(); 407a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov for (int i = 0; i < diffSize; i++) { 408a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov ContentProviderOperation operation = diff.get(i); 409a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (operation.getType() == ContentProviderOperation.TYPE_INSERT 410a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov && operation.getUri().getEncodedPath().contains( 411a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov RawContacts.CONTENT_URI.getEncodedPath())) { 412a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov return ContentUris.parseId(results[i].uri); 413a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 414a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 415a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov return -1; 416a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 417a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 418a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov /** 419717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan * Creates an intent that can be sent to this service to create a new group as 420717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan * well as add new members at the same time. 421717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan * 422717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan * @param context of the application 423717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan * @param account in which the group should be created 424717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan * @param label is the name of the group (cannot be null) 425717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan * @param rawContactsToAdd is an array of raw contact IDs for contacts that 426717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan * should be added to the group 427717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan * @param callbackActivity is the activity to send the callback intent to 428717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan * @param callbackAction is the intent action for the callback intent 429caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov */ 4302b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro public static Intent createNewGroupIntent(Context context, AccountWithDataSet account, 431717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan String label, long[] rawContactsToAdd, Class<?> callbackActivity, 432717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan String callbackAction) { 4339d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov Intent serviceIntent = new Intent(context, ContactSaveService.class); 4349d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.setAction(ContactSaveService.ACTION_CREATE_GROUP); 4359d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_ACCOUNT_TYPE, account.type); 4369d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_ACCOUNT_NAME, account.name); 4372b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro serviceIntent.putExtra(ContactSaveService.EXTRA_DATA_SET, account.dataSet); 4389d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_GROUP_LABEL, label); 439717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan serviceIntent.putExtra(ContactSaveService.EXTRA_RAW_CONTACTS_TO_ADD, rawContactsToAdd); 440caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov 4419d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov // Callback intent will be invoked by the service once the new group is 442717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan // created. 4439d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov Intent callbackIntent = new Intent(context, callbackActivity); 4449d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov callbackIntent.setAction(callbackAction); 4451ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent); 4469d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov 4471ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov return serviceIntent; 4481ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov } 4491ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov 4501ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov private void createGroup(Intent intent) { 4512b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro String accountType = intent.getStringExtra(EXTRA_ACCOUNT_TYPE); 4522b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro String accountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME); 4532b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro String dataSet = intent.getStringExtra(EXTRA_DATA_SET); 4542b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro String label = intent.getStringExtra(EXTRA_GROUP_LABEL); 455717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan final long[] rawContactsToAdd = intent.getLongArrayExtra(EXTRA_RAW_CONTACTS_TO_ADD); 4561ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov 4571ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov ContentValues values = new ContentValues(); 4581ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov values.put(Groups.ACCOUNT_TYPE, accountType); 4591ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov values.put(Groups.ACCOUNT_NAME, accountName); 4602b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro values.put(Groups.DATA_SET, dataSet); 4611ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov values.put(Groups.TITLE, label); 4621ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov 463717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan final ContentResolver resolver = getContentResolver(); 464717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan 465717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan // Create the new group 466717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan final Uri groupUri = resolver.insert(Groups.CONTENT_URI, values); 467717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan 468717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan // If there's no URI, then the insertion failed. Abort early because group members can't be 469717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan // added if the group doesn't exist 4701ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov if (groupUri == null) { 471717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan Log.e(TAG, "Couldn't create group with label " + label); 4721ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov return; 4731ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov } 4741ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov 475717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan // Add new group members 476717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan addMembersToGroup(resolver, rawContactsToAdd, ContentUris.parseId(groupUri)); 477717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan 478717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan // TODO: Move this into the contact editor where it belongs. This needs to be integrated 479717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan // with the way other intent extras that are passed to the {@link ContactEditorActivity}. 4801ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov values.clear(); 4811ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov values.put(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE); 4821ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov values.put(GroupMembership.GROUP_ROW_ID, ContentUris.parseId(groupUri)); 4831ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov 4841ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT); 485c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan callbackIntent.setData(groupUri); 486717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan // TODO: This can be taken out when the above TODO is addressed 4871ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov callbackIntent.putExtra(ContactsContract.Intents.Insert.DATA, Lists.newArrayList(values)); 4883a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov deliverCallback(callbackIntent); 4891ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov } 4901ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov 4911ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov /** 4929d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov * Creates an intent that can be sent to this service to rename a group. 4931ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov */ 494c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public static Intent createGroupRenameIntent(Context context, long groupId, String newLabel, 495c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan Class<?> callbackActivity, String callbackAction) { 4969d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov Intent serviceIntent = new Intent(context, ContactSaveService.class); 4979d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.setAction(ContactSaveService.ACTION_RENAME_GROUP); 4989d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_GROUP_ID, groupId); 4999d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_GROUP_LABEL, newLabel); 500c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 501c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // Callback intent will be invoked by the service once the group is renamed. 502c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan Intent callbackIntent = new Intent(context, callbackActivity); 503c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan callbackIntent.setAction(callbackAction); 504c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent); 505c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 506caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov return serviceIntent; 507caf0bc759c4ef96dde5bb0a5256c1dcb51b6ccc4Dmitri Plotnikov } 508e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov 509e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov private void renameGroup(Intent intent) { 510e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov long groupId = intent.getLongExtra(EXTRA_GROUP_ID, -1); 511e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov String label = intent.getStringExtra(EXTRA_GROUP_LABEL); 512e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov 513e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov if (groupId == -1) { 514e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov Log.e(TAG, "Invalid arguments for renameGroup request"); 515e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov return; 516e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov } 517e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov 518e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov ContentValues values = new ContentValues(); 519e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov values.put(Groups.TITLE, label); 520c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan final Uri groupUri = ContentUris.withAppendedId(Groups.CONTENT_URI, groupId); 521c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan getContentResolver().update(groupUri, values, null, null); 522c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 523c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT); 524c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan callbackIntent.setData(groupUri); 525c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan deliverCallback(callbackIntent); 526e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov } 527e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov 528e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov /** 5299d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov * Creates an intent that can be sent to this service to delete a group. 530e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov */ 5319d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov public static Intent createGroupDeletionIntent(Context context, long groupId) { 5329d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov Intent serviceIntent = new Intent(context, ContactSaveService.class); 5339d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.setAction(ContactSaveService.ACTION_DELETE_GROUP); 534e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_GROUP_ID, groupId); 535e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov return serviceIntent; 536e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov } 537e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov 538e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov private void deleteGroup(Intent intent) { 539e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov long groupId = intent.getLongExtra(EXTRA_GROUP_ID, -1); 540e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov if (groupId == -1) { 541e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov Log.e(TAG, "Invalid arguments for deleteGroup request"); 542e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov return; 543e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov } 544e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov 545e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov getContentResolver().delete( 546e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov ContentUris.withAppendedId(Groups.CONTENT_URI, groupId), null, null); 547e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov } 548e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov 549e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov /** 5502d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * Creates an intent that can be sent to this service to rename a group as 5512d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * well as add and remove members from the group. 5522d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * 5532d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * @param context of the application 5542d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * @param groupId of the group that should be modified 5552d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * @param newLabel is the updated name of the group (can be null if the name 5562d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * should not be updated) 5572d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * @param rawContactsToAdd is an array of raw contact IDs for contacts that 5582d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * should be added to the group 5592d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * @param rawContactsToRemove is an array of raw contact IDs for contacts 5602d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * that should be removed from the group 5612d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * @param callbackActivity is the activity to send the callback intent to 5622d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan * @param callbackAction is the intent action for the callback intent 5632d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan */ 5642d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan public static Intent createGroupUpdateIntent(Context context, long groupId, String newLabel, 5652d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan long[] rawContactsToAdd, long[] rawContactsToRemove, 5662d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan Class<?> callbackActivity, String callbackAction) { 5672d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan Intent serviceIntent = new Intent(context, ContactSaveService.class); 5682d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan serviceIntent.setAction(ContactSaveService.ACTION_UPDATE_GROUP); 5692d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan serviceIntent.putExtra(ContactSaveService.EXTRA_GROUP_ID, groupId); 5702d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan serviceIntent.putExtra(ContactSaveService.EXTRA_GROUP_LABEL, newLabel); 5712d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan serviceIntent.putExtra(ContactSaveService.EXTRA_RAW_CONTACTS_TO_ADD, rawContactsToAdd); 5722d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan serviceIntent.putExtra(ContactSaveService.EXTRA_RAW_CONTACTS_TO_REMOVE, 5732d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan rawContactsToRemove); 5742d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 5752d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // Callback intent will be invoked by the service once the group is updated 5762d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan Intent callbackIntent = new Intent(context, callbackActivity); 5772d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan callbackIntent.setAction(callbackAction); 5782d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent); 5792d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 5802d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan return serviceIntent; 5812d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } 5822d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 5832d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan private void updateGroup(Intent intent) { 5842d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan long groupId = intent.getLongExtra(EXTRA_GROUP_ID, -1); 5852d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan String label = intent.getStringExtra(EXTRA_GROUP_LABEL); 5862d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan long[] rawContactsToAdd = intent.getLongArrayExtra(EXTRA_RAW_CONTACTS_TO_ADD); 5872d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan long[] rawContactsToRemove = intent.getLongArrayExtra(EXTRA_RAW_CONTACTS_TO_REMOVE); 5882d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 5892d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan if (groupId == -1) { 5902d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan Log.e(TAG, "Invalid arguments for updateGroup request"); 5912d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan return; 5922d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } 5932d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 5942d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan final ContentResolver resolver = getContentResolver(); 5952d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan final Uri groupUri = ContentUris.withAppendedId(Groups.CONTENT_URI, groupId); 5962d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 5972d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // Update group name if necessary 5982d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan if (label != null) { 5992d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan ContentValues values = new ContentValues(); 6002d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan values.put(Groups.TITLE, label); 601717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan resolver.update(groupUri, values, null, null); 6022d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } 6032d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 604717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan // Add and remove members if necessary 605717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan addMembersToGroup(resolver, rawContactsToAdd, groupId); 606717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan removeMembersFromGroup(resolver, rawContactsToRemove, groupId); 607717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan 608717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT); 609717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan callbackIntent.setData(groupUri); 610717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan deliverCallback(callbackIntent); 611717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan } 612717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan 613717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan private void addMembersToGroup(ContentResolver resolver, long[] rawContactsToAdd, 614717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan long groupId) { 615717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan if (rawContactsToAdd == null) { 616717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan return; 617717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan } 6182d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan for (long rawContactId : rawContactsToAdd) { 6192d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan try { 6202d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan final ArrayList<ContentProviderOperation> rawContactOperations = 6212d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan new ArrayList<ContentProviderOperation>(); 6222d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 6232d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // Build an assert operation to ensure the contact is not already in the group 6242d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan final ContentProviderOperation.Builder assertBuilder = ContentProviderOperation 6252d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan .newAssertQuery(Data.CONTENT_URI); 6262d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan assertBuilder.withSelection(Data.RAW_CONTACT_ID + "=? AND " + 6272d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan Data.MIMETYPE + "=? AND " + GroupMembership.GROUP_ROW_ID + "=?", 6282d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan new String[] { String.valueOf(rawContactId), 6292d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(groupId)}); 6302d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan assertBuilder.withExpectedCount(0); 6312d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan rawContactOperations.add(assertBuilder.build()); 6322d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 6332d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // Build an insert operation to add the contact to the group 6342d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan final ContentProviderOperation.Builder insertBuilder = ContentProviderOperation 6352d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan .newInsert(Data.CONTENT_URI); 6362d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan insertBuilder.withValue(Data.RAW_CONTACT_ID, rawContactId); 6372d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan insertBuilder.withValue(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE); 6382d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan insertBuilder.withValue(GroupMembership.GROUP_ROW_ID, groupId); 6392d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan rawContactOperations.add(insertBuilder.build()); 6402d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 6412d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan if (DEBUG) { 6422d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan for (ContentProviderOperation operation : rawContactOperations) { 6432d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan Log.v(TAG, operation.toString()); 6442d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } 6452d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } 6462d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 6472d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // Apply batch 6482d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan ContentProviderResult[] results = null; 6492d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan if (!rawContactOperations.isEmpty()) { 6502d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan results = resolver.applyBatch(ContactsContract.AUTHORITY, rawContactOperations); 6512d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } 6522d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } catch (RemoteException e) { 6532d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // Something went wrong, bail without success 6542d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan Log.e(TAG, "Problem persisting user edits for raw contact ID " + 6552d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan String.valueOf(rawContactId), e); 6562d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } catch (OperationApplicationException e) { 6572d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // The assert could have failed because the contact is already in the group, 6582d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // just continue to the next contact 6592d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan Log.w(TAG, "Assert failed in adding raw contact ID " + 6602d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan String.valueOf(rawContactId) + ". Already exists in group " + 6612d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan String.valueOf(groupId), e); 6622d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } 6632d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } 664717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan } 6652d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 666717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan private void removeMembersFromGroup(ContentResolver resolver, long[] rawContactsToRemove, 667717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan long groupId) { 668717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan if (rawContactsToRemove == null) { 669717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan return; 670717e343811088da922cd84fb0d196de85fba7fe9Katherine Kuan } 6712d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan for (long rawContactId : rawContactsToRemove) { 6722d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // Apply the delete operation on the data row for the given raw contact's 6732d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // membership in the given group. If no contact matches the provided selection, then 6742d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // nothing will be done. Just continue to the next contact. 6752d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan getContentResolver().delete(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=? AND " + 6762d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan Data.MIMETYPE + "=? AND " + GroupMembership.GROUP_ROW_ID + "=?", 6772d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan new String[] { String.valueOf(rawContactId), 6782d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(groupId)}); 6792d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } 6802d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } 6812d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 6822d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan /** 6839d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov * Creates an intent that can be sent to this service to star or un-star a contact. 684e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov */ 6859d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov public static Intent createSetStarredIntent(Context context, Uri contactUri, boolean value) { 6869d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov Intent serviceIntent = new Intent(context, ContactSaveService.class); 6879d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.setAction(ContactSaveService.ACTION_SET_STARRED); 6889d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_CONTACT_URI, contactUri); 6899d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_STARRED_FLAG, value); 6909d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov 691e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov return serviceIntent; 692e898a9fa52728b2ff6fcd3add693471e9e15553dDmitri Plotnikov } 6939d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov 6949d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov private void setStarred(Intent intent) { 6959d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov Uri contactUri = intent.getParcelableExtra(EXTRA_CONTACT_URI); 6969d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov boolean value = intent.getBooleanExtra(EXTRA_STARRED_FLAG, false); 6979d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov if (contactUri == null) { 6989d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov Log.e(TAG, "Invalid arguments for setStarred request"); 6999d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov return; 7009d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov } 7019d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov 7029d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov final ContentValues values = new ContentValues(1); 7039d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov values.put(Contacts.STARRED, value); 7049d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov getContentResolver().update(contactUri, values, null, null); 7059d730dd9d9efe125c9102b298f897577157ffecdDmitri Plotnikov } 7060f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann 7070f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann /** 708683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson * Creates an intent that can be sent to this service to set the redirect to voicemail. 709683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson */ 710683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson public static Intent createSetSendToVoicemail(Context context, Uri contactUri, 711683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson boolean value) { 712683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson Intent serviceIntent = new Intent(context, ContactSaveService.class); 713683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson serviceIntent.setAction(ContactSaveService.ACTION_SET_SEND_TO_VOICEMAIL); 714683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson serviceIntent.putExtra(ContactSaveService.EXTRA_CONTACT_URI, contactUri); 715683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson serviceIntent.putExtra(ContactSaveService.EXTRA_SEND_TO_VOICEMAIL_FLAG, value); 716683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson 717683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson return serviceIntent; 718683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson } 719683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson 720683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson private void setSendToVoicemail(Intent intent) { 721683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson Uri contactUri = intent.getParcelableExtra(EXTRA_CONTACT_URI); 722683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson boolean value = intent.getBooleanExtra(EXTRA_SEND_TO_VOICEMAIL_FLAG, false); 723683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson if (contactUri == null) { 724683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson Log.e(TAG, "Invalid arguments for setRedirectToVoicemail"); 725683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson return; 726683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson } 727683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson 728683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson final ContentValues values = new ContentValues(1); 729683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson values.put(Contacts.SEND_TO_VOICEMAIL, value); 730683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson getContentResolver().update(contactUri, values, null, null); 731683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson } 732683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson 733683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson /** 734683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson * Creates an intent that can be sent to this service to save the contact's ringtone. 735683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson */ 736683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson public static Intent createSetRingtone(Context context, Uri contactUri, 737683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson String value) { 738683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson Intent serviceIntent = new Intent(context, ContactSaveService.class); 739683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson serviceIntent.setAction(ContactSaveService.ACTION_SET_RINGTONE); 740683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson serviceIntent.putExtra(ContactSaveService.EXTRA_CONTACT_URI, contactUri); 741683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson serviceIntent.putExtra(ContactSaveService.EXTRA_CUSTOM_RINGTONE, value); 742683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson 743683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson return serviceIntent; 744683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson } 745683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson 746683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson private void setRingtone(Intent intent) { 747683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson Uri contactUri = intent.getParcelableExtra(EXTRA_CONTACT_URI); 748683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson String value = intent.getStringExtra(EXTRA_CUSTOM_RINGTONE); 749683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson if (contactUri == null) { 750683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson Log.e(TAG, "Invalid arguments for setRingtone"); 751683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson return; 752683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson } 753683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson ContentValues values = new ContentValues(1); 754683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson values.put(Contacts.CUSTOM_RINGTONE, value); 755683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson getContentResolver().update(contactUri, values, null, null); 756683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson } 757683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson 758683b57e1fbf27c81c9973de814fc8bb1852e6df8Isaac Katzenelson /** 7590f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann * Creates an intent that sets the selected data item as super primary (default) 7600f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann */ 7610f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann public static Intent createSetSuperPrimaryIntent(Context context, long dataId) { 7620f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann Intent serviceIntent = new Intent(context, ContactSaveService.class); 7630f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann serviceIntent.setAction(ContactSaveService.ACTION_SET_SUPER_PRIMARY); 7640f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann serviceIntent.putExtra(ContactSaveService.EXTRA_DATA_ID, dataId); 7650f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann return serviceIntent; 7660f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann } 7670f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann 7680f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann private void setSuperPrimary(Intent intent) { 7690f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann long dataId = intent.getLongExtra(EXTRA_DATA_ID, -1); 7700f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann if (dataId == -1) { 7710f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann Log.e(TAG, "Invalid arguments for setSuperPrimary request"); 7720f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann return; 7730f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann } 7740f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann 7750f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann // Update the primary values in the data record. 7760f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann ContentValues values = new ContentValues(1); 7770f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann values.put(Data.IS_SUPER_PRIMARY, 1); 7780f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann values.put(Data.IS_PRIMARY, 1); 7790f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann 7800f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann getContentResolver().update(ContentUris.withAppendedId(Data.CONTENT_URI, dataId), 7810f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann values, null, null); 7820f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann } 7830f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann 7840f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann /** 7850f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann * Creates an intent that clears the primary flag of all data items that belong to the same 7860f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann * raw_contact as the given data item. Will only clear, if the data item was primary before 7870f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann * this call 7880f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann */ 7890f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann public static Intent createClearPrimaryIntent(Context context, long dataId) { 7900f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann Intent serviceIntent = new Intent(context, ContactSaveService.class); 7910f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann serviceIntent.setAction(ContactSaveService.ACTION_CLEAR_PRIMARY); 7920f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann serviceIntent.putExtra(ContactSaveService.EXTRA_DATA_ID, dataId); 7930f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann return serviceIntent; 7940f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann } 7950f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann 7960f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann private void clearPrimary(Intent intent) { 7970f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann long dataId = intent.getLongExtra(EXTRA_DATA_ID, -1); 7980f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann if (dataId == -1) { 7990f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann Log.e(TAG, "Invalid arguments for clearPrimary request"); 8000f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann return; 8010f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann } 8020f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann 8030f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann // Update the primary values in the data record. 8040f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann ContentValues values = new ContentValues(1); 8050f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann values.put(Data.IS_SUPER_PRIMARY, 0); 8060f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann values.put(Data.IS_PRIMARY, 0); 8070f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann 8080f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann getContentResolver().update(ContentUris.withAppendedId(Data.CONTENT_URI, dataId), 8090f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann values, null, null); 8100f78e8b198c56963d6d6044839bb0679f4afd075Daniel Lehmann } 8117d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov 8127d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov /** 8137d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov * Creates an intent that can be sent to this service to delete a contact. 8147d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov */ 8157d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov public static Intent createDeleteContactIntent(Context context, Uri contactUri) { 8167d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov Intent serviceIntent = new Intent(context, ContactSaveService.class); 8177d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov serviceIntent.setAction(ContactSaveService.ACTION_DELETE_CONTACT); 8187d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_CONTACT_URI, contactUri); 8197d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov return serviceIntent; 8207d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov } 8217d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov 8227d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov private void deleteContact(Intent intent) { 8237d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov Uri contactUri = intent.getParcelableExtra(EXTRA_CONTACT_URI); 8247d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov if (contactUri == null) { 8257d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov Log.e(TAG, "Invalid arguments for deleteContact request"); 8267d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov return; 8277d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov } 8287d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov 8297d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov getContentResolver().delete(contactUri, null, null); 8307d8cabb65b02096583b928c64ae455d1f79e5633Dmitri Plotnikov } 8312b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 8322b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov /** 8332b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov * Creates an intent that can be sent to this service to join two contacts. 8342b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov */ 8352b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov public static Intent createJoinContactsIntent(Context context, long contactId1, 8362b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov long contactId2, boolean contactWritable, 8372b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov Class<?> callbackActivity, String callbackAction) { 8382b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov Intent serviceIntent = new Intent(context, ContactSaveService.class); 8392b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov serviceIntent.setAction(ContactSaveService.ACTION_JOIN_CONTACTS); 8402b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_CONTACT_ID1, contactId1); 8412b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_CONTACT_ID2, contactId2); 8422b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_CONTACT_WRITABLE, contactWritable); 8432b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 8442b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov // Callback intent will be invoked by the service once the contacts are joined. 8452b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov Intent callbackIntent = new Intent(context, callbackActivity); 8462b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov callbackIntent.setAction(callbackAction); 8472b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent); 8482b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 8492b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov return serviceIntent; 8502b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 8512b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 8522b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 8532b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov private interface JoinContactQuery { 8542b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov String[] PROJECTION = { 8552b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov RawContacts._ID, 8562b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov RawContacts.CONTACT_ID, 8572b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov RawContacts.NAME_VERIFIED, 8582b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov RawContacts.DISPLAY_NAME_SOURCE, 8592b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov }; 8602b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 8612b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov String SELECTION = RawContacts.CONTACT_ID + "=? OR " + RawContacts.CONTACT_ID + "=?"; 8622b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 8632b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov int _ID = 0; 8642b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov int CONTACT_ID = 1; 8652b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov int NAME_VERIFIED = 2; 8662b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov int DISPLAY_NAME_SOURCE = 3; 8672b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 8682b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 8692b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov private void joinContacts(Intent intent) { 8702b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov long contactId1 = intent.getLongExtra(EXTRA_CONTACT_ID1, -1); 8712b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov long contactId2 = intent.getLongExtra(EXTRA_CONTACT_ID2, -1); 8722b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov boolean writable = intent.getBooleanExtra(EXTRA_CONTACT_WRITABLE, false); 8732b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov if (contactId1 == -1 || contactId2 == -1) { 8742b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov Log.e(TAG, "Invalid arguments for joinContacts request"); 8752b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov return; 8762b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 8772b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 8782b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov final ContentResolver resolver = getContentResolver(); 8792b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 8802b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov // Load raw contact IDs for all raw contacts involved - currently edited and selected 8812b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov // in the join UIs 8822b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov Cursor c = resolver.query(RawContacts.CONTENT_URI, 8832b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov JoinContactQuery.PROJECTION, 8842b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov JoinContactQuery.SELECTION, 8852b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov new String[]{String.valueOf(contactId1), String.valueOf(contactId2)}, null); 8862b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 8872b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov long rawContactIds[]; 8882b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov long verifiedNameRawContactId = -1; 8892b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov try { 8902b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov int maxDisplayNameSource = -1; 8912b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov rawContactIds = new long[c.getCount()]; 8922b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov for (int i = 0; i < rawContactIds.length; i++) { 8932b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov c.moveToPosition(i); 8942b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov long rawContactId = c.getLong(JoinContactQuery._ID); 8952b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov rawContactIds[i] = rawContactId; 8962b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov int nameSource = c.getInt(JoinContactQuery.DISPLAY_NAME_SOURCE); 8972b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov if (nameSource > maxDisplayNameSource) { 8982b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov maxDisplayNameSource = nameSource; 8992b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9002b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9012b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 9022b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov // Find an appropriate display name for the joined contact: 9032b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov // if should have a higher DisplayNameSource or be the name 9042b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov // of the original contact that we are joining with another. 9052b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov if (writable) { 9062b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov for (int i = 0; i < rawContactIds.length; i++) { 9072b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov c.moveToPosition(i); 9082b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov if (c.getLong(JoinContactQuery.CONTACT_ID) == contactId1) { 9092b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov int nameSource = c.getInt(JoinContactQuery.DISPLAY_NAME_SOURCE); 9102b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov if (nameSource == maxDisplayNameSource 9112b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov && (verifiedNameRawContactId == -1 9122b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov || c.getInt(JoinContactQuery.NAME_VERIFIED) != 0)) { 9132b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov verifiedNameRawContactId = c.getLong(JoinContactQuery._ID); 9142b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9152b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9162b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9172b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9182b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } finally { 9192b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov c.close(); 9202b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9212b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 9222b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov // For each pair of raw contacts, insert an aggregation exception 9232b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(); 9242b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov for (int i = 0; i < rawContactIds.length; i++) { 9252b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov for (int j = 0; j < rawContactIds.length; j++) { 9262b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov if (i != j) { 9272b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov buildJoinContactDiff(operations, rawContactIds[i], rawContactIds[j]); 9282b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9292b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9302b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9312b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 9322b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov // Mark the original contact as "name verified" to make sure that the contact 9332b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov // display name does not change as a result of the join 9342b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov if (verifiedNameRawContactId != -1) { 9352b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov Builder builder = ContentProviderOperation.newUpdate( 9362b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov ContentUris.withAppendedId(RawContacts.CONTENT_URI, verifiedNameRawContactId)); 9372b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov builder.withValue(RawContacts.NAME_VERIFIED, 1); 9382b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov operations.add(builder.build()); 9392b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9402b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 9412b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov boolean success = false; 9422b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov // Apply all aggregation exceptions as one batch 9432b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov try { 9442b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov resolver.applyBatch(ContactsContract.AUTHORITY, operations); 945886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov showToast(R.string.contactsJoinedMessage); 9462b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov success = true; 9472b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } catch (RemoteException e) { 9482b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov Log.e(TAG, "Failed to apply aggregation exception batch", e); 949886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov showToast(R.string.contactSavedErrorToast); 9502b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } catch (OperationApplicationException e) { 9512b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov Log.e(TAG, "Failed to apply aggregation exception batch", e); 952886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov showToast(R.string.contactSavedErrorToast); 9532b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9542b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 9552b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov Intent callbackIntent = intent.getParcelableExtra(EXTRA_CALLBACK_INTENT); 9562b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov if (success) { 9572b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov Uri uri = RawContacts.getContactLookupUri(resolver, 9582b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactIds[0])); 9592b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov callbackIntent.setData(uri); 9602b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9613a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov deliverCallback(callbackIntent); 9622b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9632b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 9642b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov /** 9652b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov * Construct a {@link AggregationExceptions#TYPE_KEEP_TOGETHER} ContentProviderOperation. 9662b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov */ 9672b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov private void buildJoinContactDiff(ArrayList<ContentProviderOperation> operations, 9682b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov long rawContactId1, long rawContactId2) { 9692b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov Builder builder = 9702b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI); 9712b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER); 9722b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1); 9732b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2); 9742b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov operations.add(builder.build()); 9752b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 976886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov 977886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov /** 978886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov * Shows a toast on the UI thread. 979886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov */ 980886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov private void showToast(final int message) { 9813a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov mMainHandler.post(new Runnable() { 982886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov 983886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov @Override 984886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov public void run() { 985886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov Toast.makeText(ContactSaveService.this, message, Toast.LENGTH_LONG).show(); 986886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov } 987886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov }); 988886d3d6de4a6f7202b1871f5af9944e8650413dfDmitri Plotnikov } 9893a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov 9903a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov private void deliverCallback(final Intent callbackIntent) { 9913a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov mMainHandler.post(new Runnable() { 9923a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov 9933a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov @Override 9943a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov public void run() { 9953a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov deliverCallbackOnUiThread(callbackIntent); 9963a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov } 9973a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov }); 9983a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov } 9993a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov 10003a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov void deliverCallbackOnUiThread(final Intent callbackIntent) { 10013a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov // TODO: this assumes that if there are multiple instances of the same 10023a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov // activity registered, the last one registered is the one waiting for 10033a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov // the callback. Validity of this assumption needs to be verified. 1004a831c0b539cdc120655856074d4621e8e60a843bHugo Hudson for (Listener listener : sListeners) { 1005a831c0b539cdc120655856074d4621e8e60a843bHugo Hudson if (callbackIntent.getComponent().equals( 1006a831c0b539cdc120655856074d4621e8e60a843bHugo Hudson ((Activity) listener).getIntent().getComponent())) { 1007a831c0b539cdc120655856074d4621e8e60a843bHugo Hudson listener.onServiceCompleted(callbackIntent); 1008a831c0b539cdc120655856074d4621e8e60a843bHugo Hudson return; 10093a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov } 10103a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov } 10113a6a905a39e6cbb3b2dc99835cdf28c84437691aDmitri Plotnikov } 1012173ffe1300afa6a88a7f0a924adade121e564274Daniel Lehmann} 1013