1ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonpackage com.android.exchange.adapter;
2ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
3ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.content.ContentProviderOperation;
4add575db94f86397c9246d89ed85d29968b5aeaaAlon Albertimport android.content.ContentProviderOperation.Builder;
5ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.content.ContentProviderResult;
6ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.content.ContentResolver;
7ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.content.ContentUris;
8ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.content.ContentValues;
9ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.content.Context;
10ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.content.Entity;
11add575db94f86397c9246d89ed85d29968b5aeaaAlon Albertimport android.content.Entity.NamedContentValues;
12ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.content.EntityIterator;
13ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.content.OperationApplicationException;
14ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.database.Cursor;
15ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.net.Uri;
16ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.os.RemoteException;
17ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract;
18ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.Email;
19ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.Event;
20ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;
21ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.Im;
22ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.Nickname;
23ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.Note;
24ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.Organization;
25ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.Phone;
26ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.Photo;
27ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.Relation;
28ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
29ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
30ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.provider.ContactsContract.CommonDataKinds.Website;
31add575db94f86397c9246d89ed85d29968b5aeaaAlon Albertimport android.provider.ContactsContract.Data;
32add575db94f86397c9246d89ed85d29968b5aeaaAlon Albertimport android.provider.ContactsContract.RawContacts;
33add575db94f86397c9246d89ed85d29968b5aeaaAlon Albertimport android.provider.ContactsContract.SyncState;
34add575db94f86397c9246d89ed85d29968b5aeaaAlon Albertimport android.provider.SyncStateContract;
356cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shraunerimport android.text.TextUtils;
36ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.text.util.Rfc822Token;
37ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.text.util.Rfc822Tokenizer;
38ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport android.util.Base64;
39ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
40ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport com.android.emailcommon.provider.Account;
41ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport com.android.emailcommon.provider.Mailbox;
42ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport com.android.emailcommon.utility.Utility;
43ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport com.android.exchange.Eas;
446cb6c70ea47035a27bd1d808babe39a2d1829c8dYu Ping Huimport com.android.exchange.eas.EasSyncCollectionTypeBase;
45f4195d389ffd4d92e37cd1d01db1713180740291Yu Ping Huimport com.android.exchange.eas.EasSyncContacts;
46ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport com.android.exchange.utility.CalendarUtilities;
47ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport com.android.mail.utils.LogUtils;
48ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
49ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport java.io.IOException;
50ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport java.io.InputStream;
512f369a47e14916a34f49c79c0a246a2e3ac3072fJay Shraunerimport java.text.ParseException;
52ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport java.util.ArrayList;
53ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport java.util.GregorianCalendar;
54ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonimport java.util.TimeZone;
55ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
56ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdonpublic class ContactsSyncParser extends AbstractSyncParser {
57110837ebff288a75f9bda067c38e2c46797d99b5Alon Albert    private static final String TAG = Eas.LOG_TAG;
58ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
59ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private static final String SERVER_ID_SELECTION = RawContacts.SOURCE_ID + "=?";
60ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private static final String CLIENT_ID_SELECTION = RawContacts.SYNC1 + "=?";
61ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private static final String[] ID_PROJECTION = new String[] {RawContacts._ID};
62ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
63ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private static final ArrayList<NamedContentValues> EMPTY_ARRAY_NAMEDCONTENTVALUES
64ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        = new ArrayList<NamedContentValues>();
65ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
66ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private static final String FOUND_DATA_ROW = "com.android.exchange.FOUND_ROW";
67ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
68ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private static final int MAX_IM_ROWS = 3;
69ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private static final int MAX_EMAIL_ROWS = 3;
70ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private static final int MAX_PHONE_ROWS = 2;
71ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private static final String COMMON_DATA_ROW = Im.DATA;  // Could have been Email.DATA, etc.
72ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private static final String COMMON_TYPE_ROW = Phone.TYPE; // Could have been any typed row
73ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
74ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    String[] mBindArgument = new String[1];
75ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    ContactOperations ops = new ContactOperations();
76ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private final android.accounts.Account mAccountManagerAccount;
77ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private final Uri mAccountUri;
78ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private boolean mGroupsUsed = false;
79ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
80ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public ContactsSyncParser(final Context context, final ContentResolver resolver,
81ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            final InputStream in, final Mailbox mailbox, final Account account,
82ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            final android.accounts.Account accountManagerAccount) throws IOException {
83ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        super(context, resolver, in, mailbox, account);
84ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        mAccountManagerAccount = accountManagerAccount;
85ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        mAccountUri = uriWithAccountAndIsSyncAdapter(RawContacts.CONTENT_URI,
86ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                mAccount.mEmailAddress);
87ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
88ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
89ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public boolean isGroupsUsed() {
90ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        return mGroupsUsed;
91ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
92ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
93ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public void addData(String serverId, ContactOperations ops, Entity entity)
94ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            throws IOException {
95ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String prefix = null;
96ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String firstName = null;
97ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String lastName = null;
98ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String middleName = null;
99ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String suffix = null;
100ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String companyName = null;
101ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String yomiFirstName = null;
102ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String yomiLastName = null;
103ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String yomiCompanyName = null;
104ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String title = null;
105ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String department = null;
106ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String officeLocation = null;
107ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        Address home = new Address();
108ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        Address work = new Address();
109ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        Address other = new Address();
110ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        EasBusiness business = new EasBusiness();
111ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        EasPersonal personal = new EasPersonal();
112ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ArrayList<String> children = new ArrayList<String>();
113ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ArrayList<UntypedRow> emails = new ArrayList<UntypedRow>();
114ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ArrayList<UntypedRow> ims = new ArrayList<UntypedRow>();
115ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ArrayList<UntypedRow> homePhones = new ArrayList<UntypedRow>();
116ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ArrayList<UntypedRow> workPhones = new ArrayList<UntypedRow>();
117ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        if (entity == null) {
118ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ops.newContact(serverId, mAccount.mEmailAddress);
119ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
120ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
121ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        while (nextTag(Tags.SYNC_APPLICATION_DATA) != END) {
122ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            switch (tag) {
123ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_FIRST_NAME:
124ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    firstName = getValue();
125ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
126ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_LAST_NAME:
127ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    lastName = getValue();
128ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
129ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_MIDDLE_NAME:
130ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    middleName = getValue();
131ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
132ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_SUFFIX:
133ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    suffix = getValue();
134ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
135ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_COMPANY_NAME:
136ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    companyName = getValue();
137ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
138ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_JOB_TITLE:
139ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    title = getValue();
140ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
141ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_EMAIL1_ADDRESS:
142ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_EMAIL2_ADDRESS:
143ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_EMAIL3_ADDRESS:
144ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    emails.add(new EmailRow(getValue()));
145ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
146ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_BUSINESS2_TELEPHONE_NUMBER:
147ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_BUSINESS_TELEPHONE_NUMBER:
148ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    workPhones.add(new PhoneRow(getValue(), Phone.TYPE_WORK));
149ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
150ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS2_MMS:
151ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addPhone(entity, Phone.TYPE_MMS, getValue());
152ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
153ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_BUSINESS_FAX_NUMBER:
154ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addPhone(entity, Phone.TYPE_FAX_WORK, getValue());
155ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
156ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS2_COMPANY_MAIN_PHONE:
157ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addPhone(entity, Phone.TYPE_COMPANY_MAIN, getValue());
158ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
159ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_HOME_FAX_NUMBER:
160ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addPhone(entity, Phone.TYPE_FAX_HOME, getValue());
161ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
162ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_HOME_TELEPHONE_NUMBER:
163ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_HOME2_TELEPHONE_NUMBER:
164ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    homePhones.add(new PhoneRow(getValue(), Phone.TYPE_HOME));
165ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
166ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_MOBILE_TELEPHONE_NUMBER:
167ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addPhone(entity, Phone.TYPE_MOBILE, getValue());
168ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
169ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_CAR_TELEPHONE_NUMBER:
170ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addPhone(entity, Phone.TYPE_CAR, getValue());
171ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
172ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_RADIO_TELEPHONE_NUMBER:
173ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addPhone(entity, Phone.TYPE_RADIO, getValue());
174ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
175ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_PAGER_NUMBER:
176ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addPhone(entity, Phone.TYPE_PAGER, getValue());
177ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
178ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_ASSISTANT_TELEPHONE_NUMBER:
179ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addPhone(entity, Phone.TYPE_ASSISTANT, getValue());
180ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
181ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS2_IM_ADDRESS:
182ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS2_IM_ADDRESS_2:
183ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS2_IM_ADDRESS_3:
184ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ims.add(new ImRow(getValue()));
185ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
186ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_BUSINESS_ADDRESS_CITY:
187ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    work.city = getValue();
188ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
189ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_BUSINESS_ADDRESS_COUNTRY:
190ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    work.country = getValue();
191ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
192ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_BUSINESS_ADDRESS_POSTAL_CODE:
193ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    work.code = getValue();
194ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
195ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_BUSINESS_ADDRESS_STATE:
196ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    work.state = getValue();
197ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
198ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_BUSINESS_ADDRESS_STREET:
199ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    work.street = getValue();
200ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
201ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_HOME_ADDRESS_CITY:
202ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    home.city = getValue();
203ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
204ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_HOME_ADDRESS_COUNTRY:
205ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    home.country = getValue();
206ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
207ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_HOME_ADDRESS_POSTAL_CODE:
208ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    home.code = getValue();
209ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
210ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_HOME_ADDRESS_STATE:
211ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    home.state = getValue();
212ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
213ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_HOME_ADDRESS_STREET:
214ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    home.street = getValue();
215ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
216ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_OTHER_ADDRESS_CITY:
217ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    other.city = getValue();
218ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
219ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_OTHER_ADDRESS_COUNTRY:
220ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    other.country = getValue();
221ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
222ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_OTHER_ADDRESS_POSTAL_CODE:
223ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    other.code = getValue();
224ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
225ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_OTHER_ADDRESS_STATE:
226ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    other.state = getValue();
227ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
228ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_OTHER_ADDRESS_STREET:
229ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    other.street = getValue();
230ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
231ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
232ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_CHILDREN:
233ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    childrenParser(children);
234ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
235ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
236ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_YOMI_COMPANY_NAME:
237ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    yomiCompanyName = getValue();
238ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
239ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_YOMI_FIRST_NAME:
240ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    yomiFirstName = getValue();
241ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
242ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_YOMI_LAST_NAME:
243ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    yomiLastName = getValue();
244ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
245ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
246ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS2_NICKNAME:
247ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addNickname(entity, getValue());
248ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
249ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
250ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_ASSISTANT_NAME:
251ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addRelation(entity, Relation.TYPE_ASSISTANT, getValue());
252ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
253ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS2_MANAGER_NAME:
254ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addRelation(entity, Relation.TYPE_MANAGER, getValue());
255ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
256ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_SPOUSE:
257ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addRelation(entity, Relation.TYPE_SPOUSE, getValue());
258ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
259ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_DEPARTMENT:
260ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    department = getValue();
261ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
262ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_TITLE:
263ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    prefix = getValue();
264ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
265ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
266ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                // EAS Business
267ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_OFFICE_LOCATION:
268ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    officeLocation = getValue();
269ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
270ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS2_CUSTOMER_ID:
271ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    business.customerId = getValue();
272ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
273ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS2_GOVERNMENT_ID:
274ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    business.governmentId = getValue();
275ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
276ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS2_ACCOUNT_NAME:
277ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    business.accountName = getValue();
278ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
279ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
280ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                // EAS Personal
281ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_ANNIVERSARY:
282ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    personal.anniversary = getValue();
283ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
284102e1cf9d34fceebbad64356e58e3427ee4e6da4Anthony Lee                case Tags.CONTACTS_FILE_AS:
285102e1cf9d34fceebbad64356e58e3427ee4e6da4Anthony Lee                    personal.fileAs = getValue();
286102e1cf9d34fceebbad64356e58e3427ee4e6da4Anthony Lee                    break;
287ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_BIRTHDAY:
288ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addBirthday(entity, getValue());
289ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
290ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_WEBPAGE:
291ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addWebpage(entity, getValue());
292ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
293ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
294ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_PICTURE:
295ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addPhoto(entity, getValue());
296ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
297ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
298ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.BASE_BODY:
299ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addNote(entity, bodyParser());
300ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
301ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_BODY:
302ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addNote(entity, getValue());
303ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
304ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
305ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_CATEGORIES:
306ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    mGroupsUsed = true;
307ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    categoriesParser(ops, entity);
308ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
309ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
310ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                default:
311ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    skipTag();
312ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
313ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
314ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
315ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ops.addName(entity, prefix, firstName, lastName, middleName, suffix,
316ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                yomiFirstName, yomiLastName);
317ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ops.addBusiness(entity, business);
318ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ops.addPersonal(entity, personal);
319ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
320ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ops.addUntyped(entity, emails, Email.CONTENT_ITEM_TYPE, -1, MAX_EMAIL_ROWS);
321ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ops.addUntyped(entity, ims, Im.CONTENT_ITEM_TYPE, -1, MAX_IM_ROWS);
322ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ops.addUntyped(entity, homePhones, Phone.CONTENT_ITEM_TYPE, Phone.TYPE_HOME,
323ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                MAX_PHONE_ROWS);
324ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ops.addUntyped(entity, workPhones, Phone.CONTENT_ITEM_TYPE, Phone.TYPE_WORK,
325ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                MAX_PHONE_ROWS);
326ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
327ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        if (!children.isEmpty()) {
328ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ops.addChildren(entity, children);
329ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
330ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
331ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        if (work.hasData()) {
332ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ops.addPostal(entity, StructuredPostal.TYPE_WORK, work.street, work.city,
333ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    work.state, work.country, work.code);
334ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
335ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        if (home.hasData()) {
336ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ops.addPostal(entity, StructuredPostal.TYPE_HOME, home.street, home.city,
337ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    home.state, home.country, home.code);
338ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
339ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        if (other.hasData()) {
340ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ops.addPostal(entity, StructuredPostal.TYPE_OTHER, other.street, other.city,
341ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    other.state, other.country, other.code);
342ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
343ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
344ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        if (companyName != null) {
345ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ops.addOrganization(entity, Organization.TYPE_WORK, companyName, title, department,
346ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    yomiCompanyName, officeLocation);
347ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
348ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
349ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        if (entity != null) {
350ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // We've been removing rows from the list as they've been found in the xml
351ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Any that are left must have been deleted on the server
352ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ArrayList<NamedContentValues> ncvList = entity.getSubValues();
353ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            for (NamedContentValues ncv: ncvList) {
354ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                // These rows need to be deleted...
355ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                Uri u = dataUriFromNamedContentValues(ncv);
356ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                ops.add(ContentProviderOperation.newDelete(addCallerIsSyncAdapterParameter(u))
357ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        .build());
358ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
359ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
360ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
361ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
362ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private void categoriesParser(ContactOperations ops, Entity entity) throws IOException {
363ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        while (nextTag(Tags.CONTACTS_CATEGORIES) != END) {
364ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            switch (tag) {
365ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_CATEGORY:
366ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ops.addGroup(entity, getValue());
367ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
368ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                default:
369ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    skipTag();
370ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
371ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
372ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
373ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
374ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private void childrenParser(ArrayList<String> children) throws IOException {
375ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        while (nextTag(Tags.CONTACTS_CHILDREN) != END) {
376ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            switch (tag) {
377ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.CONTACTS_CHILD:
378ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    if (children.size() < EasChildren.MAX_CHILDREN) {
379ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        children.add(getValue());
380ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    }
381ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
382ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                default:
383ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    skipTag();
384ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
385ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
386ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
387ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
388ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private String bodyParser() throws IOException {
389ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String body = null;
390ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        while (nextTag(Tags.BASE_BODY) != END) {
391ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            switch (tag) {
392ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.BASE_DATA:
393ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    body = getValue();
394ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
395ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                default:
396ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    skipTag();
397ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
398ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
399ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        return body;
400ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
401ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
402ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public void addParser(ContactOperations ops) throws IOException {
403ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String serverId = null;
404ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        while (nextTag(Tags.SYNC_ADD) != END) {
405ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            switch (tag) {
406ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.SYNC_SERVER_ID: // same as
407ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    serverId = getValue();
408ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
409ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.SYNC_APPLICATION_DATA:
410ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    addData(serverId, ops, null);
411ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
412ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                default:
413ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    skipTag();
414ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
415ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
416ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
417ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
418ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private Cursor getServerIdCursor(String serverId) {
419ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        mBindArgument[0] = serverId;
420ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        return mContentResolver.query(mAccountUri, ID_PROJECTION, SERVER_ID_SELECTION,
421ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                mBindArgument, null);
422ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
423ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
424ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private Cursor getClientIdCursor(String clientId) {
425ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        mBindArgument[0] = clientId;
426ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        return mContentResolver.query(mAccountUri, ID_PROJECTION, CLIENT_ID_SELECTION,
427ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                mBindArgument, null);
428ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
429ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
430ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public void deleteParser(ContactOperations ops) throws IOException {
431ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        while (nextTag(Tags.SYNC_DELETE) != END) {
432ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            switch (tag) {
433ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.SYNC_SERVER_ID:
434ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    String serverId = getValue();
435ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    // Find the message in this mailbox with the given serverId
436ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    Cursor c = getServerIdCursor(serverId);
437ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    try {
438ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        if (c.moveToFirst()) {
439ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            userLog("Deleting ", serverId);
440ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            ops.delete(c.getLong(0));
441ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        }
442ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    } finally {
443ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        c.close();
444ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    }
445ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
446ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                default:
447ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    skipTag();
448ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
449ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
450ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
451ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
452ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    class ServerChange {
453ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        long id;
454ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        boolean read;
455ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
456ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ServerChange(long _id, boolean _read) {
457ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            id = _id;
458ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            read = _read;
459ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
460ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
461ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
462ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    /**
463ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     * Changes are handled row by row, and only changed/new rows are acted upon
464ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     * @param ops the array of pending ContactProviderOperations.
465ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     * @throws IOException
466ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     */
467ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public void changeParser(ContactOperations ops) throws IOException {
468ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String serverId = null;
469ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        Entity entity = null;
470ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        while (nextTag(Tags.SYNC_CHANGE) != END) {
471ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            switch (tag) {
472ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.SYNC_SERVER_ID:
473ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    serverId = getValue();
474ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    Cursor c = getServerIdCursor(serverId);
475ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    try {
476ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        if (c.moveToFirst()) {
477ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            // TODO Handle deleted individual rows...
478ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            Uri uri = ContentUris.withAppendedId(
479ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                    RawContacts.CONTENT_URI, c.getLong(0));
480ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            uri = Uri.withAppendedPath(
481ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                    uri, RawContacts.Entity.CONTENT_DIRECTORY);
482185060cbeb39dc4539fbc0c72a865d8ec8d12979Jay Shrauner                            final Cursor cursor = mContentResolver.query(uri,
483185060cbeb39dc4539fbc0c72a865d8ec8d12979Jay Shrauner                                    null, null, null, null);
484185060cbeb39dc4539fbc0c72a865d8ec8d12979Jay Shrauner                            if (cursor != null) {
485185060cbeb39dc4539fbc0c72a865d8ec8d12979Jay Shrauner                                final EntityIterator entityIterator =
486185060cbeb39dc4539fbc0c72a865d8ec8d12979Jay Shrauner                                    RawContacts.newEntityIterator(cursor);
487185060cbeb39dc4539fbc0c72a865d8ec8d12979Jay Shrauner                                if (entityIterator.hasNext()) {
488185060cbeb39dc4539fbc0c72a865d8ec8d12979Jay Shrauner                                    entity = entityIterator.next();
489185060cbeb39dc4539fbc0c72a865d8ec8d12979Jay Shrauner                                }
490185060cbeb39dc4539fbc0c72a865d8ec8d12979Jay Shrauner                                userLog("Changing contact ", serverId);
491ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            }
492ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        }
493ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    } finally {
494ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        c.close();
495ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    }
496ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
497ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.SYNC_APPLICATION_DATA:
498ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    addData(serverId, ops, entity);
499ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
500ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                default:
501ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    skipTag();
502ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
503ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
504ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
505ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
506ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    @Override
507ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public void commandsParser() throws IOException {
508ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        while (nextTag(Tags.SYNC_COMMANDS) != END) {
509ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (tag == Tags.SYNC_ADD) {
510ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                addParser(ops);
511ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            } else if (tag == Tags.SYNC_DELETE) {
512ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                deleteParser(ops);
513ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            } else if (tag == Tags.SYNC_CHANGE) {
514ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                changeParser(ops);
515ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            } else
516ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                skipTag();
517ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
518ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
519ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
520ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    @Override
521ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public void commit() throws IOException {
522ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon       // Save the syncKey here, using the Helper provider by Contacts provider
523ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        userLog("Contacts SyncKey saved as: ", mMailbox.mSyncKey);
524ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ops.add(SyncStateContract.Helpers.newSetOperation(SyncState.CONTENT_URI,
525ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                mAccountManagerAccount, mMailbox.mSyncKey.getBytes()));
526ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
527ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        // Execute these all at once...
528ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ops.execute(mContext);
529ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
530d34e08dade60d10a9751920f928fe0d02f58ac4cJay Shrauner        if (ops.mResults != null && ops.mResults.length > 0) {
531d34e08dade60d10a9751920f928fe0d02f58ac4cJay Shrauner            final ContentValues cv = new ContentValues();
532ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            cv.put(RawContacts.DIRTY, 0);
533ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            for (int i = 0; i < ops.mContactIndexCount; i++) {
534d34e08dade60d10a9751920f928fe0d02f58ac4cJay Shrauner                final int index = ops.mContactIndexArray[i];
535d34e08dade60d10a9751920f928fe0d02f58ac4cJay Shrauner                final Uri u = index < ops.mResults.length ? ops.mResults[index].uri : null;
536ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                if (u != null) {
537ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    String idString = u.getLastPathSegment();
538ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    mContentResolver.update(
539ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            addCallerIsSyncAdapterParameter(RawContacts.CONTENT_URI), cv,
540ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            RawContacts._ID + "=" + idString, null);
541ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                }
542ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
543ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
544ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
545ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
546ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public void addResponsesParser() throws IOException {
547ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String serverId = null;
548ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String clientId = null;
549ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ContentValues cv = new ContentValues();
550ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        while (nextTag(Tags.SYNC_ADD) != END) {
551ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            switch (tag) {
552ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.SYNC_SERVER_ID:
553ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    serverId = getValue();
554ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
555ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.SYNC_CLIENT_ID:
556ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    clientId = getValue();
557ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
558ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.SYNC_STATUS:
559ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    getValue();
560ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
561ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                default:
562ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    skipTag();
563ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
564ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
565ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
566ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        // This is theoretically impossible, but...
567ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        if (clientId == null || serverId == null) return;
568ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
569ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        Cursor c = getClientIdCursor(clientId);
570ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        try {
571ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (c.moveToFirst()) {
572ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                cv.put(RawContacts.SOURCE_ID, serverId);
573ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                cv.put(RawContacts.DIRTY, 0);
574ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                ops.add(ContentProviderOperation.newUpdate(
575ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        ContentUris.withAppendedId(
576ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                addCallerIsSyncAdapterParameter(RawContacts.CONTENT_URI),
577ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                c.getLong(0)))
578ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        .withValues(cv)
579ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        .build());
580ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                userLog("New contact " + clientId + " was given serverId: " + serverId);
581ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
582ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        } finally {
583ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            c.close();
584ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
585ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
586ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
587ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public void changeResponsesParser() throws IOException {
588ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String serverId = null;
589ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String status = null;
590ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        while (nextTag(Tags.SYNC_CHANGE) != END) {
591ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            switch (tag) {
592ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.SYNC_SERVER_ID:
593ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    serverId = getValue();
594ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
595ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                case Tags.SYNC_STATUS:
596ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    status = getValue();
597ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
598ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                default:
599ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    skipTag();
600ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
601ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
602ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        if (serverId != null && status != null) {
603ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            userLog("Changed contact " + serverId + " failed with status: " + status);
604ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
605ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
606ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
607ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
608ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    @Override
609ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public void responsesParser() throws IOException {
610ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        // Handle server responses here (for Add and Change)
611ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        while (nextTag(Tags.SYNC_RESPONSES) != END) {
612ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (tag == Tags.SYNC_ADD) {
613ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                addResponsesParser();
614ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            } else if (tag == Tags.SYNC_CHANGE) {
615ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                changeResponsesParser();
616ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            } else
617ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                skipTag();
618ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
619ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
620ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
621ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private static Uri uriWithAccountAndIsSyncAdapter(final Uri uri, final String emailAddress) {
622ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        return uri.buildUpon()
623ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            .appendQueryParameter(RawContacts.ACCOUNT_NAME, emailAddress)
624ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            .appendQueryParameter(RawContacts.ACCOUNT_TYPE, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE)
625ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
626ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            .build();
627ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
628ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
629ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    static Uri addCallerIsSyncAdapterParameter(Uri uri) {
630ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        return uri.buildUpon()
631ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
632ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                .build();
633ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
634ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
635ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    /**
636ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     * Generate the uri for the data row associated with this NamedContentValues object
637ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     * @param ncv the NamedContentValues object
638ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     * @return a uri that can be used to refer to this row
639ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     */
640ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public static Uri dataUriFromNamedContentValues(NamedContentValues ncv) {
641ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        long id = ncv.values.getAsLong(RawContacts._ID);
642ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        Uri dataUri = ContentUris.withAppendedId(ncv.uri, id);
643ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        return dataUri;
644ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
645ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
646ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public static final class EasChildren {
647ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        private EasChildren() {}
648ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
649ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        /** MIME type used when storing this in data table. */
650ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/eas_children";
651ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public static final int MAX_CHILDREN = 8;
652ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public static final String[] ROWS =
653ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            new String[] {"data2", "data3", "data4", "data5", "data6", "data7", "data8", "data9"};
654ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
655ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
656ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public static final class EasPersonal {
657ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String anniversary;
658ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String fileAs;
659ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
660ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            /** MIME type used when storing this in data table. */
661ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/eas_personal";
662ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public static final String ANNIVERSARY = "data2";
663ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public static final String FILE_AS = "data4";
664ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
665ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        boolean hasData() {
666ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return anniversary != null || fileAs != null;
667ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
668ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
669ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
670ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public static final class EasBusiness {
671ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String customerId;
672ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String governmentId;
673ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String accountName;
674ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
675ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        /** MIME type used when storing this in data table. */
676ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/eas_business";
677ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public static final String CUSTOMER_ID = "data6";
678ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public static final String GOVERNMENT_ID = "data7";
679ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public static final String ACCOUNT_NAME = "data8";
680ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
681ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        boolean hasData() {
682ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return customerId != null || governmentId != null || accountName != null;
683ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
684ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
685ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
686ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public static final class Address {
687ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String city;
688ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String country;
689ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String code;
690ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String street;
691ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String state;
692ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
693ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        boolean hasData() {
694ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return city != null || country != null || code != null || state != null
695ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                || street != null;
696ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
697ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
698ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
699ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    interface UntypedRow {
700ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addValues(RowBuilder builder);
701ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public boolean isSameAs(int type, String value);
702ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
703ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
704ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    static class EmailRow implements UntypedRow {
705ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String email;
706ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String displayName;
707ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
708ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public EmailRow(String _email) {
709ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(_email);
710ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Can't happen, but belt & suspenders
711ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (tokens.length == 0) {
712ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                email = "";
713ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                displayName = "";
714ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            } else {
715ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                Rfc822Token token = tokens[0];
716ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                email = token.getAddress();
717ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                displayName = token.getName();
718ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
719ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
720ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
721ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        @Override
722ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addValues(RowBuilder builder) {
723ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Email.DATA, email);
724ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Email.DISPLAY_NAME, displayName);
725ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
726ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
727ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        @Override
728ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public boolean isSameAs(int type, String value) {
729ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return email.equalsIgnoreCase(value);
730ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
731ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
732ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
733ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    static class ImRow implements UntypedRow {
734ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String im;
735ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
736ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public ImRow(String _im) {
737ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            im = _im;
738ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
739ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
740ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        @Override
741ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addValues(RowBuilder builder) {
742ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Im.DATA, im);
743ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
744ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
745ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        @Override
746ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public boolean isSameAs(int type, String value) {
747ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return im.equalsIgnoreCase(value);
748ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
749ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
750ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
751ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    static class PhoneRow implements UntypedRow {
752ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        String phone;
753ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        int type;
754ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
755ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public PhoneRow(String _phone, int _type) {
756ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            phone = _phone;
757ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            type = _type;
758ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
759ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
760ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        @Override
761ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addValues(RowBuilder builder) {
762ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Im.DATA, phone);
763ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Phone.TYPE, type);
764ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
765ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
766ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        @Override
767ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public boolean isSameAs(int _type, String value) {
768ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return type == _type && phone.equalsIgnoreCase(value);
769ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
770ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
771ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
772ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    /**
773ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     * RowBuilder is a wrapper for the Builder class that is used to create/update rows for a
774ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     * ContentProvider.  It has, in addition to the Builder, ContentValues which, if present,
775ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     * represent the current values of that row, that can be compared against current values to
776ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     * see whether an update is even necessary.  The methods on SmartBuilder are delegated to
777ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     * the Builder.
778ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon     */
779ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    private static class RowBuilder {
780ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        Builder builder;
781ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ContentValues cv;
782ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
783ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public RowBuilder(Builder _builder) {
784ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder = _builder;
785ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
786ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
787ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public RowBuilder(Builder _builder, NamedContentValues _ncv) {
788ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder = _builder;
789ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            cv = _ncv.values;
790ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
791ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
792ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        RowBuilder withValueBackReference(String key, int previousResult) {
793ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValueBackReference(key, previousResult);
794ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return this;
795ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
796ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
797ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        ContentProviderOperation build() {
798ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return builder.build();
799ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
800ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
801ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        RowBuilder withValue(String key, Object value) {
802ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(key, value);
803ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return this;
804ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
805ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
806ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    public static class ContactOperations extends ArrayList<ContentProviderOperation> {
807ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        private static final long serialVersionUID = 1L;
808ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        private int mCount = 0;
809ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        private int mContactBackValue = mCount;
8105b874897559eb3ad6ac777c7317cfd5d253704f9Yu Ping Hu        // Make an array big enough for the max possible window size.
8116cb6c70ea47035a27bd1d808babe39a2d1829c8dYu Ping Hu        private final int[] mContactIndexArray = new int[EasSyncCollectionTypeBase.MAX_WINDOW_SIZE];
812ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        private int mContactIndexCount = 0;
813ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        private ContentProviderResult[] mResults = null;
814ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
815ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        @Override
816ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public boolean add(ContentProviderOperation op) {
817ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            super.add(op);
818ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            mCount++;
819ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return true;
820ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
821ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
822ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void newContact(final String serverId, final String emailAddress) {
823ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            Builder builder = ContentProviderOperation.newInsert(
824ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    uriWithAccountAndIsSyncAdapter(RawContacts.CONTENT_URI, emailAddress));
825ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ContentValues values = new ContentValues();
826ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            values.put(RawContacts.SOURCE_ID, serverId);
827ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValues(values);
828ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            mContactBackValue = mCount;
829ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            mContactIndexArray[mContactIndexCount++] = mCount;
830ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
831ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
832ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
833ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void delete(long id) {
834ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(ContentProviderOperation
835ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    .newDelete(ContentUris.withAppendedId(RawContacts.CONTENT_URI, id)
836ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            .buildUpon()
837ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
838ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            .build())
839ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    .build());
840ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
841ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
842ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void execute(final Context context) {
843ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            try {
844ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                if (!isEmpty()) {
845ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    mResults = context.getContentResolver().applyBatch(
846ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            ContactsContract.AUTHORITY, this);
847ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                }
848ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            } catch (RemoteException e) {
849ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                // There is nothing sensible to be done here
850ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                LogUtils.e(TAG, "problem inserting contact during server update", e);
851ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            } catch (OperationApplicationException e) {
852ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                // There is nothing sensible to be done here
853ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                LogUtils.e(TAG, "problem inserting contact during server update", e);
8540c0fdc5dfe605eb4b2047d4a7a89bcce5b2aa813Jay Shrauner            } catch (IllegalArgumentException e) {
8550c0fdc5dfe605eb4b2047d4a7a89bcce5b2aa813Jay Shrauner                // CP2 has been disabled
8560c0fdc5dfe605eb4b2047d4a7a89bcce5b2aa813Jay Shrauner                LogUtils.e(TAG, "CP2 is disabled; unable to insert contact.");
857ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
858ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
859ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
860ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        /**
861ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * Given the list of NamedContentValues for an entity, a mime type, and a subtype,
862ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * tries to find a match, returning it
863ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param list the list of NCV's from the contact entity
864ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param contentItemType the mime type we're looking for
865ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param type the subtype (e.g. HOME, WORK, etc.)
866ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @return the matching NCV or null if not found
867ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         */
868ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        private static NamedContentValues findTypedData(ArrayList<NamedContentValues> list,
869ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                String contentItemType, int type, String stringType) {
870ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            NamedContentValues result = null;
8716cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner            if (contentItemType == null) {
8726cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner                return result;
8736cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner            }
874ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
875ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Loop through the ncv's, looking for an existing row
876ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            for (NamedContentValues namedContentValues: list) {
8776cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner                final Uri uri = namedContentValues.uri;
8786cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner                final ContentValues cv = namedContentValues.values;
879ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                if (Data.CONTENT_URI.equals(uri)) {
8806cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner                    final String mimeType = cv.getAsString(Data.MIMETYPE);
8816cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner                    if (TextUtils.equals(mimeType, contentItemType)) {
882ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        if (stringType != null) {
883ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            if (cv.getAsString(GroupMembership.GROUP_ROW_ID).equals(stringType)) {
884ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                result = namedContentValues;
885ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            }
886ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        // Note Email.TYPE could be ANY type column; they are all defined in
887ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        // the private CommonColumns class in ContactsContract
888ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        // We'll accept either type < 0 (don't care), cv doesn't have a type,
889ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        // or the types are equal
890ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        } else if (type < 0 || !cv.containsKey(Email.TYPE) ||
891ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                cv.getAsInteger(Email.TYPE) == type) {
892ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            result = namedContentValues;
893ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        }
894ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    }
895ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                }
896ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
897ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
898ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // If we've found an existing data row, we'll delete it.  Any rows left at the
899ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // end should be deleted...
900ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (result != null) {
901ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                list.remove(result);
902ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
903ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
904ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Return the row found (or null)
905ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return result;
906ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
907ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
908ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        /**
909ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * Given the list of NamedContentValues for an entity and a mime type
910ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * gather all of the matching NCV's, returning them
911ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param list the list of NCV's from the contact entity
912ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param contentItemType the mime type we're looking for
913ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param type the subtype (e.g. HOME, WORK, etc.)
914ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @return the matching NCVs
915ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         */
916ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        private static ArrayList<NamedContentValues> findUntypedData(
917ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                ArrayList<NamedContentValues> list, int type, String contentItemType) {
9186cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner            final ArrayList<NamedContentValues> result = new ArrayList<NamedContentValues>();
9196cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner            if (contentItemType == null) {
9206cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner                return result;
9216cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner            }
922ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
923ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Loop through the ncv's, looking for an existing row
924ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            for (NamedContentValues namedContentValues: list) {
9256cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner                final Uri uri = namedContentValues.uri;
9266cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner                final ContentValues cv = namedContentValues.values;
927ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                if (Data.CONTENT_URI.equals(uri)) {
9286cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner                    final String mimeType = cv.getAsString(Data.MIMETYPE);
9296cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner                    if (TextUtils.equals(mimeType, contentItemType)) {
930ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        if (type != -1) {
9316cf9c927628e2d5d84f5983f4e1737e6e448485eJay Shrauner                            final int subtype = cv.getAsInteger(Phone.TYPE);
932ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            if (type != subtype) {
933ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                continue;
934ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            }
935ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        }
936ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        result.add(namedContentValues);
937ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    }
938ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                }
939ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
940ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
941ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // If we've found an existing data row, we'll delete it.  Any rows left at the
942ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // end should be deleted...
943ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            for (NamedContentValues values : result) {
944ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                list.remove(values);
945ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
946ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
947ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Return the row found (or null)
948ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return result;
949ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
950ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
951ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        /**
952ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * Create a wrapper for a builder (insert or update) that also includes the NCV for
953ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * an existing row of this type.   If the SmartBuilder's cv field is not null, then
954ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * it represents the current (old) values of this field.  The caller can then check
955ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * whether the field is now different and needs to be updated; if it's not different,
956ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * the caller will simply return and not generate a new CPO.  Otherwise, the builder
957ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * should have its content values set, and the built CPO should be added to the
958ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * ContactOperations list.
959ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         *
960ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param entity the contact entity (or null if this is a new contact)
961ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param mimeType the mime type of this row
962ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param type the subtype of this row
963ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param stringType for groups, the name of the group (type will be ignored), or null
964ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @return the created SmartBuilder
965ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         */
966ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public RowBuilder createBuilder(Entity entity, String mimeType, int type,
967ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                String stringType) {
968ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder = null;
969ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
970ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (entity != null) {
971ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                NamedContentValues ncv =
972ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    findTypedData(entity.getSubValues(), mimeType, type, stringType);
973ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                if (ncv != null) {
974ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    builder = new RowBuilder(
975ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            ContentProviderOperation
976ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                .newUpdate(addCallerIsSyncAdapterParameter(
977ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                    dataUriFromNamedContentValues(ncv))),
978ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                            ncv);
979ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                }
980ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
981ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
982ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (builder == null) {
983ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                builder = newRowBuilder(entity, mimeType);
984ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
985ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
986ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Return the appropriate builder (insert or update)
987ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Caller will fill in the appropriate values; 4 MIMETYPE is already set
988ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return builder;
989ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
990ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
991ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        private RowBuilder typedRowBuilder(Entity entity, String mimeType, int type) {
992ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return createBuilder(entity, mimeType, type, null);
993ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
994ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
995ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        private RowBuilder untypedRowBuilder(Entity entity, String mimeType) {
996ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return createBuilder(entity, mimeType, -1, null);
997ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
998ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
999ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        private RowBuilder newRowBuilder(Entity entity, String mimeType) {
1000ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // This is a new row; first get the contactId
1001ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // If the Contact is new, use the saved back value; otherwise the value in the entity
1002ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            int contactId = mContactBackValue;
1003ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (entity != null) {
1004ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                contactId = entity.getEntityValues().getAsInteger(RawContacts._ID);
1005ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1006ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1007ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Create an insert operation with the proper contactId reference
1008ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder =
1009ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                new RowBuilder(ContentProviderOperation.newInsert(
1010ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        addCallerIsSyncAdapterParameter(Data.CONTENT_URI)));
1011ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (entity == null) {
1012ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                builder.withValueBackReference(Data.RAW_CONTACT_ID, contactId);
1013ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            } else {
1014ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                builder.withValue(Data.RAW_CONTACT_ID, contactId);
1015ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1016ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1017ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Set the mime type of the row
1018ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Data.MIMETYPE, mimeType);
1019ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return builder;
1020ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1021ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1022ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        /**
1023ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * Compare a column in a ContentValues with an (old) value, and see if they are the
1024ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * same.  For this purpose, null and an empty string are considered the same.
1025ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param cv a ContentValues object, from a NamedContentValues
1026ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param column a column that might be in the ContentValues
1027ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @param oldValue an old value (or null) to check against
1028ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * @return whether the column's value in the ContentValues matches oldValue
1029ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         */
1030ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        private static boolean cvCompareString(ContentValues cv, String column, String oldValue) {
1031ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cv.containsKey(column)) {
1032ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                if (oldValue != null && cv.getAsString(column).equals(oldValue)) {
1033ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    return true;
1034ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                }
1035ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            } else if (oldValue == null || oldValue.length() == 0) {
1036ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return true;
1037ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1038ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            return false;
1039ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1040ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1041ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addChildren(Entity entity, ArrayList<String> children) {
1042ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder = untypedRowBuilder(entity, EasChildren.CONTENT_ITEM_TYPE);
1043ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            int i = 0;
1044ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            for (String child: children) {
1045ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                builder.withValue(EasChildren.ROWS[i++], child);
1046ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1047ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1048ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1049ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1050ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addGroup(Entity entity, String group) {
1051ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder =
1052ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                createBuilder(entity, GroupMembership.CONTENT_ITEM_TYPE, -1, group);
1053ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(GroupMembership.GROUP_SOURCE_ID, group);
1054ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1055ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1056ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1057ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addBirthday(Entity entity, String birthday) {
1058ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder =
1059ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    typedRowBuilder(entity, Event.CONTENT_ITEM_TYPE, Event.TYPE_BIRTHDAY);
1060ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ContentValues cv = builder.cv;
1061ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cv != null && cvCompareString(cv, Event.START_DATE, birthday)) {
1062ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1063ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1064ab9c23bcf59ec01a3dd79000b7b4136791a9db65Yu Ping Hu            // TODO: Store the date in the format expected by EAS servers.
10652f369a47e14916a34f49c79c0a246a2e3ac3072fJay Shrauner            final long millis;
10662f369a47e14916a34f49c79c0a246a2e3ac3072fJay Shrauner            try {
10672f369a47e14916a34f49c79c0a246a2e3ac3072fJay Shrauner                millis = Utility.parseEmailDateTimeToMillis(birthday);
10682f369a47e14916a34f49c79c0a246a2e3ac3072fJay Shrauner            } catch (ParseException e) {
10692f369a47e14916a34f49c79c0a246a2e3ac3072fJay Shrauner                LogUtils.w(TAG, "Parse error for birthday date field.", e);
10702f369a47e14916a34f49c79c0a246a2e3ac3072fJay Shrauner                return;
10712f369a47e14916a34f49c79c0a246a2e3ac3072fJay Shrauner            }
1072ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
1073ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            cal.setTimeInMillis(millis);
1074ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cal.get(GregorianCalendar.HOUR_OF_DAY) >= 12) {
1075ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                cal.add(GregorianCalendar.DATE, 1);
1076ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1077ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            String realBirthday = CalendarUtilities.calendarToBirthdayString(cal);
1078ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Event.START_DATE, realBirthday);
1079ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Event.TYPE, Event.TYPE_BIRTHDAY);
1080ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1081ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1082ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1083ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addName(Entity entity, String prefix, String givenName, String familyName,
1084ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                String middleName, String suffix, String yomiFirstName, String yomiLastName) {
1085ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder = untypedRowBuilder(entity, StructuredName.CONTENT_ITEM_TYPE);
1086ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ContentValues cv = builder.cv;
1087ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cv != null && cvCompareString(cv, StructuredName.GIVEN_NAME, givenName) &&
1088ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, StructuredName.FAMILY_NAME, familyName) &&
1089ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, StructuredName.MIDDLE_NAME, middleName) &&
1090ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, StructuredName.PREFIX, prefix) &&
1091ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, StructuredName.PHONETIC_GIVEN_NAME, yomiFirstName) &&
1092ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, StructuredName.PHONETIC_FAMILY_NAME, yomiLastName) &&
1093ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, StructuredName.SUFFIX, suffix)) {
1094ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1095ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1096ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredName.GIVEN_NAME, givenName);
1097ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredName.FAMILY_NAME, familyName);
1098ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredName.MIDDLE_NAME, middleName);
1099ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredName.SUFFIX, suffix);
1100ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredName.PHONETIC_GIVEN_NAME, yomiFirstName);
1101ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredName.PHONETIC_FAMILY_NAME, yomiLastName);
1102ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredName.PREFIX, prefix);
1103ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1104ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1105ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1106ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addPersonal(Entity entity, EasPersonal personal) {
1107ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder = untypedRowBuilder(entity, EasPersonal.CONTENT_ITEM_TYPE);
1108ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ContentValues cv = builder.cv;
1109ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cv != null && cvCompareString(cv, EasPersonal.ANNIVERSARY, personal.anniversary) &&
1110ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, EasPersonal.FILE_AS , personal.fileAs)) {
1111ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1112ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1113ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (!personal.hasData()) {
1114ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1115ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1116ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(EasPersonal.FILE_AS, personal.fileAs);
1117ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(EasPersonal.ANNIVERSARY, personal.anniversary);
1118ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1119ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1120ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1121ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addBusiness(Entity entity, EasBusiness business) {
1122ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder = untypedRowBuilder(entity, EasBusiness.CONTENT_ITEM_TYPE);
1123ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ContentValues cv = builder.cv;
1124ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cv != null && cvCompareString(cv, EasBusiness.ACCOUNT_NAME, business.accountName) &&
1125ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, EasBusiness.CUSTOMER_ID, business.customerId) &&
1126ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, EasBusiness.GOVERNMENT_ID, business.governmentId)) {
1127ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1128ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1129ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (!business.hasData()) {
1130ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1131ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1132ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(EasBusiness.ACCOUNT_NAME, business.accountName);
1133ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(EasBusiness.CUSTOMER_ID, business.customerId);
1134ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(EasBusiness.GOVERNMENT_ID, business.governmentId);
1135ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1136ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1137ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1138ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addPhoto(Entity entity, String photo) {
1139ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // We're always going to add this; it's not worth trying to figure out whether the
1140ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // picture is the same as the one stored.
11417c3686eae16af8c7873e114976c67f4c8b62bc60Jay Shrauner            final byte[] pic;
11427c3686eae16af8c7873e114976c67f4c8b62bc60Jay Shrauner            try {
11437c3686eae16af8c7873e114976c67f4c8b62bc60Jay Shrauner                pic = Base64.decode(photo, Base64.DEFAULT);
11447c3686eae16af8c7873e114976c67f4c8b62bc60Jay Shrauner            } catch (IllegalArgumentException e) {
11457c3686eae16af8c7873e114976c67f4c8b62bc60Jay Shrauner                LogUtils.w(TAG, "Bad base-64 encoding; unable to decode photo.");
11467c3686eae16af8c7873e114976c67f4c8b62bc60Jay Shrauner                return;
11477c3686eae16af8c7873e114976c67f4c8b62bc60Jay Shrauner            }
11487c3686eae16af8c7873e114976c67f4c8b62bc60Jay Shrauner
11497c3686eae16af8c7873e114976c67f4c8b62bc60Jay Shrauner            final RowBuilder builder = untypedRowBuilder(entity, Photo.CONTENT_ITEM_TYPE);
1150ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Photo.PHOTO, pic);
1151ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1152ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1153ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1154ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addPhone(Entity entity, int type, String phone) {
1155ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder = typedRowBuilder(entity, Phone.CONTENT_ITEM_TYPE, type);
1156ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ContentValues cv = builder.cv;
1157ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cv != null && cvCompareString(cv, Phone.NUMBER, phone)) {
1158ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1159ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1160ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Phone.TYPE, type);
1161ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Phone.NUMBER, phone);
1162ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1163ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1164ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1165ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addWebpage(Entity entity, String url) {
1166ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder = untypedRowBuilder(entity, Website.CONTENT_ITEM_TYPE);
1167ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ContentValues cv = builder.cv;
1168ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cv != null && cvCompareString(cv, Website.URL, url)) {
1169ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1170ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1171ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Website.TYPE, Website.TYPE_WORK);
1172ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Website.URL, url);
1173ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1174ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1175ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1176ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addRelation(Entity entity, int type, String value) {
1177ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder = typedRowBuilder(entity, Relation.CONTENT_ITEM_TYPE, type);
1178ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ContentValues cv = builder.cv;
1179ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cv != null && cvCompareString(cv, Relation.DATA, value)) {
1180ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1181ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1182ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Relation.TYPE, type);
1183ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Relation.DATA, value);
1184ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1185ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1186ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1187ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addNickname(Entity entity, String name) {
1188ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder =
1189ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                typedRowBuilder(entity, Nickname.CONTENT_ITEM_TYPE, Nickname.TYPE_DEFAULT);
1190ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ContentValues cv = builder.cv;
1191ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cv != null && cvCompareString(cv, Nickname.NAME, name)) {
1192ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1193ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1194ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Nickname.TYPE, Nickname.TYPE_DEFAULT);
1195ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Nickname.NAME, name);
1196ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1197ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1198ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1199ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addPostal(Entity entity, int type, String street, String city, String state,
1200ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                String country, String code) {
1201ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder = typedRowBuilder(entity, StructuredPostal.CONTENT_ITEM_TYPE,
1202ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    type);
1203ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ContentValues cv = builder.cv;
1204ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cv != null && cvCompareString(cv, StructuredPostal.CITY, city) &&
1205ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, StructuredPostal.STREET, street) &&
1206ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, StructuredPostal.COUNTRY, country) &&
1207ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, StructuredPostal.POSTCODE, code) &&
1208ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, StructuredPostal.REGION, state)) {
1209ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1210ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1211ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredPostal.TYPE, type);
1212ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredPostal.CITY, city);
1213ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredPostal.STREET, street);
1214ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredPostal.COUNTRY, country);
1215ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredPostal.POSTCODE, code);
1216ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(StructuredPostal.REGION, state);
1217ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1218ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1219ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1220ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon       /**
1221ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * We now are dealing with up to maxRows typeless rows of mimeType data.  We need to try to
1222ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * match them with existing rows; if there's a match, everything's great.  Otherwise, we
1223ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * either need to add a new row for the data, or we have to replace an existing one
1224ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         * that no longer matches.  This is similar to the way Emails are handled.
1225ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon         */
1226ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addUntyped(Entity entity, ArrayList<UntypedRow> rows, String mimeType,
1227ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                int type, int maxRows) {
1228ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Make a list of all same type rows in the existing entity
1229ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ArrayList<NamedContentValues> oldValues = EMPTY_ARRAY_NAMEDCONTENTVALUES;
1230ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ArrayList<NamedContentValues> entityValues = EMPTY_ARRAY_NAMEDCONTENTVALUES;
1231ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (entity != null) {
1232ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                oldValues = findUntypedData(entityValues, type, mimeType);
1233ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                entityValues = entity.getSubValues();
1234ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1235ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1236ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // These will be rows needing replacement with new values
1237ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ArrayList<UntypedRow> rowsToReplace = new ArrayList<UntypedRow>();
1238ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1239ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // The count of existing rows
1240ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            int numRows = oldValues.size();
1241ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            for (UntypedRow row: rows) {
1242ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                boolean found = false;
1243ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                // If we already have this row, mark it
1244ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                for (NamedContentValues ncv: oldValues) {
1245ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ContentValues cv = ncv.values;
1246ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    String data = cv.getAsString(COMMON_DATA_ROW);
1247ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    int rowType = -1;
1248ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    if (cv.containsKey(COMMON_TYPE_ROW)) {
1249ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        rowType = cv.getAsInteger(COMMON_TYPE_ROW);
1250ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    }
1251ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    if (row.isSameAs(rowType, data)) {
1252ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        cv.put(FOUND_DATA_ROW, true);
1253ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        // Remove this to indicate it's still being used
1254ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        entityValues.remove(ncv);
1255ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        found = true;
1256ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        break;
1257ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    }
1258ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                }
1259ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                if (!found) {
1260ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    // If we don't, there are two possibilities
1261ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    if (numRows < maxRows) {
1262ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        // If there are available rows, add a new one
1263ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        RowBuilder builder = newRowBuilder(entity, mimeType);
1264ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        row.addValues(builder);
1265ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        add(builder.build());
1266ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        numRows++;
1267ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    } else {
1268ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        // Otherwise, say we need to replace a row with this
1269ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        rowsToReplace.add(row);
1270ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    }
1271ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                }
1272ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1273ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1274ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Go through rows needing replacement
1275ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            for (UntypedRow row: rowsToReplace) {
1276ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                for (NamedContentValues ncv: oldValues) {
1277ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    ContentValues cv = ncv.values;
1278ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    // Find a row that hasn't been used (i.e. doesn't match current rows)
1279ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    if (!cv.containsKey(FOUND_DATA_ROW)) {
1280ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        // And update it
1281ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        RowBuilder builder = new RowBuilder(
1282ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                ContentProviderOperation
1283ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                    .newUpdate(addCallerIsSyncAdapterParameter(
1284ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                        dataUriFromNamedContentValues(ncv))),
1285ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                                ncv);
1286ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        row.addValues(builder);
1287ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                        add(builder.build());
1288ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    }
1289ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                }
1290ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1291ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1292ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1293ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addOrganization(Entity entity, int type, String company, String title,
1294ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                String department, String yomiCompanyName, String officeLocation) {
1295ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder = typedRowBuilder(entity, Organization.CONTENT_ITEM_TYPE, type);
1296ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ContentValues cv = builder.cv;
1297ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cv != null && cvCompareString(cv, Organization.COMPANY, company) &&
1298ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, Organization.PHONETIC_NAME, yomiCompanyName) &&
1299ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, Organization.DEPARTMENT, department) &&
1300ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, Organization.TITLE, title) &&
1301ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    cvCompareString(cv, Organization.OFFICE_LOCATION, officeLocation)) {
1302ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1303ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1304ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Organization.TYPE, type);
1305ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Organization.COMPANY, company);
1306ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Organization.TITLE, title);
1307ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Organization.DEPARTMENT, department);
1308ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Organization.PHONETIC_NAME, yomiCompanyName);
1309ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Organization.OFFICE_LOCATION, officeLocation);
1310ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1311ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1312ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1313ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        public void addNote(Entity entity, String note) {
1314ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            RowBuilder builder = typedRowBuilder(entity, Note.CONTENT_ITEM_TYPE, -1);
1315ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            ContentValues cv = builder.cv;
1316ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (note == null) return;
1317ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            note = note.replaceAll("\r\n", "\n");
1318ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (cv != null && cvCompareString(cv, Note.NOTE, note)) {
1319ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                return;
1320ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1321ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1322ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // Reject notes with nothing in them.  Often, we get something from Outlook when
1323ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            // nothing was ever entered.  Sigh.
1324ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            int len = note.length();
1325ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            int i = 0;
1326ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            for (; i < len; i++) {
1327ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                char c = note.charAt(i);
1328ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                if (!Character.isWhitespace(c)) {
1329ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                    break;
1330ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon                }
1331ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            }
1332ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            if (i == len) return;
1333ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon
1334ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            builder.withValue(Note.NOTE, note);
1335ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon            add(builder.build());
1336ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon        }
1337ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon    }
133828f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon
133928f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon    @Override
134028f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon    protected void wipe() {
134128f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon        LogUtils.w(TAG, "Wiping contacts for account %d", mAccount.mId);
1342f4195d389ffd4d92e37cd1d01db1713180740291Yu Ping Hu        EasSyncContacts.wipeAccountFromContentProvider(mContext,
134328f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon                mAccount.mEmailAddress);
134428f3556f92b20b2efb800c1d95c29b04a3bbbb4fMartin Hibdon    }
1345ff9fed5ccdd57d5408e759f0ca6c41e79e09e999Martin Hibdon}
1346