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