blob: 400b0e9b4435bb126c7fe12a839222c9c00b8d8e [file] [log] [blame]
Chiao Chenge88fcd32012-11-13 18:38:05 -08001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.contacts.common.model.account;
18
19import android.content.ContentValues;
20import android.content.Context;
21import android.content.res.Resources;
yaolu1bd88262016-08-18 10:29:12 -070022import android.provider.ContactsContract.Data;
Chiao Chenge88fcd32012-11-13 18:38:05 -080023import android.provider.ContactsContract.CommonDataKinds.BaseTypes;
24import android.provider.ContactsContract.CommonDataKinds.Email;
25import android.provider.ContactsContract.CommonDataKinds.Event;
26import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
27import android.provider.ContactsContract.CommonDataKinds.Im;
28import android.provider.ContactsContract.CommonDataKinds.Nickname;
29import android.provider.ContactsContract.CommonDataKinds.Note;
30import android.provider.ContactsContract.CommonDataKinds.Organization;
31import android.provider.ContactsContract.CommonDataKinds.Phone;
32import android.provider.ContactsContract.CommonDataKinds.Photo;
33import android.provider.ContactsContract.CommonDataKinds.Relation;
34import android.provider.ContactsContract.CommonDataKinds.SipAddress;
35import android.provider.ContactsContract.CommonDataKinds.StructuredName;
36import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
37import android.provider.ContactsContract.CommonDataKinds.Website;
38import android.util.AttributeSet;
39import android.util.Log;
40import android.view.inputmethod.EditorInfo;
41
42import com.android.contacts.common.R;
yaolu1bd88262016-08-18 10:29:12 -070043import com.android.contacts.common.model.dataitem.CustomDataItem;
Chiao Chenge88fcd32012-11-13 18:38:05 -080044import com.android.contacts.common.model.dataitem.DataKind;
Chiao Chenge88fcd32012-11-13 18:38:05 -080045import com.android.contacts.common.util.CommonDateUtils;
46import com.android.contacts.common.util.ContactDisplayUtils;
47import com.google.common.collect.Lists;
48import com.google.common.collect.Maps;
49
50import org.xmlpull.v1.XmlPullParser;
51import org.xmlpull.v1.XmlPullParserException;
52
53import java.io.IOException;
54import java.util.List;
55import java.util.Locale;
56import java.util.Map;
57
58public abstract class BaseAccountType extends AccountType {
59 private static final String TAG = "BaseAccountType";
60
61 protected static final int FLAGS_PHONE = EditorInfo.TYPE_CLASS_PHONE;
62 protected static final int FLAGS_EMAIL = EditorInfo.TYPE_CLASS_TEXT
63 | EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
64 protected static final int FLAGS_PERSON_NAME = EditorInfo.TYPE_CLASS_TEXT
65 | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS | EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME;
66 protected static final int FLAGS_PHONETIC = EditorInfo.TYPE_CLASS_TEXT
67 | EditorInfo.TYPE_TEXT_VARIATION_PHONETIC;
68 protected static final int FLAGS_GENERIC_NAME = EditorInfo.TYPE_CLASS_TEXT
69 | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
70 protected static final int FLAGS_NOTE = EditorInfo.TYPE_CLASS_TEXT
71 | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
72 protected static final int FLAGS_EVENT = EditorInfo.TYPE_CLASS_TEXT;
73 protected static final int FLAGS_WEBSITE = EditorInfo.TYPE_CLASS_TEXT
74 | EditorInfo.TYPE_TEXT_VARIATION_URI;
75 protected static final int FLAGS_POSTAL = EditorInfo.TYPE_CLASS_TEXT
76 | EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS
77 | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
78 protected static final int FLAGS_SIP_ADDRESS = EditorInfo.TYPE_CLASS_TEXT
79 | EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS; // since SIP addresses have the same
80 // basic format as email addresses
81 protected static final int FLAGS_RELATION = EditorInfo.TYPE_CLASS_TEXT
82 | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS | EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME;
83
84 // Specify the maximum number of lines that can be used to display various field types. If no
85 // value is specified for a particular type, we use the default value from {@link DataKind}.
86 protected static final int MAX_LINES_FOR_POSTAL_ADDRESS = 10;
87 protected static final int MAX_LINES_FOR_GROUP = 10;
88 protected static final int MAX_LINES_FOR_NOTE = 100;
89
90 private interface Tag {
91 static final String DATA_KIND = "DataKind";
92 static final String TYPE = "Type";
93 }
94
95 private interface Attr {
96 static final String MAX_OCCURRENCE = "maxOccurs";
97 static final String DATE_WITH_TIME = "dateWithTime";
98 static final String YEAR_OPTIONAL = "yearOptional";
99 static final String KIND = "kind";
100 static final String TYPE = "type";
101 }
102
Brian Attwell913e18a2014-10-30 11:16:05 -0700103 protected interface Weight {
Chiao Chenge88fcd32012-11-13 18:38:05 -0800104 static final int NONE = -1;
Chiao Chenge88fcd32012-11-13 18:38:05 -0800105 static final int PHONE = 10;
106 static final int EMAIL = 15;
Chiao Chenge88fcd32012-11-13 18:38:05 -0800107 static final int STRUCTURED_POSTAL = 25;
Brian Attwell913e18a2014-10-30 11:16:05 -0700108 static final int NICKNAME = 111;
109 static final int EVENT = 120;
110 static final int ORGANIZATION = 125;
111 static final int NOTE = 130;
112 static final int IM = 140;
113 static final int SIP_ADDRESS = 145;
114 static final int GROUP_MEMBERSHIP = 150;
115 static final int WEBSITE = 160;
116 static final int RELATIONSHIP = 999;
Chiao Chenge88fcd32012-11-13 18:38:05 -0800117 }
118
119 public BaseAccountType() {
120 this.accountType = null;
121 this.dataSet = null;
122 this.titleRes = R.string.account_phone;
Walter Jangb1414622016-01-14 12:19:27 -0800123 this.iconRes = R.mipmap.ic_contacts_launcher;
Chiao Chenge88fcd32012-11-13 18:38:05 -0800124 }
125
126 protected static EditType buildPhoneType(int type) {
127 return new EditType(type, Phone.getTypeLabelResource(type));
128 }
129
130 protected static EditType buildEmailType(int type) {
131 return new EditType(type, Email.getTypeLabelResource(type));
132 }
133
134 protected static EditType buildPostalType(int type) {
135 return new EditType(type, StructuredPostal.getTypeLabelResource(type));
136 }
137
138 protected static EditType buildImType(int type) {
139 return new EditType(type, Im.getProtocolLabelResource(type));
140 }
141
142 protected static EditType buildEventType(int type, boolean yearOptional) {
143 return new EventEditType(type, Event.getTypeResource(type)).setYearOptional(yearOptional);
144 }
145
146 protected static EditType buildRelationType(int type) {
147 return new EditType(type, Relation.getTypeLabelResource(type));
148 }
149
150 protected DataKind addDataKindStructuredName(Context context) throws DefinitionException {
Gary Mai698cee72016-09-19 16:09:54 -0700151 final DataKind kind = addKind(new DataKind(StructuredName.CONTENT_ITEM_TYPE,
Brian Attwell913e18a2014-10-30 11:16:05 -0700152 R.string.nameLabelsGroup, Weight.NONE, true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800153 kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
154 kind.actionBody = new SimpleInflater(Nickname.NAME);
155 kind.typeOverallMax = 1;
156
157 kind.fieldList = Lists.newArrayList();
Gary Mai7a6daea2016-10-10 15:41:48 -0700158 kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
159 FLAGS_PERSON_NAME).setLongForm(true));
160 kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
161 FLAGS_PERSON_NAME));
162 kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
163 FLAGS_PERSON_NAME).setLongForm(true));
164 kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
165 FLAGS_PERSON_NAME));
166 kind.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
167 FLAGS_PERSON_NAME).setLongForm(true));
168 kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
169 R.string.name_phonetic_family, FLAGS_PHONETIC));
170 kind.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
171 R.string.name_phonetic_middle, FLAGS_PHONETIC));
172 kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
173 R.string.name_phonetic_given, FLAGS_PHONETIC));
174
175 return kind;
176 }
177
178 protected DataKind addDataKindName(Context context) throws DefinitionException {
179 final DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_NAME,
180 R.string.nameLabelsGroup, Weight.NONE, true));
181 kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
182 kind.actionBody = new SimpleInflater(Nickname.NAME);
183 kind.typeOverallMax = 1;
184
185 kind.fieldList = Lists.newArrayList();
Gary Mai698cee72016-09-19 16:09:54 -0700186 final boolean displayOrderPrimary =
Chiao Chenge88fcd32012-11-13 18:38:05 -0800187 context.getResources().getBoolean(R.bool.config_editor_field_order_primary);
188
Gary Mai698cee72016-09-19 16:09:54 -0700189 kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
yaolu69765492016-11-07 11:01:27 -0800190 FLAGS_PERSON_NAME).setOptional(true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800191 if (!displayOrderPrimary) {
Chiao Chenge88fcd32012-11-13 18:38:05 -0800192 kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
Gary Mai698cee72016-09-19 16:09:54 -0700193 FLAGS_PERSON_NAME));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800194 kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
yaolu69765492016-11-07 11:01:27 -0800195 FLAGS_PERSON_NAME).setOptional(true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800196 kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
Gary Mai698cee72016-09-19 16:09:54 -0700197 FLAGS_PERSON_NAME));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800198 } else {
Chiao Chenge88fcd32012-11-13 18:38:05 -0800199 kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
Gary Mai698cee72016-09-19 16:09:54 -0700200 FLAGS_PERSON_NAME));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800201 kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
yaolu69765492016-11-07 11:01:27 -0800202 FLAGS_PERSON_NAME).setOptional(true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800203 kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
Gary Mai698cee72016-09-19 16:09:54 -0700204 FLAGS_PERSON_NAME));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800205 }
Gary Mai698cee72016-09-19 16:09:54 -0700206 kind.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
yaolu69765492016-11-07 11:01:27 -0800207 FLAGS_PERSON_NAME).setOptional(true));
Gary Mai698cee72016-09-19 16:09:54 -0700208
Chiao Chenge88fcd32012-11-13 18:38:05 -0800209 return kind;
210 }
211
212 protected DataKind addDataKindPhoneticName(Context context) throws DefinitionException {
213 DataKind kind = addKind(new DataKind(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME,
Brian Attwell913e18a2014-10-30 11:16:05 -0700214 R.string.name_phonetic, Weight.NONE, true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800215 kind.actionHeader = new SimpleInflater(R.string.nameLabelsGroup);
216 kind.actionBody = new SimpleInflater(Nickname.NAME);
217 kind.typeOverallMax = 1;
218
219 kind.fieldList = Lists.newArrayList();
220 kind.fieldList.add(new EditField(DataKind.PSEUDO_COLUMN_PHONETIC_NAME,
221 R.string.name_phonetic, FLAGS_PHONETIC).setShortForm(true));
222 kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
223 R.string.name_phonetic_family, FLAGS_PHONETIC).setLongForm(true));
224 kind.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
225 R.string.name_phonetic_middle, FLAGS_PHONETIC).setLongForm(true));
226 kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
227 R.string.name_phonetic_given, FLAGS_PHONETIC).setLongForm(true));
228
229 return kind;
230 }
231
232 protected DataKind addDataKindNickname(Context context) throws DefinitionException {
233 DataKind kind = addKind(new DataKind(Nickname.CONTENT_ITEM_TYPE,
Brian Attwell913e18a2014-10-30 11:16:05 -0700234 R.string.nicknameLabelsGroup, Weight.NICKNAME, true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800235 kind.typeOverallMax = 1;
236 kind.actionHeader = new SimpleInflater(R.string.nicknameLabelsGroup);
237 kind.actionBody = new SimpleInflater(Nickname.NAME);
238 kind.defaultValues = new ContentValues();
239 kind.defaultValues.put(Nickname.TYPE, Nickname.TYPE_DEFAULT);
240
241 kind.fieldList = Lists.newArrayList();
242 kind.fieldList.add(new EditField(Nickname.NAME, R.string.nicknameLabelsGroup,
243 FLAGS_PERSON_NAME));
244
245 return kind;
246 }
247
248 protected DataKind addDataKindPhone(Context context) throws DefinitionException {
249 DataKind kind = addKind(new DataKind(Phone.CONTENT_ITEM_TYPE, R.string.phoneLabelsGroup,
Brian Attwell913e18a2014-10-30 11:16:05 -0700250 Weight.PHONE, true));
Walter Jang353570e2016-05-04 17:43:56 -0700251 kind.iconAltRes = R.drawable.ic_message_24dp_mirrored;
Chiao Chenge88fcd32012-11-13 18:38:05 -0800252 kind.iconAltDescriptionRes = R.string.sms;
253 kind.actionHeader = new PhoneActionInflater();
254 kind.actionAltHeader = new PhoneActionAltInflater();
255 kind.actionBody = new SimpleInflater(Phone.NUMBER);
256 kind.typeColumn = Phone.TYPE;
257 kind.typeList = Lists.newArrayList();
258 kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE));
259 kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));
260 kind.typeList.add(buildPhoneType(Phone.TYPE_WORK));
261 kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_WORK).setSecondary(true));
262 kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_HOME).setSecondary(true));
263 kind.typeList.add(buildPhoneType(Phone.TYPE_PAGER).setSecondary(true));
264 kind.typeList.add(buildPhoneType(Phone.TYPE_OTHER));
265 kind.typeList.add(
266 buildPhoneType(Phone.TYPE_CUSTOM).setSecondary(true).setCustomColumn(Phone.LABEL));
267 kind.typeList.add(buildPhoneType(Phone.TYPE_CALLBACK).setSecondary(true));
268 kind.typeList.add(buildPhoneType(Phone.TYPE_CAR).setSecondary(true));
269 kind.typeList.add(buildPhoneType(Phone.TYPE_COMPANY_MAIN).setSecondary(true));
270 kind.typeList.add(buildPhoneType(Phone.TYPE_ISDN).setSecondary(true));
271 kind.typeList.add(buildPhoneType(Phone.TYPE_MAIN).setSecondary(true));
272 kind.typeList.add(buildPhoneType(Phone.TYPE_OTHER_FAX).setSecondary(true));
273 kind.typeList.add(buildPhoneType(Phone.TYPE_RADIO).setSecondary(true));
274 kind.typeList.add(buildPhoneType(Phone.TYPE_TELEX).setSecondary(true));
275 kind.typeList.add(buildPhoneType(Phone.TYPE_TTY_TDD).setSecondary(true));
276 kind.typeList.add(buildPhoneType(Phone.TYPE_WORK_MOBILE).setSecondary(true));
277 kind.typeList.add(buildPhoneType(Phone.TYPE_WORK_PAGER).setSecondary(true));
278 kind.typeList.add(buildPhoneType(Phone.TYPE_ASSISTANT).setSecondary(true));
279 kind.typeList.add(buildPhoneType(Phone.TYPE_MMS).setSecondary(true));
280
281 kind.fieldList = Lists.newArrayList();
282 kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE));
283
284 return kind;
285 }
286
287 protected DataKind addDataKindEmail(Context context) throws DefinitionException {
288 DataKind kind = addKind(new DataKind(Email.CONTENT_ITEM_TYPE, R.string.emailLabelsGroup,
Brian Attwell913e18a2014-10-30 11:16:05 -0700289 Weight.EMAIL, true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800290 kind.actionHeader = new EmailActionInflater();
291 kind.actionBody = new SimpleInflater(Email.DATA);
292 kind.typeColumn = Email.TYPE;
293 kind.typeList = Lists.newArrayList();
294 kind.typeList.add(buildEmailType(Email.TYPE_HOME));
295 kind.typeList.add(buildEmailType(Email.TYPE_WORK));
296 kind.typeList.add(buildEmailType(Email.TYPE_OTHER));
297 kind.typeList.add(buildEmailType(Email.TYPE_MOBILE));
298 kind.typeList.add(
299 buildEmailType(Email.TYPE_CUSTOM).setSecondary(true).setCustomColumn(Email.LABEL));
300
301 kind.fieldList = Lists.newArrayList();
302 kind.fieldList.add(new EditField(Email.DATA, R.string.emailLabelsGroup, FLAGS_EMAIL));
303
304 return kind;
305 }
306
307 protected DataKind addDataKindStructuredPostal(Context context) throws DefinitionException {
308 DataKind kind = addKind(new DataKind(StructuredPostal.CONTENT_ITEM_TYPE,
Brian Attwell913e18a2014-10-30 11:16:05 -0700309 R.string.postalLabelsGroup, Weight.STRUCTURED_POSTAL, true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800310 kind.actionHeader = new PostalActionInflater();
311 kind.actionBody = new SimpleInflater(StructuredPostal.FORMATTED_ADDRESS);
312 kind.typeColumn = StructuredPostal.TYPE;
313 kind.typeList = Lists.newArrayList();
314 kind.typeList.add(buildPostalType(StructuredPostal.TYPE_HOME));
315 kind.typeList.add(buildPostalType(StructuredPostal.TYPE_WORK));
316 kind.typeList.add(buildPostalType(StructuredPostal.TYPE_OTHER));
317 kind.typeList.add(buildPostalType(StructuredPostal.TYPE_CUSTOM).setSecondary(true)
318 .setCustomColumn(StructuredPostal.LABEL));
319
320 kind.fieldList = Lists.newArrayList();
321 kind.fieldList.add(
322 new EditField(StructuredPostal.FORMATTED_ADDRESS, R.string.postal_address,
323 FLAGS_POSTAL));
324
325 kind.maxLinesForDisplay = MAX_LINES_FOR_POSTAL_ADDRESS;
326
327 return kind;
328 }
329
330 protected DataKind addDataKindIm(Context context) throws DefinitionException {
Brian Attwell913e18a2014-10-30 11:16:05 -0700331 DataKind kind = addKind(new DataKind(Im.CONTENT_ITEM_TYPE, R.string.imLabelsGroup,
332 Weight.IM, true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800333 kind.actionHeader = new ImActionInflater();
334 kind.actionBody = new SimpleInflater(Im.DATA);
335
336 // NOTE: even though a traditional "type" exists, for editing
337 // purposes we're using the protocol to pick labels
338
339 kind.defaultValues = new ContentValues();
340 kind.defaultValues.put(Im.TYPE, Im.TYPE_OTHER);
341
342 kind.typeColumn = Im.PROTOCOL;
343 kind.typeList = Lists.newArrayList();
344 kind.typeList.add(buildImType(Im.PROTOCOL_AIM));
345 kind.typeList.add(buildImType(Im.PROTOCOL_MSN));
346 kind.typeList.add(buildImType(Im.PROTOCOL_YAHOO));
347 kind.typeList.add(buildImType(Im.PROTOCOL_SKYPE));
348 kind.typeList.add(buildImType(Im.PROTOCOL_QQ));
349 kind.typeList.add(buildImType(Im.PROTOCOL_GOOGLE_TALK));
350 kind.typeList.add(buildImType(Im.PROTOCOL_ICQ));
351 kind.typeList.add(buildImType(Im.PROTOCOL_JABBER));
352 kind.typeList.add(buildImType(Im.PROTOCOL_CUSTOM).setSecondary(true).setCustomColumn(
353 Im.CUSTOM_PROTOCOL));
354
355 kind.fieldList = Lists.newArrayList();
356 kind.fieldList.add(new EditField(Im.DATA, R.string.imLabelsGroup, FLAGS_EMAIL));
357
358 return kind;
359 }
360
361 protected DataKind addDataKindOrganization(Context context) throws DefinitionException {
362 DataKind kind = addKind(new DataKind(Organization.CONTENT_ITEM_TYPE,
Brian Attwell913e18a2014-10-30 11:16:05 -0700363 R.string.organizationLabelsGroup, Weight.ORGANIZATION, true));
Paul Soulos17f639c2014-07-23 13:33:25 -0700364 kind.actionHeader = new SimpleInflater(R.string.organizationLabelsGroup);
365 kind.actionBody = ORGANIZATION_BODY_INFLATER;
Chiao Chenge88fcd32012-11-13 18:38:05 -0800366 kind.typeOverallMax = 1;
367
368 kind.fieldList = Lists.newArrayList();
369 kind.fieldList.add(new EditField(Organization.COMPANY, R.string.ghostData_company,
370 FLAGS_GENERIC_NAME));
371 kind.fieldList.add(new EditField(Organization.TITLE, R.string.ghostData_title,
372 FLAGS_GENERIC_NAME));
373
374 return kind;
375 }
376
377 protected DataKind addDataKindPhoto(Context context) throws DefinitionException {
Brian Attwell913e18a2014-10-30 11:16:05 -0700378 DataKind kind = addKind(new DataKind(Photo.CONTENT_ITEM_TYPE, -1, Weight.NONE, true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800379 kind.typeOverallMax = 1;
380 kind.fieldList = Lists.newArrayList();
381 kind.fieldList.add(new EditField(Photo.PHOTO, -1, -1));
382 return kind;
383 }
384
385 protected DataKind addDataKindNote(Context context) throws DefinitionException {
Brian Attwell913e18a2014-10-30 11:16:05 -0700386 DataKind kind = addKind(new DataKind(Note.CONTENT_ITEM_TYPE, R.string.label_notes,
387 Weight.NOTE, true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800388 kind.typeOverallMax = 1;
389 kind.actionHeader = new SimpleInflater(R.string.label_notes);
390 kind.actionBody = new SimpleInflater(Note.NOTE);
391 kind.fieldList = Lists.newArrayList();
392 kind.fieldList.add(new EditField(Note.NOTE, R.string.label_notes, FLAGS_NOTE));
393
394 kind.maxLinesForDisplay = MAX_LINES_FOR_NOTE;
395
396 return kind;
397 }
398
399 protected DataKind addDataKindWebsite(Context context) throws DefinitionException {
400 DataKind kind = addKind(new DataKind(Website.CONTENT_ITEM_TYPE,
Brian Attwell913e18a2014-10-30 11:16:05 -0700401 R.string.websiteLabelsGroup, Weight.WEBSITE, true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800402 kind.actionHeader = new SimpleInflater(R.string.websiteLabelsGroup);
403 kind.actionBody = new SimpleInflater(Website.URL);
404 kind.defaultValues = new ContentValues();
405 kind.defaultValues.put(Website.TYPE, Website.TYPE_OTHER);
406
407 kind.fieldList = Lists.newArrayList();
408 kind.fieldList.add(new EditField(Website.URL, R.string.websiteLabelsGroup, FLAGS_WEBSITE));
409
410 return kind;
411 }
412
413 protected DataKind addDataKindSipAddress(Context context) throws DefinitionException {
414 DataKind kind = addKind(new DataKind(SipAddress.CONTENT_ITEM_TYPE,
Brian Attwell913e18a2014-10-30 11:16:05 -0700415 R.string.label_sip_address, Weight.SIP_ADDRESS, true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800416
Chiao Chenge88fcd32012-11-13 18:38:05 -0800417 kind.actionHeader = new SimpleInflater(R.string.label_sip_address);
418 kind.actionBody = new SimpleInflater(SipAddress.SIP_ADDRESS);
419 kind.fieldList = Lists.newArrayList();
420 kind.fieldList.add(new EditField(SipAddress.SIP_ADDRESS,
421 R.string.label_sip_address, FLAGS_SIP_ADDRESS));
Walter Jang8df87f12015-07-10 12:19:24 -0700422 kind.typeOverallMax = 1;
Chiao Chenge88fcd32012-11-13 18:38:05 -0800423
424 return kind;
425 }
426
427 protected DataKind addDataKindGroupMembership(Context context) throws DefinitionException {
428 DataKind kind = addKind(new DataKind(GroupMembership.CONTENT_ITEM_TYPE,
Brian Attwell913e18a2014-10-30 11:16:05 -0700429 R.string.groupsLabel, Weight.GROUP_MEMBERSHIP, true));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800430
431 kind.typeOverallMax = 1;
432 kind.fieldList = Lists.newArrayList();
433 kind.fieldList.add(new EditField(GroupMembership.GROUP_ROW_ID, -1, -1));
434
435 kind.maxLinesForDisplay = MAX_LINES_FOR_GROUP;
436
437 return kind;
438 }
439
yaolu1bd88262016-08-18 10:29:12 -0700440 protected DataKind addDataKindCustomField(Context context) throws DefinitionException {
441 final DataKind kind = addKind(new DataKind(CustomDataItem.MIMETYPE_CUSTOM_FIELD,
442 R.string.label_custom_field, Weight.NONE, /* editable */ false));
443 kind.actionBody = new SimpleInflater(Data.DATA2);
444 return kind;
445 }
446
Chiao Chenge88fcd32012-11-13 18:38:05 -0800447 /**
448 * Simple inflater that assumes a string resource has a "%s" that will be
449 * filled from the given column.
450 */
451 public static class SimpleInflater implements StringInflater {
452 private final int mStringRes;
453 private final String mColumnName;
454
455 public SimpleInflater(int stringRes) {
456 this(stringRes, null);
457 }
458
459 public SimpleInflater(String columnName) {
460 this(-1, columnName);
461 }
462
463 public SimpleInflater(int stringRes, String columnName) {
464 mStringRes = stringRes;
465 mColumnName = columnName;
466 }
467
468 @Override
469 public CharSequence inflateUsing(Context context, ContentValues values) {
470 final boolean validColumn = values.containsKey(mColumnName);
471 final boolean validString = mStringRes > 0;
472
473 final CharSequence stringValue = validString ? context.getText(mStringRes) : null;
474 final CharSequence columnValue = validColumn ? values.getAsString(mColumnName) : null;
475
476 if (validString && validColumn) {
477 return String.format(stringValue.toString(), columnValue);
478 } else if (validString) {
479 return stringValue;
480 } else if (validColumn) {
481 return columnValue;
482 } else {
483 return null;
484 }
485 }
486
487 @Override
488 public String toString() {
489 return this.getClass().getSimpleName()
490 + " mStringRes=" + mStringRes
491 + " mColumnName" + mColumnName;
492 }
493
Chiao Chenge88fcd32012-11-13 18:38:05 -0800494 public String getColumnNameForTest() {
495 return mColumnName;
496 }
497 }
498
499 public static abstract class CommonInflater implements StringInflater {
500 protected abstract int getTypeLabelResource(Integer type);
501
502 protected boolean isCustom(Integer type) {
503 return type == BaseTypes.TYPE_CUSTOM;
504 }
505
506 protected String getTypeColumn() {
507 return Phone.TYPE;
508 }
509
510 protected String getLabelColumn() {
511 return Phone.LABEL;
512 }
513
514 protected CharSequence getTypeLabel(Resources res, Integer type, CharSequence label) {
515 final int labelRes = getTypeLabelResource(type);
516 if (type == null) {
517 return res.getText(labelRes);
518 } else if (isCustom(type)) {
519 return res.getString(labelRes, label == null ? "" : label);
520 } else {
521 return res.getText(labelRes);
522 }
523 }
524
525 @Override
526 public CharSequence inflateUsing(Context context, ContentValues values) {
527 final Integer type = values.getAsInteger(getTypeColumn());
528 final String label = values.getAsString(getLabelColumn());
529 return getTypeLabel(context.getResources(), type, label);
530 }
531
532 @Override
533 public String toString() {
534 return this.getClass().getSimpleName();
535 }
536 }
537
538 public static class PhoneActionInflater extends CommonInflater {
539 @Override
540 protected boolean isCustom(Integer type) {
541 return ContactDisplayUtils.isCustomPhoneType(type);
542 }
543
544 @Override
545 protected int getTypeLabelResource(Integer type) {
546 return ContactDisplayUtils.getPhoneLabelResourceId(type);
547 }
548 }
549
550 public static class PhoneActionAltInflater extends CommonInflater {
551 @Override
552 protected boolean isCustom(Integer type) {
553 return ContactDisplayUtils.isCustomPhoneType(type);
554 }
555
556 @Override
557 protected int getTypeLabelResource(Integer type) {
558 return ContactDisplayUtils.getSmsLabelResourceId(type);
559 }
560 }
561
562 public static class EmailActionInflater extends CommonInflater {
563 @Override
564 protected int getTypeLabelResource(Integer type) {
565 if (type == null) return R.string.email;
566 switch (type) {
567 case Email.TYPE_HOME: return R.string.email_home;
568 case Email.TYPE_WORK: return R.string.email_work;
569 case Email.TYPE_OTHER: return R.string.email_other;
570 case Email.TYPE_MOBILE: return R.string.email_mobile;
571 default: return R.string.email_custom;
572 }
573 }
574 }
575
576 public static class EventActionInflater extends CommonInflater {
577 @Override
578 protected int getTypeLabelResource(Integer type) {
579 return Event.getTypeResource(type);
580 }
581 }
582
583 public static class RelationActionInflater extends CommonInflater {
584 @Override
585 protected int getTypeLabelResource(Integer type) {
586 return Relation.getTypeLabelResource(type == null ? Relation.TYPE_CUSTOM : type);
587 }
588 }
589
590 public static class PostalActionInflater extends CommonInflater {
591 @Override
592 protected int getTypeLabelResource(Integer type) {
593 if (type == null) return R.string.map_other;
594 switch (type) {
595 case StructuredPostal.TYPE_HOME: return R.string.map_home;
596 case StructuredPostal.TYPE_WORK: return R.string.map_work;
597 case StructuredPostal.TYPE_OTHER: return R.string.map_other;
598 default: return R.string.map_custom;
599 }
600 }
601 }
602
603 public static class ImActionInflater extends CommonInflater {
604 @Override
605 protected String getTypeColumn() {
606 return Im.PROTOCOL;
607 }
608
609 @Override
610 protected String getLabelColumn() {
611 return Im.CUSTOM_PROTOCOL;
612 }
613
614 @Override
615 protected int getTypeLabelResource(Integer type) {
616 if (type == null) return R.string.chat;
617 switch (type) {
618 case Im.PROTOCOL_AIM: return R.string.chat_aim;
619 case Im.PROTOCOL_MSN: return R.string.chat_msn;
620 case Im.PROTOCOL_YAHOO: return R.string.chat_yahoo;
621 case Im.PROTOCOL_SKYPE: return R.string.chat_skype;
622 case Im.PROTOCOL_QQ: return R.string.chat_qq;
623 case Im.PROTOCOL_GOOGLE_TALK: return R.string.chat_gtalk;
624 case Im.PROTOCOL_ICQ: return R.string.chat_icq;
625 case Im.PROTOCOL_JABBER: return R.string.chat_jabber;
626 case Im.PROTOCOL_NETMEETING: return R.string.chat;
627 default: return R.string.chat;
628 }
629 }
630 }
631
Paul Soulos17f639c2014-07-23 13:33:25 -0700632 public static final StringInflater ORGANIZATION_BODY_INFLATER = new StringInflater() {
633 @Override
634 public CharSequence inflateUsing(Context context, ContentValues values) {
635 final CharSequence companyValue = values.containsKey(Organization.COMPANY) ?
636 values.getAsString(Organization.COMPANY) : null;
637 final CharSequence titleValue = values.containsKey(Organization.TITLE) ?
638 values.getAsString(Organization.TITLE) : null;
639
640 if (companyValue != null && titleValue != null) {
641 return companyValue + ": " + titleValue;
642 } else if (companyValue == null) {
643 return titleValue;
644 } else {
645 return companyValue;
646 }
647 }
648 };
649
Chiao Chenge88fcd32012-11-13 18:38:05 -0800650 @Override
651 public boolean isGroupMembershipEditable() {
652 return false;
653 }
654
655 /**
656 * Parses the content of the EditSchema tag in contacts.xml.
657 */
658 protected final void parseEditSchema(Context context, XmlPullParser parser, AttributeSet attrs)
659 throws XmlPullParserException, IOException, DefinitionException {
660
661 final int outerDepth = parser.getDepth();
662 int type;
663 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
664 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
665 final int depth = parser.getDepth();
666 if (type != XmlPullParser.START_TAG || depth != outerDepth + 1) {
667 continue; // Not direct child tag
668 }
669
670 final String tag = parser.getName();
671
672 if (Tag.DATA_KIND.equals(tag)) {
673 for (DataKind kind : KindParser.INSTANCE.parseDataKindTag(context, parser, attrs)) {
674 addKind(kind);
675 }
676 } else {
677 Log.w(TAG, "Skipping unknown tag " + tag);
678 }
679 }
680 }
681
682 // Utility methods to keep code shorter.
683 private static boolean getAttr(AttributeSet attrs, String attribute, boolean defaultValue) {
684 return attrs.getAttributeBooleanValue(null, attribute, defaultValue);
685 }
686
687 private static int getAttr(AttributeSet attrs, String attribute, int defaultValue) {
688 return attrs.getAttributeIntValue(null, attribute, defaultValue);
689 }
690
691 private static String getAttr(AttributeSet attrs, String attribute) {
692 return attrs.getAttributeValue(null, attribute);
693 }
694
695 // TODO Extract it to its own class, and move all KindBuilders to it as well.
696 private static class KindParser {
697 public static final KindParser INSTANCE = new KindParser();
698
699 private final Map<String, KindBuilder> mBuilders = Maps.newHashMap();
700
701 private KindParser() {
702 addBuilder(new NameKindBuilder());
703 addBuilder(new NicknameKindBuilder());
704 addBuilder(new PhoneKindBuilder());
705 addBuilder(new EmailKindBuilder());
706 addBuilder(new StructuredPostalKindBuilder());
707 addBuilder(new ImKindBuilder());
708 addBuilder(new OrganizationKindBuilder());
709 addBuilder(new PhotoKindBuilder());
710 addBuilder(new NoteKindBuilder());
711 addBuilder(new WebsiteKindBuilder());
712 addBuilder(new SipAddressKindBuilder());
713 addBuilder(new GroupMembershipKindBuilder());
714 addBuilder(new EventKindBuilder());
715 addBuilder(new RelationshipKindBuilder());
716 }
717
718 private void addBuilder(KindBuilder builder) {
719 mBuilders.put(builder.getTagName(), builder);
720 }
721
722 /**
723 * Takes a {@link XmlPullParser} at the start of a DataKind tag, parses it and returns
724 * {@link DataKind}s. (Usually just one, but there are three for the "name" kind.)
725 *
726 * This method returns a list, because we need to add 3 kinds for the name data kind.
727 * (structured, display and phonetic)
728 */
729 public List<DataKind> parseDataKindTag(Context context, XmlPullParser parser,
730 AttributeSet attrs)
731 throws DefinitionException, XmlPullParserException, IOException {
732 final String kind = getAttr(attrs, Attr.KIND);
733 final KindBuilder builder = mBuilders.get(kind);
734 if (builder != null) {
735 return builder.parseDataKind(context, parser, attrs);
736 } else {
737 throw new DefinitionException("Undefined data kind '" + kind + "'");
738 }
739 }
740 }
741
742 private static abstract class KindBuilder {
743
744 public abstract String getTagName();
745
746 /**
747 * DataKind tag parser specific to each kind. Subclasses must implement it.
748 */
749 public abstract List<DataKind> parseDataKind(Context context, XmlPullParser parser,
750 AttributeSet attrs) throws DefinitionException, XmlPullParserException, IOException;
751
752 /**
753 * Creates a new {@link DataKind}, and also parses the child Type tags in the DataKind
754 * tag.
755 */
756 protected final DataKind newDataKind(Context context, XmlPullParser parser,
757 AttributeSet attrs, boolean isPseudo, String mimeType, String typeColumn,
Chiao Cheng4eff3d82012-12-06 12:15:08 -0800758 int titleRes, int weight, StringInflater actionHeader, StringInflater actionBody)
Chiao Chenge88fcd32012-11-13 18:38:05 -0800759 throws DefinitionException, XmlPullParserException, IOException {
760
761 if (Log.isLoggable(TAG, Log.DEBUG)) {
762 Log.d(TAG, "Adding DataKind: " + mimeType);
763 }
764
Chiao Cheng4eff3d82012-12-06 12:15:08 -0800765 final DataKind kind = new DataKind(mimeType, titleRes, weight, true);
Chiao Chenge88fcd32012-11-13 18:38:05 -0800766 kind.typeColumn = typeColumn;
767 kind.actionHeader = actionHeader;
768 kind.actionBody = actionBody;
769 kind.fieldList = Lists.newArrayList();
770
771 // Get more information from the tag...
772 // A pseudo data kind doesn't have corresponding tag the XML, so we skip this.
773 if (!isPseudo) {
774 kind.typeOverallMax = getAttr(attrs, Attr.MAX_OCCURRENCE, -1);
775
776 // Process "Type" tags.
777 // If a kind has the type column, contacts.xml must have at least one type
778 // definition. Otherwise, it mustn't have a type definition.
779 if (kind.typeColumn != null) {
780 // Parse and add types.
781 kind.typeList = Lists.newArrayList();
782 parseTypes(context, parser, attrs, kind, true);
783 if (kind.typeList.size() == 0) {
784 throw new DefinitionException(
785 "Kind " + kind.mimeType + " must have at least one type");
786 }
787 } else {
788 // Make sure it has no types.
789 parseTypes(context, parser, attrs, kind, false /* can't have types */);
790 }
791 }
792
793 return kind;
794 }
795
796 /**
797 * Parses Type elements in a DataKind element, and if {@code canHaveTypes} is true adds
798 * them to the given {@link DataKind}. Otherwise the {@link DataKind} can't have a type,
799 * so throws {@link DefinitionException}.
800 */
801 private void parseTypes(Context context, XmlPullParser parser, AttributeSet attrs,
802 DataKind kind, boolean canHaveTypes)
803 throws DefinitionException, XmlPullParserException, IOException {
804 final int outerDepth = parser.getDepth();
805 int type;
806 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
807 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
808 final int depth = parser.getDepth();
809 if (type != XmlPullParser.START_TAG || depth != outerDepth + 1) {
810 continue; // Not direct child tag
811 }
812
813 final String tag = parser.getName();
814 if (Tag.TYPE.equals(tag)) {
815 if (canHaveTypes) {
816 kind.typeList.add(parseTypeTag(parser, attrs, kind));
817 } else {
818 throw new DefinitionException(
819 "Kind " + kind.mimeType + " can't have types");
820 }
821 } else {
822 throw new DefinitionException("Unknown tag: " + tag);
823 }
824 }
825 }
826
827 /**
828 * Parses a single Type element and returns an {@link EditType} built from it. Uses
829 * {@link #buildEditTypeForTypeTag} defined in subclasses to actually build an
830 * {@link EditType}.
831 */
832 private EditType parseTypeTag(XmlPullParser parser, AttributeSet attrs, DataKind kind)
833 throws DefinitionException {
834
835 final String typeName = getAttr(attrs, Attr.TYPE);
836
837 final EditType et = buildEditTypeForTypeTag(attrs, typeName);
838 if (et == null) {
839 throw new DefinitionException(
840 "Undefined type '" + typeName + "' for data kind '" + kind.mimeType + "'");
841 }
842 et.specificMax = getAttr(attrs, Attr.MAX_OCCURRENCE, -1);
843
844 return et;
845 }
846
847 /**
848 * Returns an {@link EditType} for the given "type". Subclasses may optionally use
849 * the attributes in the tag to set optional values.
850 * (e.g. "yearOptional" for the event kind)
851 */
852 protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
853 return null;
854 }
855
856 protected final void throwIfList(DataKind kind) throws DefinitionException {
857 if (kind.typeOverallMax != 1) {
858 throw new DefinitionException(
859 "Kind " + kind.mimeType + " must have 'overallMax=\"1\"'");
860 }
861 }
862 }
863
864 /**
865 * DataKind parser for Name. (structured, display, phonetic)
866 */
867 private static class NameKindBuilder extends KindBuilder {
868 @Override
869 public String getTagName() {
870 return "name";
871 }
872
873 private static void checkAttributeTrue(boolean value, String attrName)
874 throws DefinitionException {
875 if (!value) {
876 throw new DefinitionException(attrName + " must be true");
877 }
878 }
879
880 @Override
881 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
882 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
883 IOException {
884
Gary Mai7a6daea2016-10-10 15:41:48 -0700885 // Build 3 data kinds:
Chiao Chenge88fcd32012-11-13 18:38:05 -0800886 // - StructuredName.CONTENT_ITEM_TYPE
Gary Mai7a6daea2016-10-10 15:41:48 -0700887 // - DataKind.PSEUDO_MIME_TYPE_NAME
Chiao Chenge88fcd32012-11-13 18:38:05 -0800888 // - DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME
889
890 final boolean displayOrderPrimary =
891 context.getResources().getBoolean(R.bool.config_editor_field_order_primary);
892
Chiao Chenge88fcd32012-11-13 18:38:05 -0800893 final boolean supportsPrefix = getAttr(attrs, "supportsPrefix", false);
894 final boolean supportsMiddleName = getAttr(attrs, "supportsMiddleName", false);
895 final boolean supportsSuffix = getAttr(attrs, "supportsSuffix", false);
896 final boolean supportsPhoneticFamilyName =
897 getAttr(attrs, "supportsPhoneticFamilyName", false);
898 final boolean supportsPhoneticMiddleName =
899 getAttr(attrs, "supportsPhoneticMiddleName", false);
900 final boolean supportsPhoneticGivenName =
901 getAttr(attrs, "supportsPhoneticGivenName", false);
902
Gary Mai7a6daea2016-10-10 15:41:48 -0700903 // For now, every thing must be supported.
Chiao Chenge88fcd32012-11-13 18:38:05 -0800904 checkAttributeTrue(supportsPrefix, "supportsPrefix");
905 checkAttributeTrue(supportsMiddleName, "supportsMiddleName");
906 checkAttributeTrue(supportsSuffix, "supportsSuffix");
907 checkAttributeTrue(supportsPhoneticFamilyName, "supportsPhoneticFamilyName");
908 checkAttributeTrue(supportsPhoneticMiddleName, "supportsPhoneticMiddleName");
909 checkAttributeTrue(supportsPhoneticGivenName, "supportsPhoneticGivenName");
910
911 final List<DataKind> kinds = Lists.newArrayList();
912
913 // Structured name
914 final DataKind ks = newDataKind(context, parser, attrs, false,
915 StructuredName.CONTENT_ITEM_TYPE, null, R.string.nameLabelsGroup, Weight.NONE,
Chiao Chenge88fcd32012-11-13 18:38:05 -0800916 new SimpleInflater(R.string.nameLabelsGroup),
917 new SimpleInflater(Nickname.NAME));
918
Chiao Chenge88fcd32012-11-13 18:38:05 -0800919 ks.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
920 FLAGS_PERSON_NAME).setLongForm(true));
Gary Mai7a6daea2016-10-10 15:41:48 -0700921 ks.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
922 FLAGS_PERSON_NAME));
923 ks.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
924 FLAGS_PERSON_NAME).setLongForm(true));
925 ks.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
926 FLAGS_PERSON_NAME));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800927 ks.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
928 FLAGS_PERSON_NAME).setLongForm(true));
Gary Mai7a6daea2016-10-10 15:41:48 -0700929 ks.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
930 R.string.name_phonetic_family, FLAGS_PHONETIC));
931 ks.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
932 R.string.name_phonetic_middle, FLAGS_PHONETIC));
933 ks.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
934 R.string.name_phonetic_given, FLAGS_PHONETIC));
Chiao Chenge88fcd32012-11-13 18:38:05 -0800935
Gary Mai698cee72016-09-19 16:09:54 -0700936 throwIfList(ks);
937 kinds.add(ks);
Chiao Chenge88fcd32012-11-13 18:38:05 -0800938
Gary Mai7a6daea2016-10-10 15:41:48 -0700939 // Name
940 final DataKind kn = newDataKind(context, parser, attrs, true,
941 DataKind.PSEUDO_MIME_TYPE_NAME, null,
942 R.string.nameLabelsGroup, Weight.NONE,
943 new SimpleInflater(R.string.nameLabelsGroup),
944 new SimpleInflater(Nickname.NAME));
945 kn.typeOverallMax = 1;
946 throwIfList(kn);
947 kinds.add(kn);
948
949 kn.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
Gary Maia6c7a972016-11-11 18:08:59 -0800950 FLAGS_PERSON_NAME).setOptional(true));
Gary Mai7a6daea2016-10-10 15:41:48 -0700951 if (!displayOrderPrimary) {
952 kn.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
953 FLAGS_PERSON_NAME));
954 kn.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
Gary Maia6c7a972016-11-11 18:08:59 -0800955 FLAGS_PERSON_NAME).setOptional(true));
Gary Mai7a6daea2016-10-10 15:41:48 -0700956 kn.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
957 FLAGS_PERSON_NAME));
958 } else {
959 kn.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
960 FLAGS_PERSON_NAME));
961 kn.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
Gary Maia6c7a972016-11-11 18:08:59 -0800962 FLAGS_PERSON_NAME).setOptional(true));
Gary Mai7a6daea2016-10-10 15:41:48 -0700963 kn.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
964 FLAGS_PERSON_NAME));
965 }
966 kn.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
Gary Maia6c7a972016-11-11 18:08:59 -0800967 FLAGS_PERSON_NAME).setOptional(true));
Gary Mai7a6daea2016-10-10 15:41:48 -0700968
Chiao Chenge88fcd32012-11-13 18:38:05 -0800969 // Phonetic name
970 final DataKind kp = newDataKind(context, parser, attrs, true,
971 DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME, null,
Chiao Cheng4eff3d82012-12-06 12:15:08 -0800972 R.string.name_phonetic, Weight.NONE,
Chiao Chenge88fcd32012-11-13 18:38:05 -0800973 new SimpleInflater(R.string.nameLabelsGroup),
974 new SimpleInflater(Nickname.NAME));
975 kp.typeOverallMax = 1;
976 kinds.add(kp);
977
978 // We may want to change the order depending on displayOrderPrimary too.
979 kp.fieldList.add(new EditField(DataKind.PSEUDO_COLUMN_PHONETIC_NAME,
980 R.string.name_phonetic, FLAGS_PHONETIC).setShortForm(true));
981 kp.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
982 R.string.name_phonetic_family, FLAGS_PHONETIC).setLongForm(true));
983 kp.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
984 R.string.name_phonetic_middle, FLAGS_PHONETIC).setLongForm(true));
985 kp.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
986 R.string.name_phonetic_given, FLAGS_PHONETIC).setLongForm(true));
987 return kinds;
988 }
989 }
990
991 private static class NicknameKindBuilder extends KindBuilder {
992 @Override
993 public String getTagName() {
994 return "nickname";
995 }
996
997 @Override
998 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
999 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1000 IOException {
1001 final DataKind kind = newDataKind(context, parser, attrs, false,
1002 Nickname.CONTENT_ITEM_TYPE, null, R.string.nicknameLabelsGroup, Weight.NICKNAME,
Chiao Chenge88fcd32012-11-13 18:38:05 -08001003 new SimpleInflater(R.string.nicknameLabelsGroup),
1004 new SimpleInflater(Nickname.NAME));
1005
1006 kind.fieldList.add(new EditField(Nickname.NAME, R.string.nicknameLabelsGroup,
1007 FLAGS_PERSON_NAME));
1008
1009 kind.defaultValues = new ContentValues();
1010 kind.defaultValues.put(Nickname.TYPE, Nickname.TYPE_DEFAULT);
1011
1012 throwIfList(kind);
1013 return Lists.newArrayList(kind);
1014 }
1015 }
1016
1017 private static class PhoneKindBuilder extends KindBuilder {
1018 @Override
1019 public String getTagName() {
1020 return "phone";
1021 }
1022
1023 @Override
1024 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
1025 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1026 IOException {
1027 final DataKind kind = newDataKind(context, parser, attrs, false,
1028 Phone.CONTENT_ITEM_TYPE, Phone.TYPE, R.string.phoneLabelsGroup, Weight.PHONE,
Chiao Chenge88fcd32012-11-13 18:38:05 -08001029 new PhoneActionInflater(), new SimpleInflater(Phone.NUMBER));
1030
Walter Jang353570e2016-05-04 17:43:56 -07001031 kind.iconAltRes = R.drawable.ic_message_24dp_mirrored;
Chiao Chenge88fcd32012-11-13 18:38:05 -08001032 kind.iconAltDescriptionRes = R.string.sms;
1033 kind.actionAltHeader = new PhoneActionAltInflater();
1034
1035 kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE));
1036
1037 return Lists.newArrayList(kind);
1038 }
1039
1040 /** Just to avoid line-wrapping... */
1041 protected static EditType build(int type, boolean secondary) {
1042 return new EditType(type, Phone.getTypeLabelResource(type)).setSecondary(secondary);
1043 }
1044
1045 @Override
1046 protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
1047 if ("home".equals(type)) return build(Phone.TYPE_HOME, false);
1048 if ("mobile".equals(type)) return build(Phone.TYPE_MOBILE, false);
1049 if ("work".equals(type)) return build(Phone.TYPE_WORK, false);
1050 if ("fax_work".equals(type)) return build(Phone.TYPE_FAX_WORK, true);
1051 if ("fax_home".equals(type)) return build(Phone.TYPE_FAX_HOME, true);
1052 if ("pager".equals(type)) return build(Phone.TYPE_PAGER, true);
1053 if ("other".equals(type)) return build(Phone.TYPE_OTHER, false);
1054 if ("callback".equals(type)) return build(Phone.TYPE_CALLBACK, true);
1055 if ("car".equals(type)) return build(Phone.TYPE_CAR, true);
1056 if ("company_main".equals(type)) return build(Phone.TYPE_COMPANY_MAIN, true);
1057 if ("isdn".equals(type)) return build(Phone.TYPE_ISDN, true);
1058 if ("main".equals(type)) return build(Phone.TYPE_MAIN, true);
1059 if ("other_fax".equals(type)) return build(Phone.TYPE_OTHER_FAX, true);
1060 if ("radio".equals(type)) return build(Phone.TYPE_RADIO, true);
1061 if ("telex".equals(type)) return build(Phone.TYPE_TELEX, true);
1062 if ("tty_tdd".equals(type)) return build(Phone.TYPE_TTY_TDD, true);
1063 if ("work_mobile".equals(type)) return build(Phone.TYPE_WORK_MOBILE, true);
1064 if ("work_pager".equals(type)) return build(Phone.TYPE_WORK_PAGER, true);
1065
1066 // Note "assistant" used to be a custom column for the fallback type, but not anymore.
1067 if ("assistant".equals(type)) return build(Phone.TYPE_ASSISTANT, true);
1068 if ("mms".equals(type)) return build(Phone.TYPE_MMS, true);
1069 if ("custom".equals(type)) {
1070 return build(Phone.TYPE_CUSTOM, true).setCustomColumn(Phone.LABEL);
1071 }
1072 return null;
1073 }
1074 }
1075
1076 private static class EmailKindBuilder extends KindBuilder {
1077 @Override
1078 public String getTagName() {
1079 return "email";
1080 }
1081
1082 @Override
1083 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
1084 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1085 IOException {
1086 final DataKind kind = newDataKind(context, parser, attrs, false,
1087 Email.CONTENT_ITEM_TYPE, Email.TYPE, R.string.emailLabelsGroup, Weight.EMAIL,
Chiao Chenge88fcd32012-11-13 18:38:05 -08001088 new EmailActionInflater(), new SimpleInflater(Email.DATA));
1089 kind.fieldList.add(new EditField(Email.DATA, R.string.emailLabelsGroup, FLAGS_EMAIL));
1090
1091 return Lists.newArrayList(kind);
1092 }
1093
1094 @Override
1095 protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
1096 // EditType is mutable, so we need to create a new instance every time.
1097 if ("home".equals(type)) return buildEmailType(Email.TYPE_HOME);
1098 if ("work".equals(type)) return buildEmailType(Email.TYPE_WORK);
1099 if ("other".equals(type)) return buildEmailType(Email.TYPE_OTHER);
1100 if ("mobile".equals(type)) return buildEmailType(Email.TYPE_MOBILE);
1101 if ("custom".equals(type)) {
1102 return buildEmailType(Email.TYPE_CUSTOM)
1103 .setSecondary(true).setCustomColumn(Email.LABEL);
1104 }
1105 return null;
1106 }
1107 }
1108
1109 private static class StructuredPostalKindBuilder extends KindBuilder {
1110 @Override
1111 public String getTagName() {
1112 return "postal";
1113 }
1114
1115 @Override
1116 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
1117 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1118 IOException {
1119 final DataKind kind = newDataKind(context, parser, attrs, false,
1120 StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE,
1121 R.string.postalLabelsGroup, Weight.STRUCTURED_POSTAL,
Chiao Cheng4eff3d82012-12-06 12:15:08 -08001122 new PostalActionInflater(),
Chiao Chenge88fcd32012-11-13 18:38:05 -08001123 new SimpleInflater(StructuredPostal.FORMATTED_ADDRESS));
1124
1125 if (getAttr(attrs, "needsStructured", false)) {
1126 if (Locale.JAPANESE.getLanguage().equals(Locale.getDefault().getLanguage())) {
1127 // Japanese order
1128 kind.fieldList.add(new EditField(StructuredPostal.COUNTRY,
1129 R.string.postal_country, FLAGS_POSTAL).setOptional(true));
1130 kind.fieldList.add(new EditField(StructuredPostal.POSTCODE,
1131 R.string.postal_postcode, FLAGS_POSTAL));
1132 kind.fieldList.add(new EditField(StructuredPostal.REGION,
1133 R.string.postal_region, FLAGS_POSTAL));
1134 kind.fieldList.add(new EditField(StructuredPostal.CITY,
1135 R.string.postal_city,FLAGS_POSTAL));
1136 kind.fieldList.add(new EditField(StructuredPostal.STREET,
1137 R.string.postal_street, FLAGS_POSTAL));
1138 } else {
1139 // Generic order
1140 kind.fieldList.add(new EditField(StructuredPostal.STREET,
1141 R.string.postal_street, FLAGS_POSTAL));
1142 kind.fieldList.add(new EditField(StructuredPostal.CITY,
1143 R.string.postal_city,FLAGS_POSTAL));
1144 kind.fieldList.add(new EditField(StructuredPostal.REGION,
1145 R.string.postal_region, FLAGS_POSTAL));
1146 kind.fieldList.add(new EditField(StructuredPostal.POSTCODE,
1147 R.string.postal_postcode, FLAGS_POSTAL));
1148 kind.fieldList.add(new EditField(StructuredPostal.COUNTRY,
1149 R.string.postal_country, FLAGS_POSTAL).setOptional(true));
1150 }
1151 } else {
1152 kind.maxLinesForDisplay= MAX_LINES_FOR_POSTAL_ADDRESS;
1153 kind.fieldList.add(
1154 new EditField(StructuredPostal.FORMATTED_ADDRESS, R.string.postal_address,
1155 FLAGS_POSTAL));
1156 }
1157
1158 return Lists.newArrayList(kind);
1159 }
1160
1161 @Override
1162 protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
1163 // EditType is mutable, so we need to create a new instance every time.
1164 if ("home".equals(type)) return buildPostalType(StructuredPostal.TYPE_HOME);
1165 if ("work".equals(type)) return buildPostalType(StructuredPostal.TYPE_WORK);
1166 if ("other".equals(type)) return buildPostalType(StructuredPostal.TYPE_OTHER);
1167 if ("custom".equals(type)) {
1168 return buildPostalType(StructuredPostal.TYPE_CUSTOM)
1169 .setSecondary(true).setCustomColumn(Email.LABEL);
1170 }
1171 return null;
1172 }
1173 }
1174
1175 private static class ImKindBuilder extends KindBuilder {
1176 @Override
1177 public String getTagName() {
1178 return "im";
1179 }
1180
1181 @Override
1182 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
1183 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1184 IOException {
1185
1186 // IM is special:
1187 // - It uses "protocol" as the custom label field
1188 // - Its TYPE is fixed to TYPE_OTHER
1189
1190 final DataKind kind = newDataKind(context, parser, attrs, false,
1191 Im.CONTENT_ITEM_TYPE, Im.PROTOCOL, R.string.imLabelsGroup, Weight.IM,
Chiao Chenge88fcd32012-11-13 18:38:05 -08001192 new ImActionInflater(), new SimpleInflater(Im.DATA) // header / action
1193 );
1194 kind.fieldList.add(new EditField(Im.DATA, R.string.imLabelsGroup, FLAGS_EMAIL));
1195
1196 kind.defaultValues = new ContentValues();
1197 kind.defaultValues.put(Im.TYPE, Im.TYPE_OTHER);
1198
1199 return Lists.newArrayList(kind);
1200 }
1201
1202 @Override
1203 protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
1204 if ("aim".equals(type)) return buildImType(Im.PROTOCOL_AIM);
1205 if ("msn".equals(type)) return buildImType(Im.PROTOCOL_MSN);
1206 if ("yahoo".equals(type)) return buildImType(Im.PROTOCOL_YAHOO);
1207 if ("skype".equals(type)) return buildImType(Im.PROTOCOL_SKYPE);
1208 if ("qq".equals(type)) return buildImType(Im.PROTOCOL_QQ);
1209 if ("google_talk".equals(type)) return buildImType(Im.PROTOCOL_GOOGLE_TALK);
1210 if ("icq".equals(type)) return buildImType(Im.PROTOCOL_ICQ);
1211 if ("jabber".equals(type)) return buildImType(Im.PROTOCOL_JABBER);
1212 if ("custom".equals(type)) {
1213 return buildImType(Im.PROTOCOL_CUSTOM).setSecondary(true)
1214 .setCustomColumn(Im.CUSTOM_PROTOCOL);
1215 }
1216 return null;
1217 }
1218 }
1219
1220 private static class OrganizationKindBuilder extends KindBuilder {
1221 @Override
1222 public String getTagName() {
1223 return "organization";
1224 }
1225
1226 @Override
1227 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
1228 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1229 IOException {
1230 final DataKind kind = newDataKind(context, parser, attrs, false,
1231 Organization.CONTENT_ITEM_TYPE, null, R.string.organizationLabelsGroup,
Chiao Cheng4eff3d82012-12-06 12:15:08 -08001232 Weight.ORGANIZATION,
Paul Soulos17f639c2014-07-23 13:33:25 -07001233 new SimpleInflater(R.string.organizationLabelsGroup),
1234 ORGANIZATION_BODY_INFLATER);
Chiao Chenge88fcd32012-11-13 18:38:05 -08001235
1236 kind.fieldList.add(new EditField(Organization.COMPANY, R.string.ghostData_company,
1237 FLAGS_GENERIC_NAME));
1238 kind.fieldList.add(new EditField(Organization.TITLE, R.string.ghostData_title,
1239 FLAGS_GENERIC_NAME));
1240
1241 throwIfList(kind);
1242
1243 return Lists.newArrayList(kind);
1244 }
1245 }
1246
1247 private static class PhotoKindBuilder extends KindBuilder {
1248 @Override
1249 public String getTagName() {
1250 return "photo";
1251 }
1252
1253 @Override
1254 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
1255 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1256 IOException {
1257 final DataKind kind = newDataKind(context, parser, attrs, false,
Chiao Cheng4eff3d82012-12-06 12:15:08 -08001258 Photo.CONTENT_ITEM_TYPE, null /* no type */, Weight.NONE, -1,
Chiao Chenge88fcd32012-11-13 18:38:05 -08001259 null, null // no header, no body
1260 );
1261
1262 kind.fieldList.add(new EditField(Photo.PHOTO, -1, -1));
1263
1264 throwIfList(kind);
1265
1266 return Lists.newArrayList(kind);
1267 }
1268 }
1269
1270 private static class NoteKindBuilder extends KindBuilder {
1271 @Override
1272 public String getTagName() {
1273 return "note";
1274 }
1275
1276 @Override
1277 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
1278 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1279 IOException {
1280 final DataKind kind = newDataKind(context, parser, attrs, false,
1281 Note.CONTENT_ITEM_TYPE, null, R.string.label_notes, Weight.NOTE,
Chiao Chenge88fcd32012-11-13 18:38:05 -08001282 new SimpleInflater(R.string.label_notes), new SimpleInflater(Note.NOTE));
1283
1284 kind.fieldList.add(new EditField(Note.NOTE, R.string.label_notes, FLAGS_NOTE));
1285 kind.maxLinesForDisplay = MAX_LINES_FOR_NOTE;
1286
1287 throwIfList(kind);
1288
1289 return Lists.newArrayList(kind);
1290 }
1291 }
1292
1293 private static class WebsiteKindBuilder extends KindBuilder {
1294 @Override
1295 public String getTagName() {
1296 return "website";
1297 }
1298
1299 @Override
1300 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
1301 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1302 IOException {
1303 final DataKind kind = newDataKind(context, parser, attrs, false,
1304 Website.CONTENT_ITEM_TYPE, null, R.string.websiteLabelsGroup, Weight.WEBSITE,
Chiao Chenge88fcd32012-11-13 18:38:05 -08001305 new SimpleInflater(R.string.websiteLabelsGroup),
1306 new SimpleInflater(Website.URL));
1307
1308 kind.fieldList.add(new EditField(Website.URL, R.string.websiteLabelsGroup,
1309 FLAGS_WEBSITE));
1310
1311 kind.defaultValues = new ContentValues();
1312 kind.defaultValues.put(Website.TYPE, Website.TYPE_OTHER);
1313
1314 return Lists.newArrayList(kind);
1315 }
1316 }
1317
1318 private static class SipAddressKindBuilder extends KindBuilder {
1319 @Override
1320 public String getTagName() {
1321 return "sip_address";
1322 }
1323
1324 @Override
1325 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
1326 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1327 IOException {
1328 final DataKind kind = newDataKind(context, parser, attrs, false,
1329 SipAddress.CONTENT_ITEM_TYPE, null, R.string.label_sip_address,
Chiao Cheng4eff3d82012-12-06 12:15:08 -08001330 Weight.SIP_ADDRESS,
Chiao Chenge88fcd32012-11-13 18:38:05 -08001331 new SimpleInflater(R.string.label_sip_address),
1332 new SimpleInflater(SipAddress.SIP_ADDRESS));
1333
1334 kind.fieldList.add(new EditField(SipAddress.SIP_ADDRESS,
1335 R.string.label_sip_address, FLAGS_SIP_ADDRESS));
1336
1337 throwIfList(kind);
1338
1339 return Lists.newArrayList(kind);
1340 }
1341 }
1342
1343 private static class GroupMembershipKindBuilder extends KindBuilder {
1344 @Override
1345 public String getTagName() {
1346 return "group_membership";
1347 }
1348
1349 @Override
1350 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
1351 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1352 IOException {
1353 final DataKind kind = newDataKind(context, parser, attrs, false,
1354 GroupMembership.CONTENT_ITEM_TYPE, null,
Chiao Cheng4eff3d82012-12-06 12:15:08 -08001355 R.string.groupsLabel, Weight.GROUP_MEMBERSHIP, null, null);
Chiao Chenge88fcd32012-11-13 18:38:05 -08001356
1357 kind.fieldList.add(new EditField(GroupMembership.GROUP_ROW_ID, -1, -1));
1358 kind.maxLinesForDisplay = MAX_LINES_FOR_GROUP;
1359
1360 throwIfList(kind);
1361
1362 return Lists.newArrayList(kind);
1363 }
1364 }
1365
1366 /**
1367 * Event DataKind parser.
1368 *
1369 * Event DataKind is used only for Google/Exchange types, so this parser is not used for now.
1370 */
1371 private static class EventKindBuilder extends KindBuilder {
1372 @Override
1373 public String getTagName() {
1374 return "event";
1375 }
1376
1377 @Override
1378 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
1379 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1380 IOException {
1381 final DataKind kind = newDataKind(context, parser, attrs, false,
1382 Event.CONTENT_ITEM_TYPE, Event.TYPE, R.string.eventLabelsGroup, Weight.EVENT,
Chiao Chenge88fcd32012-11-13 18:38:05 -08001383 new EventActionInflater(), new SimpleInflater(Event.START_DATE));
1384
1385 kind.fieldList.add(new EditField(Event.DATA, R.string.eventLabelsGroup, FLAGS_EVENT));
1386
1387 if (getAttr(attrs, Attr.DATE_WITH_TIME, false)) {
1388 kind.dateFormatWithoutYear = CommonDateUtils.NO_YEAR_DATE_AND_TIME_FORMAT;
1389 kind.dateFormatWithYear = CommonDateUtils.DATE_AND_TIME_FORMAT;
1390 } else {
1391 kind.dateFormatWithoutYear = CommonDateUtils.NO_YEAR_DATE_FORMAT;
1392 kind.dateFormatWithYear = CommonDateUtils.FULL_DATE_FORMAT;
1393 }
1394
1395 return Lists.newArrayList(kind);
1396 }
1397
1398 @Override
1399 protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
1400 final boolean yo = getAttr(attrs, Attr.YEAR_OPTIONAL, false);
1401
1402 if ("birthday".equals(type)) {
1403 return buildEventType(Event.TYPE_BIRTHDAY, yo).setSpecificMax(1);
1404 }
1405 if ("anniversary".equals(type)) return buildEventType(Event.TYPE_ANNIVERSARY, yo);
1406 if ("other".equals(type)) return buildEventType(Event.TYPE_OTHER, yo);
1407 if ("custom".equals(type)) {
1408 return buildEventType(Event.TYPE_CUSTOM, yo)
1409 .setSecondary(true).setCustomColumn(Event.LABEL);
1410 }
1411 return null;
1412 }
1413 }
1414
1415 /**
1416 * Relationship DataKind parser.
1417 *
1418 * Relationship DataKind is used only for Google/Exchange types, so this parser is not used for
1419 * now.
1420 */
1421 private static class RelationshipKindBuilder extends KindBuilder {
1422 @Override
1423 public String getTagName() {
1424 return "relationship";
1425 }
1426
1427 @Override
1428 public List<DataKind> parseDataKind(Context context, XmlPullParser parser,
1429 AttributeSet attrs) throws DefinitionException, XmlPullParserException,
1430 IOException {
1431 final DataKind kind = newDataKind(context, parser, attrs, false,
1432 Relation.CONTENT_ITEM_TYPE, Relation.TYPE,
1433 R.string.relationLabelsGroup, Weight.RELATIONSHIP,
Chiao Chenge88fcd32012-11-13 18:38:05 -08001434 new RelationActionInflater(), new SimpleInflater(Relation.NAME));
1435
1436 kind.fieldList.add(new EditField(Relation.DATA, R.string.relationLabelsGroup,
1437 FLAGS_RELATION));
1438
1439 kind.defaultValues = new ContentValues();
1440 kind.defaultValues.put(Relation.TYPE, Relation.TYPE_SPOUSE);
1441
1442 return Lists.newArrayList(kind);
1443 }
1444
1445 @Override
1446 protected EditType buildEditTypeForTypeTag(AttributeSet attrs, String type) {
1447 // EditType is mutable, so we need to create a new instance every time.
1448 if ("assistant".equals(type)) return buildRelationType(Relation.TYPE_ASSISTANT);
1449 if ("brother".equals(type)) return buildRelationType(Relation.TYPE_BROTHER);
1450 if ("child".equals(type)) return buildRelationType(Relation.TYPE_CHILD);
1451 if ("domestic_partner".equals(type)) {
1452 return buildRelationType(Relation.TYPE_DOMESTIC_PARTNER);
1453 }
1454 if ("father".equals(type)) return buildRelationType(Relation.TYPE_FATHER);
1455 if ("friend".equals(type)) return buildRelationType(Relation.TYPE_FRIEND);
1456 if ("manager".equals(type)) return buildRelationType(Relation.TYPE_MANAGER);
1457 if ("mother".equals(type)) return buildRelationType(Relation.TYPE_MOTHER);
1458 if ("parent".equals(type)) return buildRelationType(Relation.TYPE_PARENT);
1459 if ("partner".equals(type)) return buildRelationType(Relation.TYPE_PARTNER);
1460 if ("referred_by".equals(type)) return buildRelationType(Relation.TYPE_REFERRED_BY);
1461 if ("relative".equals(type)) return buildRelationType(Relation.TYPE_RELATIVE);
1462 if ("sister".equals(type)) return buildRelationType(Relation.TYPE_SISTER);
1463 if ("spouse".equals(type)) return buildRelationType(Relation.TYPE_SPOUSE);
1464 if ("custom".equals(type)) {
1465 return buildRelationType(Relation.TYPE_CUSTOM).setSecondary(true)
1466 .setCustomColumn(Relation.LABEL);
1467 }
1468 return null;
1469 }
1470 }
1471}