15ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee/* 25ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Copyright (C) 2009 The Android Open Source Project 35ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * 45ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Licensed under the Apache License, Version 2.0 (the "License"); 55ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * you may not use this file except in compliance with the License. 65ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * You may obtain a copy of the License at 75ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * 85ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * http://www.apache.org/licenses/LICENSE-2.0 95ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * 105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Unless required by applicable law or agreed to in writing, software 115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * distributed under the License is distributed on an "AS IS" BASIS, 125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * See the License for the specific language governing permissions and 145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * limitations under the License. 155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leepackage com.android.contacts.common.model; 185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.content.ContentProviderOperation; 205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.content.ContentProviderOperation.Builder; 215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.content.ContentValues; 225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.content.Context; 235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.net.Uri; 245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.os.Parcel; 255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.os.Parcelable; 265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.BaseColumns; 275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.Data; 285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.Profile; 295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.RawContacts; 305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.util.Log; 315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.AccountTypeManager; 335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.ValuesDelta; 345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.account.AccountType; 355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.test.NeededForTesting; 365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.google.common.collect.Lists; 375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.google.common.collect.Maps; 385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport java.util.ArrayList; 405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport java.util.HashMap; 415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee/** 435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Contains a {@link RawContact} and records any modifications separately so the 445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * original {@link RawContact} can be swapped out with a newer version and the 455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * changes still cleanly applied. 465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * <p> 475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * One benefit of this approach is that we can build changes entirely on an 485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * empty {@link RawContact}, which then becomes an insert {@link RawContacts} case. 495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * <p> 505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * When applying modifications over an {@link RawContact}, we try finding the 515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * original {@link Data#_ID} rows where the modifications took place. If those 525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * rows are missing from the new {@link RawContact}, we know the original data must 535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * be deleted, but to preserve the user modifications we treat as an insert. 545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leepublic class RawContactDelta implements Parcelable { 565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // TODO: optimize by using contentvalues pool, since we allocate so many of them 575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static final String TAG = "EntityDelta"; 595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static final boolean LOGV = false; 605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Direct values from {@link Entity#getEntityValues()}. 635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private ValuesDelta mValues; 655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * URI used for contacts queries, by default it is set to query raw contacts. 685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * It can be set to query the profile's raw contact(s). 695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private Uri mContactsQueryUri = RawContacts.CONTENT_URI; 715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Internal map of children values from {@link Entity#getSubValues()}, which 745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * we store here sorted into {@link Data#MIMETYPE} bins. 755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private final HashMap<String, ArrayList<ValuesDelta>> mEntries = Maps.newHashMap(); 775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public RawContactDelta() { 795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public RawContactDelta(ValuesDelta values) { 825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee mValues = values; 835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Build an {@link RawContactDelta} using the given {@link RawContact} as a 875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * starting point; the "before" snapshot. 885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static RawContactDelta fromBefore(RawContact before) { 905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final RawContactDelta rawContactDelta = new RawContactDelta(); 915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee rawContactDelta.mValues = ValuesDelta.fromBefore(before.getValues()); 925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee rawContactDelta.mValues.setIdColumn(RawContacts._ID); 935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (final ContentValues values : before.getContentValues()) { 945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee rawContactDelta.addEntry(ValuesDelta.fromBefore(values)); 955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return rawContactDelta; 975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 1005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Merge the "after" values from the given {@link RawContactDelta} onto the 1015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * "before" state represented by this {@link RawContactDelta}, discarding any 1025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * existing "after" states. This is typically used when re-parenting changes 1035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * onto an updated {@link Entity}. 1045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 1055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static RawContactDelta mergeAfter(RawContactDelta local, RawContactDelta remote) { 1065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Bail early if trying to merge delete with missing local 1075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ValuesDelta remoteValues = remote.mValues; 1085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (local == null && (remoteValues.isDelete() || remoteValues.isTransient())) return null; 1095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Create local version if none exists yet 1115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (local == null) local = new RawContactDelta(); 1125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (LOGV) { 1145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Long localVersion = (local.mValues == null) ? null : local.mValues 1155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee .getAsLong(RawContacts.VERSION); 1165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Long remoteVersion = remote.mValues.getAsLong(RawContacts.VERSION); 1175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Log.d(TAG, "Re-parenting from original version " + remoteVersion + " to " 1185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee + localVersion); 1195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Create values if needed, and merge "after" changes 1225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee local.mValues = ValuesDelta.mergeAfter(local.mValues, remote.mValues); 1235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Find matching local entry for each remote values, or create 1255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ArrayList<ValuesDelta> mimeEntries : remote.mEntries.values()) { 1265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta remoteEntry : mimeEntries) { 1275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Long childId = remoteEntry.getId(); 1285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Find or create local match and merge 1305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ValuesDelta localEntry = local.getEntry(childId); 1315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ValuesDelta merged = ValuesDelta.mergeAfter(localEntry, remoteEntry); 1325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (localEntry == null && merged != null) { 1345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // No local entry before, so insert 1355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee local.addEntry(merged); 1365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return local; 1415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public ValuesDelta getValues() { 1445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return mValues; 1455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public boolean isContactInsert() { 1485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return mValues.isInsert(); 1495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 1525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Get the {@link ValuesDelta} child marked as {@link Data#IS_PRIMARY}, 1535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * which may return null when no entry exists. 1545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 1555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public ValuesDelta getPrimaryEntry(String mimeType) { 1565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ArrayList<ValuesDelta> mimeEntries = getMimeEntries(mimeType, false); 1575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (mimeEntries == null) return null; 1585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : mimeEntries) { 1605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (entry.isPrimary()) { 1615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return entry; 1625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // When no direct primary, return something 1665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return mimeEntries.size() > 0 ? mimeEntries.get(0) : null; 1675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 1705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * calls {@link #getSuperPrimaryEntry(String, boolean)} with true 1715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * @see #getSuperPrimaryEntry(String, boolean) 1725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 1735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public ValuesDelta getSuperPrimaryEntry(String mimeType) { 1745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getSuperPrimaryEntry(mimeType, true); 1755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 1785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Returns the super-primary entry for the given mime type 1795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * @param forceSelection if true, will try to return some value even if a super-primary 1805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * doesn't exist (may be a primary, or just a random item 1815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * @return 1825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 1835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee @NeededForTesting 1845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public ValuesDelta getSuperPrimaryEntry(String mimeType, boolean forceSelection) { 1855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ArrayList<ValuesDelta> mimeEntries = getMimeEntries(mimeType, false); 1865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (mimeEntries == null) return null; 1875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ValuesDelta primary = null; 1895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : mimeEntries) { 1905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (entry.isSuperPrimary()) { 1915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return entry; 1925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else if (entry.isPrimary()) { 1935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee primary = entry; 1945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!forceSelection) { 1985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return null; 1995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // When no direct super primary, return something 2025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (primary != null) { 2035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return primary; 2045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return mimeEntries.size() > 0 ? mimeEntries.get(0) : null; 2065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 2095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Return the AccountType that this raw-contact belongs to. 2105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 2115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public AccountType getRawContactAccountType(Context context) { 2125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ContentValues entityValues = getValues().getCompleteValues(); 2135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee String type = entityValues.getAsString(RawContacts.ACCOUNT_TYPE); 2145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee String dataSet = entityValues.getAsString(RawContacts.DATA_SET); 2155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return AccountTypeManager.getInstance(context).getAccountType(type, dataSet); 2165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public Long getRawContactId() { 2195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getValues().getAsLong(RawContacts._ID); 2205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public String getAccountName() { 2235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getValues().getAsString(RawContacts.ACCOUNT_NAME); 2245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public String getAccountType() { 2275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getValues().getAsString(RawContacts.ACCOUNT_TYPE); 2285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public String getDataSet() { 2315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getValues().getAsString(RawContacts.DATA_SET); 2325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public AccountType getAccountType(AccountTypeManager manager) { 2355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return manager.getAccountType(getAccountType(), getDataSet()); 2365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public boolean isVisible() { 2395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getValues().isVisible(); 2405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 2435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Return the list of child {@link ValuesDelta} from our optimized map, 2445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * creating the list if requested. 2455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 2465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private ArrayList<ValuesDelta> getMimeEntries(String mimeType, boolean lazyCreate) { 2475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ArrayList<ValuesDelta> mimeEntries = mEntries.get(mimeType); 2485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (mimeEntries == null && lazyCreate) { 2495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee mimeEntries = Lists.newArrayList(); 2505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee mEntries.put(mimeType, mimeEntries); 2515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return mimeEntries; 2535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public ArrayList<ValuesDelta> getMimeEntries(String mimeType) { 2565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getMimeEntries(mimeType, false); 2575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public int getMimeEntriesCount(String mimeType, boolean onlyVisible) { 2605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ArrayList<ValuesDelta> mimeEntries = getMimeEntries(mimeType); 2615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (mimeEntries == null) return 0; 2625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee int count = 0; 2645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta child : mimeEntries) { 2655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Skip deleted items when requesting only visible 2665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (onlyVisible && !child.isVisible()) continue; 2675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee count++; 2685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return count; 2705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public boolean hasMimeEntries(String mimeType) { 2735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return mEntries.containsKey(mimeType); 2745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public ValuesDelta addEntry(ValuesDelta entry) { 2775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String mimeType = entry.getMimetype(); 2785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee getMimeEntries(mimeType, true).add(entry); 2795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return entry; 2805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public ArrayList<ContentValues> getContentValues() { 2835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ArrayList<ContentValues> values = Lists.newArrayList(); 2845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) { 2855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : mimeEntries) { 2865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!entry.isDelete()) { 2875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.add(entry.getCompleteValues()); 2885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return values; 2925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 2955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Find entry with the given {@link BaseColumns#_ID} value. 2965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 2975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public ValuesDelta getEntry(Long childId) { 2985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (childId == null) { 2995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Requesting an "insert" entry, which has no "before" 3005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return null; 3015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Search all children for requested entry 3045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) { 3055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : mimeEntries) { 3065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (childId.equals(entry.getId())) { 3075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return entry; 3085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return null; 3125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 3155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Return the total number of {@link ValuesDelta} contained. 3165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 3175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public int getEntryCount(boolean onlyVisible) { 3185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee int count = 0; 3195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (String mimeType : mEntries.keySet()) { 3205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee count += getMimeEntriesCount(mimeType, onlyVisible); 3215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return count; 3235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee @Override 3265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public boolean equals(Object object) { 3275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (object instanceof RawContactDelta) { 3285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final RawContactDelta other = (RawContactDelta)object; 3295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Equality failed if parent values different 3315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!other.mValues.equals(mValues)) return false; 3325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) { 3345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta child : mimeEntries) { 3355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Equality failed if any children unmatched 3365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!other.containsEntry(child)) return false; 3375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Passed all tests, so equal 3415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return true; 3425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return false; 3445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private boolean containsEntry(ValuesDelta entry) { 3475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) { 3485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta child : mimeEntries) { 3495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Contained if we find any child that matches 3505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (child.equals(entry)) return true; 3515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return false; 3545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 3575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Mark this entire object deleted, including any {@link ValuesDelta}. 3585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 3595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public void markDeleted() { 3605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee this.mValues.markDeleted(); 3615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) { 3625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta child : mimeEntries) { 3635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee child.markDeleted(); 3645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee @Override 3695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public String toString() { 3705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final StringBuilder builder = new StringBuilder(); 3715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.append("\n("); 3725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.append("Uri="); 3735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.append(mContactsQueryUri); 3745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.append(", Values="); 3755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.append(mValues != null ? mValues.toString() : "null"); 3765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.append(", Entries={"); 3775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) { 3785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta child : mimeEntries) { 3795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.append("\n\t"); 3805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee child.toString(builder); 3815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.append("\n})\n"); 3845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return builder.toString(); 3855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 3885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Consider building the given {@link ContentProviderOperation.Builder} and 3895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * appending it to the given list, which only happens if builder is valid. 3905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 3915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private void possibleAdd(ArrayList<ContentProviderOperation> diff, 3925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ContentProviderOperation.Builder builder) { 3935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (builder != null) { 3945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee diff.add(builder.build()); 3955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 3995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Build a list of {@link ContentProviderOperation} that will assert any 4005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * "before" state hasn't changed. This is maintained separately so that all 4015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * asserts can take place before any updates occur. 4025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 4035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public void buildAssert(ArrayList<ContentProviderOperation> buildInto) { 4045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean isContactInsert = mValues.isInsert(); 4055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!isContactInsert) { 4065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Assert version is consistent while persisting changes 4075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Long beforeId = mValues.getId(); 4085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Long beforeVersion = mValues.getAsLong(RawContacts.VERSION); 4095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (beforeId == null || beforeVersion == null) return; 4105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ContentProviderOperation.Builder builder = ContentProviderOperation 4125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee .newAssertQuery(mContactsQueryUri); 4135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.withSelection(RawContacts._ID + "=" + beforeId, null); 4145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.withValue(RawContacts.VERSION, beforeVersion); 4155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee buildInto.add(builder.build()); 4165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 4205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Build a list of {@link ContentProviderOperation} that will transform the 4215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * current "before" {@link Entity} state into the modified state which this 4225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link RawContactDelta} represents. 4235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 4245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public void buildDiff(ArrayList<ContentProviderOperation> buildInto) { 4255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int firstIndex = buildInto.size(); 4265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean isContactInsert = mValues.isInsert(); 4285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean isContactDelete = mValues.isDelete(); 4295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean isContactUpdate = !isContactInsert && !isContactDelete; 4305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Long beforeId = mValues.getId(); 4325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Builder builder; 4345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (isContactInsert) { 4365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // TODO: for now simply disabling aggregation when a new contact is 4375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // created on the phone. In the future, will show aggregation suggestions 4385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // after saving the contact. 4395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee mValues.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED); 4405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Build possible operation at Contact level 4435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder = mValues.buildDiff(mContactsQueryUri); 4445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee possibleAdd(buildInto, builder); 4455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Build operations for all children 4475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) { 4485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta child : mimeEntries) { 4495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Ignore children if parent was deleted 4505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (isContactDelete) continue; 4515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Use the profile data URI if the contact is the profile. 4535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (mContactsQueryUri.equals(Profile.CONTENT_RAW_CONTACTS_URI)) { 4545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder = child.buildDiff(Uri.withAppendedPath(Profile.CONTENT_URI, 4555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee RawContacts.Data.CONTENT_DIRECTORY)); 4565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 4575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder = child.buildDiff(Data.CONTENT_URI); 4585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (child.isInsert()) { 4615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (isContactInsert) { 4625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Parent is brand new insert, so back-reference _id 4635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.withValueBackReference(Data.RAW_CONTACT_ID, firstIndex); 4645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 4655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Inserting under existing, so fill with known _id 4665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.withValue(Data.RAW_CONTACT_ID, beforeId); 4675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else if (isContactInsert && builder != null) { 4695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Child must be insert when Contact insert 4705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee throw new IllegalArgumentException("When parent insert, child must be also"); 4715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee possibleAdd(buildInto, builder); 4735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean addedOperations = buildInto.size() > firstIndex; 4775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (addedOperations && isContactUpdate) { 4785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Suspend aggregation while persisting updates 4795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder = buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_SUSPENDED); 4805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee buildInto.add(firstIndex, builder.build()); 4815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Restore aggregation mode as last operation 4835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder = buildSetAggregationMode(beforeId, RawContacts.AGGREGATION_MODE_DEFAULT); 4845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee buildInto.add(builder.build()); 4855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else if (isContactInsert) { 4865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Restore aggregation mode as last operation 4875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder = ContentProviderOperation.newUpdate(mContactsQueryUri); 4885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT); 4895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.withSelection(RawContacts._ID + "=?", new String[1]); 4905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.withSelectionBackReference(0, firstIndex); 4915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee buildInto.add(builder.build()); 4925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 4965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Build a {@link ContentProviderOperation} that changes 4975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link RawContacts#AGGREGATION_MODE} to the given value. 4985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 4995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee protected Builder buildSetAggregationMode(Long beforeId, int mode) { 5005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Builder builder = ContentProviderOperation.newUpdate(mContactsQueryUri); 5015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.withValue(RawContacts.AGGREGATION_MODE, mode); 5025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.withSelection(RawContacts._ID + "=" + beforeId, null); 5035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return builder; 5045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** {@inheritDoc} */ 5075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public int describeContents() { 5085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Nothing special about this parcel 5095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return 0; 5105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** {@inheritDoc} */ 5135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public void writeToParcel(Parcel dest, int flags) { 5145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int size = this.getEntryCount(false); 5155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee dest.writeInt(size); 5165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee dest.writeParcelable(mValues, flags); 5175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee dest.writeParcelable(mContactsQueryUri, flags); 5185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ArrayList<ValuesDelta> mimeEntries : mEntries.values()) { 5195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta child : mimeEntries) { 5205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee dest.writeParcelable(child, flags); 5215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public void readFromParcel(Parcel source) { 5265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ClassLoader loader = getClass().getClassLoader(); 5275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int size = source.readInt(); 5285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee mValues = source.<ValuesDelta> readParcelable(loader); 5295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee mContactsQueryUri = source.<Uri> readParcelable(loader); 5305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (int i = 0; i < size; i++) { 5315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ValuesDelta child = source.<ValuesDelta> readParcelable(loader); 5325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee this.addEntry(child); 5335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 5375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Used to set the query URI to the profile URI to store profiles. 5385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 5395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public void setProfileQueryUri() { 5405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee mContactsQueryUri = Profile.CONTENT_RAW_CONTACTS_URI; 5415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static final Parcelable.Creator<RawContactDelta> CREATOR = 5445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee new Parcelable.Creator<RawContactDelta>() { 5455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public RawContactDelta createFromParcel(Parcel in) { 5465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final RawContactDelta state = new RawContactDelta(); 5475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee state.readFromParcel(in); 5485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return state; 5495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public RawContactDelta[] newArray(int size) { 5525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return new RawContactDelta[size]; 5535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee }; 5555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee} 557