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.ContentValues; 205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.content.Context; 215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.database.Cursor; 225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.net.Uri; 235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.os.Bundle; 245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract; 255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.BaseTypes; 265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Email; 275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Event; 285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.GroupMembership; 295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Im; 305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Nickname; 315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Note; 325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Organization; 335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Phone; 345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Photo; 355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Relation; 365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.SipAddress; 375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Website; 405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.Data; 415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.Intents; 425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.Intents.Insert; 435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.provider.ContactsContract.RawContacts; 445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.text.TextUtils; 455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.util.Log; 465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.util.SparseArray; 475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport android.util.SparseIntArray; 485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.ContactsUtils; 505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.AccountTypeManager; 515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.ValuesDelta; 525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.util.CommonDateUtils; 535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.util.DateUtils; 545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.util.NameConverter; 555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.account.AccountType; 565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.account.AccountType.EditField; 575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.account.AccountType.EditType; 585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.account.AccountType.EventEditType; 595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.account.GoogleAccountType; 605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.dataitem.DataKind; 615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.dataitem.PhoneDataItem; 625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport com.android.contacts.common.model.dataitem.StructuredNameDataItem; 635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport java.text.ParsePosition; 655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport java.util.ArrayList; 665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport java.util.Arrays; 675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport java.util.Calendar; 685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport java.util.Date; 695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport java.util.HashSet; 705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport java.util.Iterator; 715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport java.util.List; 725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport java.util.Locale; 735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leeimport java.util.Set; 745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee/** 765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Helper methods for modifying an {@link RawContactDelta}, such as inserting 775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * new rows, or enforcing {@link AccountType}. 785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Leepublic class RawContactModifier { 805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static final String TAG = RawContactModifier.class.getSimpleName(); 815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** Set to true in order to view logs on entity operations */ 835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static final boolean DEBUG = false; 845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * For the given {@link RawContactDelta}, determine if the given 875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link DataKind} could be inserted under specific 885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link AccountType}. 895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static boolean canInsert(RawContactDelta state, DataKind kind) { 915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Insert possible when have valid types and under overall maximum 925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int visibleCount = state.getMimeEntriesCount(kind.mimeType, true); 935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean validTypes = hasValidTypes(state, kind); 945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean validOverall = (kind.typeOverallMax == -1) 955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee || (visibleCount < kind.typeOverallMax); 965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return (validTypes && validOverall); 975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static boolean hasValidTypes(RawContactDelta state, DataKind kind) { 1005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (RawContactModifier.hasEditTypes(kind)) { 1015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return (getValidTypes(state, kind).size() > 0); 1025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 1035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return true; 1045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 1085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Ensure that at least one of the given {@link DataKind} exists in the 1095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * given {@link RawContactDelta} state, and try creating one if none exist. 1105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * @return The child (either newly created or the first existing one), or null if the 1115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * account doesn't support this {@link DataKind}. 1125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 1135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static ValuesDelta ensureKindExists( 1145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee RawContactDelta state, AccountType accountType, String mimeType) { 1155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final DataKind kind = accountType.getKindForMimetype(mimeType); 1165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean hasChild = state.getMimeEntriesCount(mimeType, true) > 0; 1175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind != null) { 1195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (hasChild) { 1205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Return the first entry. 1215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return state.getMimeEntries(mimeType).get(0); 1225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 1235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Create child when none exists and valid kind 1245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ValuesDelta child = insertChild(state, kind); 1255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind.mimeType.equals(Photo.CONTENT_ITEM_TYPE)) { 1265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee child.setFromTemplate(true); 1275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return child; 1295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return null; 1325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 1355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * For the given {@link RawContactDelta} and {@link DataKind}, return the 1365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * list possible {@link EditType} options available based on 1375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link AccountType}. 1385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 1395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind) { 1405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getValidTypes(state, kind, null, true, null); 1415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 1445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * For the given {@link RawContactDelta} and {@link DataKind}, return the 1455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * list possible {@link EditType} options available based on 1465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link AccountType}. 1475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * 1485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * @param forceInclude Always include this {@link EditType} in the returned 1495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * list, even when an otherwise-invalid choice. This is useful 1505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * when showing a dialog that includes the current type. 1515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 1525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind, 1535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee EditType forceInclude) { 1545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getValidTypes(state, kind, forceInclude, true, null); 1555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 1585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * For the given {@link RawContactDelta} and {@link DataKind}, return the 1595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * list possible {@link EditType} options available based on 1605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link AccountType}. 1615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * 1625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * @param forceInclude Always include this {@link EditType} in the returned 1635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * list, even when an otherwise-invalid choice. This is useful 1645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * when showing a dialog that includes the current type. 1655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * @param includeSecondary If true, include any valid types marked as 1665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link EditType#secondary}. 1675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * @param typeCount When provided, will be used for the frequency count of 1685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * each {@link EditType}, otherwise built using 1695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link #getTypeFrequencies(RawContactDelta, DataKind)}. 1705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 1715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind, 1725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee EditType forceInclude, boolean includeSecondary, SparseIntArray typeCount) { 1735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ArrayList<EditType> validTypes = new ArrayList<EditType>(); 1745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Bail early if no types provided 1765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!hasEditTypes(kind)) return validTypes; 1775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (typeCount == null) { 1795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Build frequency counts if not provided 1805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee typeCount = getTypeFrequencies(state, kind); 1815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Build list of valid types 1845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int overallCount = typeCount.get(FREQUENCY_TOTAL); 1855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (EditType type : kind.typeList) { 1865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean validOverall = (kind.typeOverallMax == -1 ? true 1875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee : overallCount < kind.typeOverallMax); 1885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean validSpecific = (type.specificMax == -1 ? true : typeCount 1895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee .get(type.rawValue) < type.specificMax); 1905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean validSecondary = (includeSecondary ? true : !type.secondary); 1915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean forcedInclude = type.equals(forceInclude); 1925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (forcedInclude || (validOverall && validSpecific && validSecondary)) { 1935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Type is valid when no limit, under limit, or forced include 1945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee validTypes.add(type); 1955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 1975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 1985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return validTypes; 1995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static final int FREQUENCY_TOTAL = Integer.MIN_VALUE; 2025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 2045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Count up the frequency that each {@link EditType} appears in the given 2055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link RawContactDelta}. The returned {@link SparseIntArray} maps from 2065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link EditType#rawValue} to counts, with the total overall count stored 2075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * as {@link #FREQUENCY_TOTAL}. 2085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 2095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static SparseIntArray getTypeFrequencies(RawContactDelta state, DataKind kind) { 2105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final SparseIntArray typeCount = new SparseIntArray(); 2115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Find all entries for this kind, bailing early if none found 2135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final List<ValuesDelta> mimeEntries = state.getMimeEntries(kind.mimeType); 2145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (mimeEntries == null) return typeCount; 2155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee int totalCount = 0; 2175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : mimeEntries) { 2185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Only count visible entries 2195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!entry.isVisible()) continue; 2205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee totalCount++; 2215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final EditType type = getCurrentType(entry, kind); 2235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (type != null) { 2245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int count = typeCount.get(type.rawValue); 2255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee typeCount.put(type.rawValue, count + 1); 2265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee typeCount.put(FREQUENCY_TOTAL, totalCount); 2295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return typeCount; 2305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 2335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Check if the given {@link DataKind} has multiple types that should be 2345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * displayed for users to pick. 2355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 2365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static boolean hasEditTypes(DataKind kind) { 2375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return kind.typeList != null && kind.typeList.size() > 0; 2385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 2415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Find the {@link EditType} that describes the given 2425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link ValuesDelta} row, assuming the given {@link DataKind} dictates 2435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * the possible types. 2445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 2455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static EditType getCurrentType(ValuesDelta entry, DataKind kind) { 2465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Long rawValue = entry.getAsLong(kind.typeColumn); 2475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (rawValue == null) return null; 2485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getType(kind, rawValue.intValue()); 2495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 2525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Find the {@link EditType} that describes the given {@link ContentValues} row, 2535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * assuming the given {@link DataKind} dictates the possible types. 2545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 2555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static EditType getCurrentType(ContentValues entry, DataKind kind) { 2565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind.typeColumn == null) return null; 2575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Integer rawValue = entry.getAsInteger(kind.typeColumn); 2585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (rawValue == null) return null; 2595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getType(kind, rawValue); 2605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 2635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Find the {@link EditType} that describes the given {@link Cursor} row, 2645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * assuming the given {@link DataKind} dictates the possible types. 2655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 2665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static EditType getCurrentType(Cursor cursor, DataKind kind) { 2675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind.typeColumn == null) return null; 2685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int index = cursor.getColumnIndex(kind.typeColumn); 2695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (index == -1) return null; 2705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int rawValue = cursor.getInt(index); 2715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getType(kind, rawValue); 2725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 2755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Find the {@link EditType} with the given {@link EditType#rawValue}. 2765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 2775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static EditType getType(DataKind kind, int rawValue) { 2785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (EditType type : kind.typeList) { 2795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (type.rawValue == rawValue) { 2805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return type; 2815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return null; 2845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 2865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 2875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Return the precedence for the the given {@link EditType#rawValue}, where 2885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * lower numbers are higher precedence. 2895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 2905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static int getTypePrecedence(DataKind kind, int rawValue) { 2915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (int i = 0; i < kind.typeList.size(); i++) { 2925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final EditType type = kind.typeList.get(i); 2935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (type.rawValue == rawValue) { 2945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return i; 2955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return Integer.MAX_VALUE; 2985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 2995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 3015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Find the best {@link EditType} for a potential insert. The "best" is the 3025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * first primary type that doesn't already exist. When all valid types 3035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * exist, we pick the last valid option. 3045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 3055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static EditType getBestValidType(RawContactDelta state, DataKind kind, 3065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean includeSecondary, int exactValue) { 3075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Shortcut when no types 30829a094106357ea806dc029437af77ec91b94cafbJay Shrauner if (kind == null || kind.typeColumn == null) return null; 3095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Find type counts and valid primary types, bail if none 3115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final SparseIntArray typeCount = getTypeFrequencies(state, kind); 3125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ArrayList<EditType> validTypes = getValidTypes(state, kind, null, includeSecondary, 3135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee typeCount); 3145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (validTypes.size() == 0) return null; 3155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Keep track of the last valid type 3175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final EditType lastType = validTypes.get(validTypes.size() - 1); 3185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Remove any types that already exist 3205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Iterator<EditType> iterator = validTypes.iterator(); 3215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee while (iterator.hasNext()) { 3225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final EditType type = iterator.next(); 3235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int count = typeCount.get(type.rawValue); 3245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (exactValue == type.rawValue) { 3265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Found exact value match 3275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return type; 3285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (count > 0) { 3315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Type already appears, so don't consider 3325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee iterator.remove(); 3335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Use the best remaining, otherwise the last valid 3375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (validTypes.size() > 0) { 3385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return validTypes.get(0); 3395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 3405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return lastType; 3415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 3455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Insert a new child of kind {@link DataKind} into the given 3465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link RawContactDelta}. Tries using the best {@link EditType} found using 3475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link #getBestValidType(RawContactDelta, DataKind, boolean, int)}. 3485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 3495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static ValuesDelta insertChild(RawContactDelta state, DataKind kind) { 35029a094106357ea806dc029437af77ec91b94cafbJay Shrauner // Bail early if invalid kind 35129a094106357ea806dc029437af77ec91b94cafbJay Shrauner if (kind == null) return null; 3525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // First try finding a valid primary 3535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee EditType bestType = getBestValidType(state, kind, false, Integer.MIN_VALUE); 3545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (bestType == null) { 3555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // No valid primary found, so expand search to secondary 3565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee bestType = getBestValidType(state, kind, true, Integer.MIN_VALUE); 3575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return insertChild(state, kind, bestType); 3595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 3625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Insert a new child of kind {@link DataKind} into the given 3635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link RawContactDelta}, marked with the given {@link EditType}. 3645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 3655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static ValuesDelta insertChild(RawContactDelta state, DataKind kind, EditType type) { 3665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Bail early if invalid kind 3675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind == null) return null; 3685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ContentValues after = new ContentValues(); 3695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Our parent CONTACT_ID is provided later 3715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee after.put(Data.MIMETYPE, kind.mimeType); 3725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Fill-in with any requested default values 3745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind.defaultValues != null) { 3755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee after.putAll(kind.defaultValues); 3765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind.typeColumn != null && type != null) { 3795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Set type, if provided 3805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee after.put(kind.typeColumn, type.rawValue); 3815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ValuesDelta child = ValuesDelta.fromAfter(after); 3845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee state.addEntry(child); 3855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return child; 3865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 3875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 3885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 3895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Processing to trim any empty {@link ValuesDelta} and {@link RawContactDelta} 3905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * from the given {@link RawContactDeltaList}, assuming the given {@link AccountTypeManager} 3915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * dictates the structure for various fields. This method ignores rows not 3925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * described by the {@link AccountType}. 3935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 3945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static void trimEmpty(RawContactDeltaList set, AccountTypeManager accountTypes) { 3955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (RawContactDelta state : set) { 3965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ValuesDelta values = state.getValues(); 3975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 3985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String dataSet = values.getAsString(RawContacts.DATA_SET); 3995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final AccountType type = accountTypes.getAccountType(accountType, dataSet); 4005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee trimEmpty(state, type); 4015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static boolean hasChanges(RawContactDeltaList set, AccountTypeManager accountTypes) { 4055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (set.isMarkedForSplitting() || set.isMarkedForJoining()) { 4065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return true; 4075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (RawContactDelta state : set) { 4105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ValuesDelta values = state.getValues(); 4115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 4125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String dataSet = values.getAsString(RawContacts.DATA_SET); 4135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final AccountType type = accountTypes.getAccountType(accountType, dataSet); 4145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (hasChanges(state, type)) { 4155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return true; 4165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return false; 4195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 4225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Processing to trim any empty {@link ValuesDelta} rows from the given 4235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link RawContactDelta}, assuming the given {@link AccountType} dictates 4245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * the structure for various fields. This method ignores rows not described 4255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * by the {@link AccountType}. 4265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 4275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static void trimEmpty(RawContactDelta state, AccountType accountType) { 4285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean hasValues = false; 4295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Walk through entries for each well-known kind 4315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (DataKind kind : accountType.getSortedDataKinds()) { 4325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String mimeType = kind.mimeType; 4335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ArrayList<ValuesDelta> entries = state.getMimeEntries(mimeType); 4345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (entries == null) continue; 4355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : entries) { 4375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Skip any values that haven't been touched 4385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean touched = entry.isInsert() || entry.isUpdate(); 4395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!touched) { 4405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee hasValues = true; 4415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee continue; 4425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Test and remove this row if empty and it isn't a photo from google 4455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean isGoogleAccount = TextUtils.equals(GoogleAccountType.ACCOUNT_TYPE, 4465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee state.getValues().getAsString(RawContacts.ACCOUNT_TYPE)); 4475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean isPhoto = TextUtils.equals(Photo.CONTENT_ITEM_TYPE, kind.mimeType); 4485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean isGooglePhoto = isPhoto && isGoogleAccount; 4495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (RawContactModifier.isEmpty(entry, kind) && !isGooglePhoto) { 4515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (DEBUG) { 4525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Log.v(TAG, "Trimming: " + entry.toString()); 4535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee entry.markDeleted(); 4555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else if (!entry.isFromTemplate()) { 4565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee hasValues = true; 4575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!hasValues) { 4615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Trim overall entity if no children exist 4625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee state.markDeleted(); 4635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static boolean hasChanges(RawContactDelta state, AccountType accountType) { 4675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (DataKind kind : accountType.getSortedDataKinds()) { 4685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String mimeType = kind.mimeType; 4695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ArrayList<ValuesDelta> entries = state.getMimeEntries(mimeType); 4705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (entries == null) continue; 4715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : entries) { 4735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // An empty Insert must be ignored, because it won't save anything (an example 4745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // is an empty name that stays empty) 4755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean isRealInsert = entry.isInsert() && !isEmpty(entry, kind); 4765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (isRealInsert || entry.isUpdate() || entry.isDelete()) { 4775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return true; 4785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return false; 4825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 4855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Test if the given {@link ValuesDelta} would be considered "empty" in 4865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * terms of {@link DataKind#fieldList}. 4875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 4885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static boolean isEmpty(ValuesDelta values, DataKind kind) { 4895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (Photo.CONTENT_ITEM_TYPE.equals(kind.mimeType)) { 4905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return values.isInsert() && values.getAsByteArray(Photo.PHOTO) == null; 4915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 4925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // No defined fields mean this row is always empty 4945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind.fieldList == null) return true; 4955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 4965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (EditField field : kind.fieldList) { 4975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // If any field has values, we're not empty 4985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String value = values.getAsString(field.column); 4995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (ContactsUtils.isGraphic(value)) { 5005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return false; 5015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return true; 5055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 5085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Compares corresponding fields in values1 and values2. Only the fields 5095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * declared by the DataKind are taken into consideration. 5105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 5115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee protected static boolean areEqual(ValuesDelta values1, ContentValues values2, DataKind kind) { 5125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind.fieldList == null) return false; 5135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (EditField field : kind.fieldList) { 5155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String value1 = values1.getAsString(field.column); 5165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String value2 = values2.getAsString(field.column); 5175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!TextUtils.equals(value1, value2)) { 5185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return false; 5195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return true; 5235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 5265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Parse the given {@link Bundle} into the given {@link RawContactDelta} state, 5275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * assuming the extras defined through {@link Intents}. 5285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 5295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static void parseExtras(Context context, AccountType accountType, RawContactDelta state, 5305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Bundle extras) { 5315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (extras == null || extras.size() == 0) { 5325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Bail early if no useful data 5335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return; 5345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee parseStructuredNameExtra(context, accountType, state, extras); 5375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee parseStructuredPostalExtra(accountType, state, extras); 5385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee { 5405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Phone 5415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final DataKind kind = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE); 5425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee parseExtras(state, kind, extras, Insert.PHONE_TYPE, Insert.PHONE, Phone.NUMBER); 5435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee parseExtras(state, kind, extras, Insert.SECONDARY_PHONE_TYPE, Insert.SECONDARY_PHONE, 5445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Phone.NUMBER); 5455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee parseExtras(state, kind, extras, Insert.TERTIARY_PHONE_TYPE, Insert.TERTIARY_PHONE, 5465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Phone.NUMBER); 5475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee { 5505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Email 5515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final DataKind kind = accountType.getKindForMimetype(Email.CONTENT_ITEM_TYPE); 5525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee parseExtras(state, kind, extras, Insert.EMAIL_TYPE, Insert.EMAIL, Email.DATA); 5535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee parseExtras(state, kind, extras, Insert.SECONDARY_EMAIL_TYPE, Insert.SECONDARY_EMAIL, 5545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Email.DATA); 5555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee parseExtras(state, kind, extras, Insert.TERTIARY_EMAIL_TYPE, Insert.TERTIARY_EMAIL, 5565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Email.DATA); 5575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee { 5605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Im 5615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final DataKind kind = accountType.getKindForMimetype(Im.CONTENT_ITEM_TYPE); 5625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee fixupLegacyImType(extras); 5635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee parseExtras(state, kind, extras, Insert.IM_PROTOCOL, Insert.IM_HANDLE, Im.DATA); 5645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Organization 5675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean hasOrg = extras.containsKey(Insert.COMPANY) 5685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee || extras.containsKey(Insert.JOB_TITLE); 5695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final DataKind kindOrg = accountType.getKindForMimetype(Organization.CONTENT_ITEM_TYPE); 5705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (hasOrg && RawContactModifier.canInsert(state, kindOrg)) { 5715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ValuesDelta child = RawContactModifier.insertChild(state, kindOrg); 5725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String company = extras.getString(Insert.COMPANY); 5745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (ContactsUtils.isGraphic(company)) { 5755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee child.put(Organization.COMPANY, company); 5765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String title = extras.getString(Insert.JOB_TITLE); 5795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (ContactsUtils.isGraphic(title)) { 5805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee child.put(Organization.TITLE, title); 5815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Notes 5855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean hasNotes = extras.containsKey(Insert.NOTES); 5865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final DataKind kindNotes = accountType.getKindForMimetype(Note.CONTENT_ITEM_TYPE); 5875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (hasNotes && RawContactModifier.canInsert(state, kindNotes)) { 5885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ValuesDelta child = RawContactModifier.insertChild(state, kindNotes); 5895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String notes = extras.getString(Insert.NOTES); 5915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (ContactsUtils.isGraphic(notes)) { 5925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee child.put(Note.NOTE, notes); 5935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 5955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 5965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Arbitrary additional data 5975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ArrayList<ContentValues> values = extras.getParcelableArrayList(Insert.DATA); 5985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (values != null) { 5995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee parseValues(state, accountType, values); 6005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 6035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static void parseStructuredNameExtra( 6045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Context context, AccountType accountType, RawContactDelta state, Bundle extras) { 6055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // StructuredName 6065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee RawContactModifier.ensureKindExists(state, accountType, StructuredName.CONTENT_ITEM_TYPE); 6075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ValuesDelta child = state.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE); 6085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 6095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String name = extras.getString(Insert.NAME); 6105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (ContactsUtils.isGraphic(name)) { 6115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final DataKind kind = accountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE); 6125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean supportsDisplayName = false; 6135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind.fieldList != null) { 6145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (EditField field : kind.fieldList) { 6155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (StructuredName.DISPLAY_NAME.equals(field.column)) { 6165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee supportsDisplayName = true; 6175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee break; 6185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 6225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (supportsDisplayName) { 6235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee child.put(StructuredName.DISPLAY_NAME, name); 6245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 6255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Uri uri = ContactsContract.AUTHORITY_URI.buildUpon() 6265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee .appendPath("complete_name") 6275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee .appendQueryParameter(StructuredName.DISPLAY_NAME, name) 6285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee .build(); 6295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Cursor cursor = context.getContentResolver().query(uri, 6305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee new String[]{ 6315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee StructuredName.PREFIX, 6325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee StructuredName.GIVEN_NAME, 6335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee StructuredName.MIDDLE_NAME, 6345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee StructuredName.FAMILY_NAME, 6355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee StructuredName.SUFFIX, 6365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee }, null, null, null); 6375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 63823fe38b225346526e3f425570f3648dd7d893a5dJay Shrauner if (cursor != null) { 63923fe38b225346526e3f425570f3648dd7d893a5dJay Shrauner try { 64023fe38b225346526e3f425570f3648dd7d893a5dJay Shrauner if (cursor.moveToFirst()) { 64123fe38b225346526e3f425570f3648dd7d893a5dJay Shrauner child.put(StructuredName.PREFIX, cursor.getString(0)); 64223fe38b225346526e3f425570f3648dd7d893a5dJay Shrauner child.put(StructuredName.GIVEN_NAME, cursor.getString(1)); 64323fe38b225346526e3f425570f3648dd7d893a5dJay Shrauner child.put(StructuredName.MIDDLE_NAME, cursor.getString(2)); 64423fe38b225346526e3f425570f3648dd7d893a5dJay Shrauner child.put(StructuredName.FAMILY_NAME, cursor.getString(3)); 64523fe38b225346526e3f425570f3648dd7d893a5dJay Shrauner child.put(StructuredName.SUFFIX, cursor.getString(4)); 64623fe38b225346526e3f425570f3648dd7d893a5dJay Shrauner } 64723fe38b225346526e3f425570f3648dd7d893a5dJay Shrauner } finally { 64823fe38b225346526e3f425570f3648dd7d893a5dJay Shrauner cursor.close(); 6495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 6545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String phoneticName = extras.getString(Insert.PHONETIC_NAME); 6555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (ContactsUtils.isGraphic(phoneticName)) { 6565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee child.put(StructuredName.PHONETIC_GIVEN_NAME, phoneticName); 6575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 6605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static void parseStructuredPostalExtra( 6615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee AccountType accountType, RawContactDelta state, Bundle extras) { 6625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // StructuredPostal 6635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final DataKind kind = accountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE); 6645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ValuesDelta child = parseExtras(state, kind, extras, Insert.POSTAL_TYPE, 6655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Insert.POSTAL, StructuredPostal.FORMATTED_ADDRESS); 6665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee String address = child == null ? null 6675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee : child.getAsString(StructuredPostal.FORMATTED_ADDRESS); 6685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!TextUtils.isEmpty(address)) { 6695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean supportsFormatted = false; 6705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind.fieldList != null) { 6715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (EditField field : kind.fieldList) { 6725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (StructuredPostal.FORMATTED_ADDRESS.equals(field.column)) { 6735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee supportsFormatted = true; 6745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee break; 6755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 6795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!supportsFormatted) { 6805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee child.put(StructuredPostal.STREET, address); 6815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee child.putNull(StructuredPostal.FORMATTED_ADDRESS); 6825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 6865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static void parseValues( 6875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee RawContactDelta state, AccountType accountType, 6885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ArrayList<ContentValues> dataValueList) { 6895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ContentValues values : dataValueList) { 6905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee String mimeType = values.getAsString(Data.MIMETYPE); 6915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (TextUtils.isEmpty(mimeType)) { 6925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Log.e(TAG, "Mimetype is required. Ignoring: " + values); 6935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee continue; 6945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 6955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 6965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Won't override the contact name 6975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) { 6985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee continue; 6995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) { 7005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(PhoneDataItem.KEY_FORMATTED_PHONE_NUMBER); 7015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Integer type = values.getAsInteger(Phone.TYPE); 7025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // If the provided phone number provides a custom phone type but not a label, 7035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // replace it with mobile (by default) to avoid the "Enter custom label" from 7045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // popping up immediately upon entering the ContactEditorFragment 7055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (type != null && type == Phone.TYPE_CUSTOM && 7065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee TextUtils.isEmpty(values.getAsString(Phone.LABEL))) { 7075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.put(Phone.TYPE, Phone.TYPE_MOBILE); 7085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 7115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee DataKind kind = accountType.getKindForMimetype(mimeType); 7125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind == null) { 7135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Log.e(TAG, "Mimetype not supported for account type " 7145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee + accountType.getAccountTypeAndDataSet() + ". Ignoring: " + values); 7155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee continue; 7165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 7185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ValuesDelta entry = ValuesDelta.fromAfter(values); 7195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (isEmpty(entry, kind)) { 7205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee continue; 7215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 7235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ArrayList<ValuesDelta> entries = state.getMimeEntries(mimeType); 7245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 7255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if ((kind.typeOverallMax != 1) || GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) { 7265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Check for duplicates 7275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean addEntry = true; 7285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee int count = 0; 7295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (entries != null && entries.size() > 0) { 7305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta delta : entries) { 7315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!delta.isDelete()) { 7325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (areEqual(delta, values, kind)) { 7335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee addEntry = false; 7345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee break; 7355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee count++; 7375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 7415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind.typeOverallMax != -1 && count >= kind.typeOverallMax) { 7425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Log.e(TAG, "Mimetype allows at most " + kind.typeOverallMax 7435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee + " entries. Ignoring: " + values); 7445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee addEntry = false; 7455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 7475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (addEntry) { 7485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee addEntry = adjustType(entry, entries, kind); 7495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 7515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (addEntry) { 7525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee state.addEntry(entry); 7535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 7555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Non-list entries should not be overridden 7565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean addEntry = true; 7575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (entries != null && entries.size() > 0) { 7585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta delta : entries) { 7595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!delta.isDelete() && !isEmpty(delta, kind)) { 7605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee addEntry = false; 7615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee break; 7625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (addEntry) { 7655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta delta : entries) { 7665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee delta.markDeleted(); 7675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 7715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (addEntry) { 7725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee addEntry = adjustType(entry, entries, kind); 7735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 7755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (addEntry) { 7765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee state.addEntry(entry); 7775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else if (Note.CONTENT_ITEM_TYPE.equals(mimeType)){ 7785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Note is most likely to contain large amounts of text 7795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // that we don't want to drop on the ground. 7805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta delta : entries) { 7815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!isEmpty(delta, kind)) { 7825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee delta.put(Note.NOTE, delta.getAsString(Note.NOTE) + "\n" 7835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee + values.getAsString(Note.NOTE)); 7845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee break; 7855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 7885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Log.e(TAG, "Will not override mimetype " + mimeType + ". Ignoring: " 7895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee + values); 7905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 7945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 7955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 7965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Checks if the data kind allows addition of another entry (e.g. Exchange only 7975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * supports two "work" phone numbers). If not, tries to switch to one of the 7985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * unused types. If successful, returns true. 7995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 8005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static boolean adjustType( 8015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ValuesDelta entry, ArrayList<ValuesDelta> entries, DataKind kind) { 8025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind.typeColumn == null || kind.typeList == null || kind.typeList.size() == 0) { 8035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return true; 8045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 8065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Integer typeInteger = entry.getAsInteger(kind.typeColumn); 8075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee int type = typeInteger != null ? typeInteger : kind.typeList.get(0).rawValue; 8085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 8095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (isTypeAllowed(type, entries, kind)) { 8105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee entry.put(kind.typeColumn, type); 8115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return true; 8125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 8145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Specified type is not allowed - choose the first available type that is allowed 8155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee int size = kind.typeList.size(); 8165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (int i = 0; i < size; i++) { 8175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee EditType editType = kind.typeList.get(i); 8185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (isTypeAllowed(editType.rawValue, entries, kind)) { 8195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee entry.put(kind.typeColumn, editType.rawValue); 8205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return true; 8215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 8245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return false; 8255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 8275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 8285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Checks if a new entry of the specified type can be added to the raw 8295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * contact. For example, Exchange only supports two "work" phone numbers, so 8305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * addition of a third would not be allowed. 8315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 8325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static boolean isTypeAllowed(int type, ArrayList<ValuesDelta> entries, DataKind kind) { 8335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee int max = 0; 8345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee int size = kind.typeList.size(); 8355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (int i = 0; i < size; i++) { 8365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee EditType editType = kind.typeList.get(i); 8375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (editType.rawValue == type) { 8385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee max = editType.specificMax; 8395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee break; 8405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 8435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (max == 0) { 8445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // This type is not allowed at all 8455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return false; 8465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 8485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (max == -1) { 8495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Unlimited instances of this type are allowed 8505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return true; 8515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 8535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return getEntryCountByType(entries, kind.typeColumn, type) < max; 8545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 8565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 8575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Counts occurrences of the specified type in the supplied entry list. 8585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * 8595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * @return The count of occurrences of the type in the entry list. 0 if entries is 8605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@literal null} 8615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 8625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static int getEntryCountByType(ArrayList<ValuesDelta> entries, String typeColumn, 8635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee int type) { 8645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee int count = 0; 8655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (entries != null) { 8665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : entries) { 8675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Integer typeInteger = entry.getAsInteger(typeColumn); 8685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (typeInteger != null && typeInteger == type) { 8695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee count++; 8705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return count; 8745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 8765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 8775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Attempt to parse legacy {@link Insert#IM_PROTOCOL} values, replacing them 8785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * with updated values. 8795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 8805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee @SuppressWarnings("deprecation") 8815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static void fixupLegacyImType(Bundle bundle) { 8825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String encodedString = bundle.getString(Insert.IM_PROTOCOL); 8835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (encodedString == null) return; 8845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 8855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee try { 8865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Object protocol = android.provider.Contacts.ContactMethods 8875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee .decodeImProtocol(encodedString); 8885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (protocol instanceof Integer) { 8895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee bundle.putInt(Insert.IM_PROTOCOL, (Integer)protocol); 8905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 8915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee bundle.putString(Insert.IM_PROTOCOL, (String)protocol); 8925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } catch (IllegalArgumentException e) { 8945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Ignore exception when legacy parser fails 8955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 8975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 8985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 8995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Parse a specific entry from the given {@link Bundle} and insert into the 9005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * given {@link RawContactDelta}. Silently skips the insert when missing value 9015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * or no valid {@link EditType} found. 9025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * 9035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * @param typeExtra {@link Bundle} key that holds the incoming 9045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * {@link EditType#rawValue} value. 9055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * @param valueExtra {@link Bundle} key that holds the incoming value. 9065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * @param valueColumn Column to write value into {@link ValuesDelta}. 9075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 9085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static ValuesDelta parseExtras(RawContactDelta state, DataKind kind, Bundle extras, 9095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee String typeExtra, String valueExtra, String valueColumn) { 9105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final CharSequence value = extras.getCharSequence(valueExtra); 9115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 9125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Bail early if account type doesn't handle this MIME type 9135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (kind == null) return null; 9145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 9155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Bail when can't insert type, or value missing 9165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean canInsert = RawContactModifier.canInsert(state, kind); 9175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean validValue = (value != null && TextUtils.isGraphic(value)); 9185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!validValue || !canInsert) return null; 9195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 9205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Find exact type when requested, otherwise best available type 9215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean hasType = extras.containsKey(typeExtra); 9225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int typeValue = extras.getInt(typeExtra, hasType ? BaseTypes.TYPE_CUSTOM 9235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee : Integer.MIN_VALUE); 9245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final EditType editType = RawContactModifier.getBestValidType(state, kind, true, typeValue); 9255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 9265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Create data row and fill with value 9275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ValuesDelta child = RawContactModifier.insertChild(state, kind, editType); 9285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee child.put(valueColumn, value.toString()); 9295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 9305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (editType != null && editType.customColumn != null) { 9315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Write down label when custom type picked 9325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String customType = extras.getString(typeExtra); 9335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee child.put(editType.customColumn, customType); 9345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 9355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 9365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return child; 9375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 9385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 9395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 9405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Generic mime types with type support (e.g. TYPE_HOME). 9415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Here, "type support" means if the data kind has CommonColumns#TYPE or not. Data kinds which 9425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * have their own migrate methods aren't listed here. 9435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 9445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static final Set<String> sGenericMimeTypesWithTypeSupport = new HashSet<String>( 9455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Arrays.asList(Phone.CONTENT_ITEM_TYPE, 9465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Email.CONTENT_ITEM_TYPE, 9475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Im.CONTENT_ITEM_TYPE, 9485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Nickname.CONTENT_ITEM_TYPE, 9495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Website.CONTENT_ITEM_TYPE, 9505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Relation.CONTENT_ITEM_TYPE, 9515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee SipAddress.CONTENT_ITEM_TYPE)); 9525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static final Set<String> sGenericMimeTypesWithoutTypeSupport = new HashSet<String>( 9535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Arrays.asList(Organization.CONTENT_ITEM_TYPE, 9545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Note.CONTENT_ITEM_TYPE, 9555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Photo.CONTENT_ITEM_TYPE, 9565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee GroupMembership.CONTENT_ITEM_TYPE)); 9575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // CommonColumns.TYPE cannot be accessed as it is protected interface, so use 9585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Phone.TYPE instead. 9595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static final String COLUMN_FOR_TYPE = Phone.TYPE; 9605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static final String COLUMN_FOR_LABEL = Phone.LABEL; 9615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static final int TYPE_CUSTOM = Phone.TYPE_CUSTOM; 9625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 9635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 9645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Migrates old RawContactDelta to newly created one with a new restriction supplied from 9655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * newAccountType. 9665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * 9675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * This is only for account switch during account creation (which must be insert operation). 9685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 9695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static void migrateStateForNewContact(Context context, 9705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee RawContactDelta oldState, RawContactDelta newState, 9715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee AccountType oldAccountType, AccountType newAccountType) { 9725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (newAccountType == oldAccountType) { 9735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Just copying all data in oldState isn't enough, but we can still rely on a lot of 9745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // shortcuts. 9755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (DataKind kind : newAccountType.getSortedDataKinds()) { 9765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String mimeType = kind.mimeType; 9775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // The fields with short/long form capability must be treated properly. 9785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) { 9795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee migrateStructuredName(context, oldState, newState, kind); 9805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 9815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee List<ValuesDelta> entryList = oldState.getMimeEntries(mimeType); 9825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (entryList != null && !entryList.isEmpty()) { 9835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : entryList) { 9845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ContentValues values = entry.getAfter(); 9855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (values != null) { 9865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee newState.addEntry(ValuesDelta.fromAfter(values)); 9875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 9885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 9895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 9905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 9915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 9925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 9935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Migrate data supported by the new account type. 9945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // All the other data inside oldState are silently dropped. 9955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (DataKind kind : newAccountType.getSortedDataKinds()) { 9965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!kind.editable) continue; 9975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String mimeType = kind.mimeType; 9985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(mimeType) 9995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee || DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) { 10005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Ignore pseudo data. 10015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee continue; 10025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) { 10035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee migrateStructuredName(context, oldState, newState, kind); 10045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) { 10055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee migratePostal(oldState, newState, kind); 10065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else if (Event.CONTENT_ITEM_TYPE.equals(mimeType)) { 10075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee migrateEvent(oldState, newState, kind, null /* default Year */); 10085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else if (sGenericMimeTypesWithoutTypeSupport.contains(mimeType)) { 10095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee migrateGenericWithoutTypeColumn(oldState, newState, kind); 10105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else if (sGenericMimeTypesWithTypeSupport.contains(mimeType)) { 10115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee migrateGenericWithTypeColumn(oldState, newState, kind); 10125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 10135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee throw new IllegalStateException("Unexpected editable mime-type: " + mimeType); 10145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 10195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** 10205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * Checks {@link DataKind#isList} and {@link DataKind#typeOverallMax}, and restricts 10215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee * the number of entries (ValuesDelta) inside newState. 10225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee */ 10235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee private static ArrayList<ValuesDelta> ensureEntryMaxSize(RawContactDelta newState, 10245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee DataKind kind, ArrayList<ValuesDelta> mimeEntries) { 10255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (mimeEntries == null) { 10265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return null; 10275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 10295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int typeOverallMax = kind.typeOverallMax; 10305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (typeOverallMax >= 0 && (mimeEntries.size() > typeOverallMax)) { 10315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ArrayList<ValuesDelta> newMimeEntries = new ArrayList<ValuesDelta>(typeOverallMax); 10325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (int i = 0; i < typeOverallMax; i++) { 10335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee newMimeEntries.add(mimeEntries.get(i)); 10345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee mimeEntries = newMimeEntries; 10365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return mimeEntries; 10385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 10405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** @hide Public only for testing. */ 10415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static void migrateStructuredName( 10425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Context context, RawContactDelta oldState, RawContactDelta newState, 10435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee DataKind newDataKind) { 10445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ContentValues values = 10455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee oldState.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE).getAfter(); 10465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (values == null) { 10475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return; 10485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 10505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean supportDisplayName = false; 10515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean supportPhoneticFullName = false; 10525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean supportPhoneticFamilyName = false; 10535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean supportPhoneticMiddleName = false; 10545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean supportPhoneticGivenName = false; 10555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (EditField editField : newDataKind.fieldList) { 10565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (StructuredName.DISPLAY_NAME.equals(editField.column)) { 10575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee supportDisplayName = true; 10585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (DataKind.PSEUDO_COLUMN_PHONETIC_NAME.equals(editField.column)) { 10605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee supportPhoneticFullName = true; 10615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (StructuredName.PHONETIC_FAMILY_NAME.equals(editField.column)) { 10635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee supportPhoneticFamilyName = true; 10645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (StructuredName.PHONETIC_MIDDLE_NAME.equals(editField.column)) { 10665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee supportPhoneticMiddleName = true; 10675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (StructuredName.PHONETIC_GIVEN_NAME.equals(editField.column)) { 10695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee supportPhoneticGivenName = true; 10705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 10735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // DISPLAY_NAME <-> PREFIX, GIVEN_NAME, MIDDLE_NAME, FAMILY_NAME, SUFFIX 10745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String displayName = values.getAsString(StructuredName.DISPLAY_NAME); 10755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!TextUtils.isEmpty(displayName)) { 10765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!supportDisplayName) { 10775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Old data has a display name, while the new account doesn't allow it. 10785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee NameConverter.displayNameToStructuredName(context, displayName, values); 10795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 10805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // We don't want to migrate unseen data which may confuse users after the creation. 10815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredName.DISPLAY_NAME); 10825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 10845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (supportDisplayName) { 10855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Old data does not have display name, while the new account requires it. 10865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.put(StructuredName.DISPLAY_NAME, 10875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee NameConverter.structuredNameToDisplayName(context, values)); 10885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (String field : NameConverter.STRUCTURED_NAME_FIELDS) { 10895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(field); 10905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 10935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 10945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Phonetic (full) name <-> PHONETIC_FAMILY_NAME, PHONETIC_MIDDLE_NAME, PHONETIC_GIVEN_NAME 10955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String phoneticFullName = values.getAsString(DataKind.PSEUDO_COLUMN_PHONETIC_NAME); 10965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!TextUtils.isEmpty(phoneticFullName)) { 10975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!supportPhoneticFullName) { 10985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Old data has a phonetic (full) name, while the new account doesn't allow it. 10995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final StructuredNameDataItem tmpItem = 11005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee NameConverter.parsePhoneticName(phoneticFullName, null); 11015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(DataKind.PSEUDO_COLUMN_PHONETIC_NAME); 11025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (supportPhoneticFamilyName) { 11035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.put(StructuredName.PHONETIC_FAMILY_NAME, 11045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee tmpItem.getPhoneticFamilyName()); 11055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 11065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredName.PHONETIC_FAMILY_NAME); 11075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (supportPhoneticMiddleName) { 11095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.put(StructuredName.PHONETIC_MIDDLE_NAME, 11105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee tmpItem.getPhoneticMiddleName()); 11115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 11125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredName.PHONETIC_MIDDLE_NAME); 11135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (supportPhoneticGivenName) { 11155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.put(StructuredName.PHONETIC_GIVEN_NAME, 11165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee tmpItem.getPhoneticGivenName()); 11175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 11185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredName.PHONETIC_GIVEN_NAME); 11195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 11225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (supportPhoneticFullName) { 11235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Old data does not have a phonetic (full) name, while the new account requires it. 11245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.put(DataKind.PSEUDO_COLUMN_PHONETIC_NAME, 11255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee NameConverter.buildPhoneticName( 11265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredName.PHONETIC_FAMILY_NAME), 11275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredName.PHONETIC_MIDDLE_NAME), 11285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredName.PHONETIC_GIVEN_NAME))); 11295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!supportPhoneticFamilyName) { 11315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredName.PHONETIC_FAMILY_NAME); 11325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!supportPhoneticMiddleName) { 11345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredName.PHONETIC_MIDDLE_NAME); 11355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!supportPhoneticGivenName) { 11375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredName.PHONETIC_GIVEN_NAME); 11385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 11415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee newState.addEntry(ValuesDelta.fromAfter(values)); 11425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 11445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** @hide Public only for testing. */ 11455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static void migratePostal(RawContactDelta oldState, RawContactDelta newState, 11465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee DataKind newDataKind) { 11475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ArrayList<ValuesDelta> mimeEntries = ensureEntryMaxSize(newState, newDataKind, 11485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee oldState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE)); 11495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (mimeEntries == null || mimeEntries.isEmpty()) { 11505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return; 11515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 11535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean supportFormattedAddress = false; 11545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean supportStreet = false; 11555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String firstColumn = newDataKind.fieldList.get(0).column; 11565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (EditField editField : newDataKind.fieldList) { 11575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (StructuredPostal.FORMATTED_ADDRESS.equals(editField.column)) { 11585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee supportFormattedAddress = true; 11595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (StructuredPostal.STREET.equals(editField.column)) { 11615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee supportStreet = true; 11625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 11655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Set<Integer> supportedTypes = new HashSet<Integer>(); 11665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (newDataKind.typeList != null && !newDataKind.typeList.isEmpty()) { 11675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (EditType editType : newDataKind.typeList) { 11685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee supportedTypes.add(editType.rawValue); 11695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 11725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : mimeEntries) { 11735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ContentValues values = entry.getAfter(); 11745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (values == null) { 11755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee continue; 11765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Integer oldType = values.getAsInteger(StructuredPostal.TYPE); 11785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!supportedTypes.contains(oldType)) { 11795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee int defaultType; 11805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (newDataKind.defaultValues != null) { 11815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee defaultType = newDataKind.defaultValues.getAsInteger(StructuredPostal.TYPE); 11825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 11835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee defaultType = newDataKind.typeList.get(0).rawValue; 11845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.put(StructuredPostal.TYPE, defaultType); 11865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (oldType != null && oldType == StructuredPostal.TYPE_CUSTOM) { 11875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredPostal.LABEL); 11885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 11905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 11915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String formattedAddress = values.getAsString(StructuredPostal.FORMATTED_ADDRESS); 11925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!TextUtils.isEmpty(formattedAddress)) { 11935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!supportFormattedAddress) { 11945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Old data has a formatted address, while the new account doesn't allow it. 11955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredPostal.FORMATTED_ADDRESS); 11965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 11975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Unlike StructuredName we don't have logic to split it, so first 11985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // try to use street field and. If the new account doesn't have one, 11995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // then select first one anyway. 12005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (supportStreet) { 12015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.put(StructuredPostal.STREET, formattedAddress); 12025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 12035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.put(firstColumn, formattedAddress); 12045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 12075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (supportFormattedAddress) { 12085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Old data does not have formatted address, while the new account requires it. 12095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Unlike StructuredName we don't have logic to join multiple address values. 12105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Use poor join heuristics for now. 12115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee String[] structuredData; 12125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final boolean useJapaneseOrder = 12135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Locale.JAPANESE.getLanguage().equals(Locale.getDefault().getLanguage()); 12145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (useJapaneseOrder) { 12155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee structuredData = new String[] { 12165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.COUNTRY), 12175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.POSTCODE), 12185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.REGION), 12195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.CITY), 12205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.NEIGHBORHOOD), 12215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.STREET), 12225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.POBOX) }; 12235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 12245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee structuredData = new String[] { 12255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.POBOX), 12265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.STREET), 12275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.NEIGHBORHOOD), 12285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.CITY), 12295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.REGION), 12305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.POSTCODE), 12315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.getAsString(StructuredPostal.COUNTRY) }; 12325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final StringBuilder builder = new StringBuilder(); 12345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (String elem : structuredData) { 12355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!TextUtils.isEmpty(elem)) { 12365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee builder.append(elem + "\n"); 12375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.put(StructuredPostal.FORMATTED_ADDRESS, builder.toString()); 12405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 12415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredPostal.POBOX); 12425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredPostal.STREET); 12435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredPostal.NEIGHBORHOOD); 12445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredPostal.CITY); 12455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredPostal.REGION); 12465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredPostal.POSTCODE); 12475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(StructuredPostal.COUNTRY); 12485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 12515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee newState.addEntry(ValuesDelta.fromAfter(values)); 12525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 12555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** @hide Public only for testing. */ 12565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static void migrateEvent(RawContactDelta oldState, RawContactDelta newState, 12575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee DataKind newDataKind, Integer defaultYear) { 12585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ArrayList<ValuesDelta> mimeEntries = ensureEntryMaxSize(newState, newDataKind, 12595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee oldState.getMimeEntries(Event.CONTENT_ITEM_TYPE)); 12605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (mimeEntries == null || mimeEntries.isEmpty()) { 12615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return; 12625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 12645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final SparseArray<EventEditType> allowedTypes = new SparseArray<EventEditType>(); 12655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (EditType editType : newDataKind.typeList) { 12665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee allowedTypes.put(editType.rawValue, (EventEditType) editType); 12675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : mimeEntries) { 12695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ContentValues values = entry.getAfter(); 12705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (values == null) { 12715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee continue; 12725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final String dateString = values.getAsString(Event.START_DATE); 12745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Integer type = values.getAsInteger(Event.TYPE); 12755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (type != null && (allowedTypes.indexOfKey(type) >= 0) 12765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee && !TextUtils.isEmpty(dateString)) { 12775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee EventEditType suitableType = allowedTypes.get(type); 12785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 12795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ParsePosition position = new ParsePosition(0); 12805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee boolean yearOptional = false; 12815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Date date = CommonDateUtils.DATE_AND_TIME_FORMAT.parse(dateString, position); 12825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (date == null) { 12835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee yearOptional = true; 12845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee date = CommonDateUtils.NO_YEAR_DATE_FORMAT.parse(dateString, position); 12855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (date != null) { 12875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (yearOptional && !suitableType.isYearOptional()) { 12885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // The new EditType doesn't allow optional year. Supply default. 12895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Calendar calendar = Calendar.getInstance(DateUtils.UTC_TIMEZONE, 12905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Locale.US); 12915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (defaultYear == null) { 12925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee defaultYear = calendar.get(Calendar.YEAR); 12935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 12945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee calendar.setTime(date); 12955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int month = calendar.get(Calendar.MONTH); 12965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int day = calendar.get(Calendar.DAY_OF_MONTH); 12975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Exchange requires 8:00 for birthdays 12985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee calendar.set(defaultYear, month, day, 12995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee CommonDateUtils.DEFAULT_HOUR, 0, 0); 13005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.put(Event.START_DATE, 13015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee CommonDateUtils.FULL_DATE_FORMAT.format(calendar.getTime())); 13025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee newState.addEntry(ValuesDelta.fromAfter(values)); 13055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 13065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Just drop it. 13075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 13115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** @hide Public only for testing. */ 13125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static void migrateGenericWithoutTypeColumn( 13135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee RawContactDelta oldState, RawContactDelta newState, DataKind newDataKind) { 13145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ArrayList<ValuesDelta> mimeEntries = ensureEntryMaxSize(newState, newDataKind, 13155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee oldState.getMimeEntries(newDataKind.mimeType)); 13165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (mimeEntries == null || mimeEntries.isEmpty()) { 13175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return; 13185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 13205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : mimeEntries) { 13215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee ContentValues values = entry.getAfter(); 13225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (values != null) { 13235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee newState.addEntry(ValuesDelta.fromAfter(values)); 13245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 13285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee /** @hide Public only for testing. */ 13295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee public static void migrateGenericWithTypeColumn( 13305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee RawContactDelta oldState, RawContactDelta newState, DataKind newDataKind) { 13315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ArrayList<ValuesDelta> mimeEntries = oldState.getMimeEntries(newDataKind.mimeType); 13325ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (mimeEntries == null || mimeEntries.isEmpty()) { 13335ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee return; 13345ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13355ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 13365ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Note that type specified with the old account may be invalid with the new account, while 13375ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // we want to preserve its data as much as possible. e.g. if a user typed a phone number 13385ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // with a type which is valid with an old account but not with a new account, the user 13395ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // probably wants to have the number with default type, rather than seeing complete data 13405ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // loss. 13415ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // 13425ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Specifically, this method works as follows: 13435ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // 1. detect defaultType 13445ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // 2. prepare constants & variables for iteration 13455ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // 3. iterate over mimeEntries: 13465ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // 3.1 stop iteration if total number of mimeEntries reached typeOverallMax specified in 13475ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // DataKind 13485ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // 3.2 replace unallowed types with defaultType 13495ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // 3.3 check if the number of entries is below specificMax specified in AccountType 13505ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 13515ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Here, defaultType can be supplied in two ways 13525ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // - via kind.defaultValues 13535ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // - via kind.typeList.get(0).rawValue 13545ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Integer defaultType = null; 13555ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (newDataKind.defaultValues != null) { 13565ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee defaultType = newDataKind.defaultValues.getAsInteger(COLUMN_FOR_TYPE); 13575ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13585ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Set<Integer> allowedTypes = new HashSet<Integer>(); 13595ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // key: type, value: the number of entries allowed for the type (specificMax) 13605ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final SparseIntArray typeSpecificMaxMap = new SparseIntArray(); 13615ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (defaultType != null) { 13625ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee allowedTypes.add(defaultType); 13635ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee typeSpecificMaxMap.put(defaultType, -1); 13645ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13655ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Note: typeList may be used in different purposes when defaultValues are specified. 13665ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // Especially in IM, typeList contains available protocols (e.g. PROTOCOL_GOOGLE_TALK) 13675ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // instead of "types" which we want to treate here (e.g. TYPE_HOME). So we don't add 13685ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // anything other than defaultType into allowedTypes and typeSpecificMapMax. 13695ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!Im.CONTENT_ITEM_TYPE.equals(newDataKind.mimeType) && 13705ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee newDataKind.typeList != null && !newDataKind.typeList.isEmpty()) { 13715ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (EditType editType : newDataKind.typeList) { 13725ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee allowedTypes.add(editType.rawValue); 13735ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee typeSpecificMaxMap.put(editType.rawValue, editType.specificMax); 13745ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13755ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (defaultType == null) { 13765ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee defaultType = newDataKind.typeList.get(0).rawValue; 13775ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13785ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13795ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 13805ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (defaultType == null) { 13815ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee Log.w(TAG, "Default type isn't available for mimetype " + newDataKind.mimeType); 13825ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13835ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 13845ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int typeOverallMax = newDataKind.typeOverallMax; 13855ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 13865ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // key: type, value: the number of current entries. 13875ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final SparseIntArray currentEntryCount = new SparseIntArray(); 13885ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee int totalCount = 0; 13895ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 13905ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee for (ValuesDelta entry : mimeEntries) { 13915ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (typeOverallMax != -1 && totalCount >= typeOverallMax) { 13925ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee break; 13935ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13945ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 13955ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final ContentValues values = entry.getAfter(); 13965ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (values == null) { 13975ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee continue; 13985ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 13995ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee 14005ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Integer oldType = entry.getAsInteger(COLUMN_FOR_TYPE); 14015ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final Integer typeForNewAccount; 14025ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (!allowedTypes.contains(oldType)) { 14035ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee // The new account doesn't support the type. 14045ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (defaultType != null) { 14055ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee typeForNewAccount = defaultType.intValue(); 14065ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.put(COLUMN_FOR_TYPE, defaultType.intValue()); 14075ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (oldType != null && oldType == TYPE_CUSTOM) { 14085ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(COLUMN_FOR_LABEL); 14095ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 14105ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 14115ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee typeForNewAccount = null; 14125ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee values.remove(COLUMN_FOR_TYPE); 14135ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 14145ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } else { 14155ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee typeForNewAccount = oldType; 14165ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 14175ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (typeForNewAccount != null) { 14185ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int specificMax = typeSpecificMaxMap.get(typeForNewAccount, 0); 14195ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (specificMax >= 0) { 14205ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee final int currentCount = currentEntryCount.get(typeForNewAccount, 0); 14215ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee if (currentCount >= specificMax) { 14225ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee continue; 14235ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 14245ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee currentEntryCount.put(typeForNewAccount, currentCount + 1); 14255ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 14265ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 14275ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee newState.addEntry(ValuesDelta.fromAfter(values)); 14285ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee totalCount++; 14295ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 14305ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee } 14315ade0bb1757b216ace2f50d2357409bf9876a07aYorke Lee} 1432