1/*
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.loaderapp.model;
18
19import com.android.loaderapp.R;
20import com.google.android.collect.Lists;
21
22import android.content.ContentValues;
23import android.content.Context;
24import android.content.res.Resources;
25import android.database.Cursor;
26import android.provider.ContactsContract.CommonDataKinds.BaseTypes;
27import android.provider.ContactsContract.CommonDataKinds.Email;
28import android.provider.ContactsContract.CommonDataKinds.Event;
29import android.provider.ContactsContract.CommonDataKinds.Im;
30import android.provider.ContactsContract.CommonDataKinds.Nickname;
31import android.provider.ContactsContract.CommonDataKinds.Note;
32import android.provider.ContactsContract.CommonDataKinds.Organization;
33import android.provider.ContactsContract.CommonDataKinds.Phone;
34import android.provider.ContactsContract.CommonDataKinds.Photo;
35import android.provider.ContactsContract.CommonDataKinds.StructuredName;
36import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
37import android.provider.ContactsContract.CommonDataKinds.Website;
38import android.view.inputmethod.EditorInfo;
39
40import java.util.Locale;
41
42public class FallbackSource extends ContactsSource {
43    protected static final int FLAGS_PHONE = EditorInfo.TYPE_CLASS_PHONE;
44    protected static final int FLAGS_EMAIL = EditorInfo.TYPE_CLASS_TEXT
45            | EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
46    protected static final int FLAGS_PERSON_NAME = EditorInfo.TYPE_CLASS_TEXT
47            | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS | EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME;
48    protected static final int FLAGS_PHONETIC = EditorInfo.TYPE_CLASS_TEXT
49            | EditorInfo.TYPE_TEXT_VARIATION_PHONETIC;
50    protected static final int FLAGS_GENERIC_NAME = EditorInfo.TYPE_CLASS_TEXT
51            | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
52    protected static final int FLAGS_NOTE = EditorInfo.TYPE_CLASS_TEXT
53            | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
54    protected static final int FLAGS_WEBSITE = EditorInfo.TYPE_CLASS_TEXT
55            | EditorInfo.TYPE_TEXT_VARIATION_URI;
56    protected static final int FLAGS_POSTAL = EditorInfo.TYPE_CLASS_TEXT
57            | EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS
58            | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
59
60    public FallbackSource() {
61        this.accountType = null;
62        this.titleRes = R.string.account_phone;
63        this.iconRes = R.drawable.ic_launcher_contacts;
64    }
65
66    @Override
67    protected void inflate(Context context, int inflateLevel) {
68
69        inflateStructuredName(context, inflateLevel);
70        inflateNickname(context, inflateLevel);
71        inflatePhone(context, inflateLevel);
72        inflateEmail(context, inflateLevel);
73        inflateStructuredPostal(context, inflateLevel);
74        inflateIm(context, inflateLevel);
75        inflateOrganization(context, inflateLevel);
76        inflatePhoto(context, inflateLevel);
77        inflateNote(context, inflateLevel);
78        inflateWebsite(context, inflateLevel);
79        inflateEvent(context, inflateLevel);
80
81        setInflatedLevel(inflateLevel);
82
83    }
84
85    protected EditType buildPhoneType(int type) {
86        return new EditType(type, Phone.getTypeLabelResource(type));
87    }
88
89    protected EditType buildEmailType(int type) {
90        return new EditType(type, Email.getTypeLabelResource(type));
91    }
92
93    protected EditType buildPostalType(int type) {
94        return new EditType(type, StructuredPostal.getTypeLabelResource(type));
95    }
96
97    protected EditType buildImType(int type) {
98        return new EditType(type, Im.getProtocolLabelResource(type));
99    }
100
101    protected EditType buildOrgType(int type) {
102        return new EditType(type, Organization.getTypeLabelResource(type));
103    }
104
105    protected DataKind inflateStructuredName(Context context, int inflateLevel) {
106        DataKind kind = getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
107        if (kind == null) {
108            kind = addKind(new DataKind(StructuredName.CONTENT_ITEM_TYPE,
109                    R.string.nameLabelsGroup, -1, -1, true));
110        }
111
112        if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
113            boolean displayOrderPrimary =
114                    context.getResources().getBoolean(R.bool.config_editor_field_order_primary);
115
116            kind.fieldList = Lists.newArrayList();
117            kind.fieldList.add(new EditField(StructuredName.PREFIX, R.string.name_prefix,
118                    FLAGS_PERSON_NAME).setOptional(true));
119            if (!displayOrderPrimary) {
120                kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
121                        FLAGS_PERSON_NAME));
122                kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
123                        FLAGS_PERSON_NAME).setOptional(true));
124                kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
125                        FLAGS_PERSON_NAME));
126                kind.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
127                        FLAGS_PERSON_NAME).setOptional(true));
128                kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
129                        R.string.name_phonetic_family, FLAGS_PHONETIC).setOptional(true));
130                kind.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
131                        R.string.name_phonetic_middle, FLAGS_PHONETIC).setOptional(true));
132                kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
133                        R.string.name_phonetic_given, FLAGS_PHONETIC).setOptional(true));
134            } else {
135                kind.fieldList.add(new EditField(StructuredName.GIVEN_NAME, R.string.name_given,
136                        FLAGS_PERSON_NAME));
137                kind.fieldList.add(new EditField(StructuredName.MIDDLE_NAME, R.string.name_middle,
138                        FLAGS_PERSON_NAME).setOptional(true));
139                kind.fieldList.add(new EditField(StructuredName.FAMILY_NAME, R.string.name_family,
140                        FLAGS_PERSON_NAME));
141                kind.fieldList.add(new EditField(StructuredName.SUFFIX, R.string.name_suffix,
142                        FLAGS_PERSON_NAME).setOptional(true));
143                kind.fieldList.add(new EditField(StructuredName.PHONETIC_GIVEN_NAME,
144                        R.string.name_phonetic_given, FLAGS_PHONETIC).setOptional(true));
145                kind.fieldList.add(new EditField(StructuredName.PHONETIC_MIDDLE_NAME,
146                        R.string.name_phonetic_middle, FLAGS_PHONETIC).setOptional(true));
147                kind.fieldList.add(new EditField(StructuredName.PHONETIC_FAMILY_NAME,
148                        R.string.name_phonetic_family, FLAGS_PHONETIC).setOptional(true));
149            }
150        }
151
152        return kind;
153    }
154
155    protected DataKind inflateNickname(Context context, int inflateLevel) {
156        DataKind kind = getKindForMimetype(Nickname.CONTENT_ITEM_TYPE);
157        if (kind == null) {
158            kind = addKind(new DataKind(Nickname.CONTENT_ITEM_TYPE,
159                    R.string.nicknameLabelsGroup, -1, 115, true));
160            kind.secondary = true;
161            kind.isList = false;
162            kind.actionHeader = new SimpleInflater(R.string.nicknameLabelsGroup);
163            kind.actionBody = new SimpleInflater(Nickname.NAME);
164        }
165
166        if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
167            kind.defaultValues = new ContentValues();
168            kind.defaultValues.put(Nickname.TYPE, Nickname.TYPE_DEFAULT);
169
170            kind.fieldList = Lists.newArrayList();
171            kind.fieldList.add(new EditField(Nickname.NAME, R.string.nicknameLabelsGroup,
172                    FLAGS_PERSON_NAME));
173        }
174
175        return kind;
176    }
177
178    protected DataKind inflatePhone(Context context, int inflateLevel) {
179        DataKind kind = getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
180        if (kind == null) {
181            kind = addKind(new DataKind(Phone.CONTENT_ITEM_TYPE, R.string.phoneLabelsGroup,
182                    android.R.drawable.sym_action_call, 10, true));
183            kind.iconAltRes = R.drawable.sym_action_sms;
184            kind.actionHeader = new PhoneActionInflater();
185            kind.actionAltHeader = new PhoneActionAltInflater();
186            kind.actionBody = new SimpleInflater(Phone.NUMBER);
187        }
188
189        if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
190            kind.typeColumn = Phone.TYPE;
191            kind.typeList = Lists.newArrayList();
192            kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));
193            kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE));
194            kind.typeList.add(buildPhoneType(Phone.TYPE_WORK));
195            kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_WORK).setSecondary(true));
196            kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_HOME).setSecondary(true));
197            kind.typeList.add(buildPhoneType(Phone.TYPE_PAGER).setSecondary(true));
198            kind.typeList.add(buildPhoneType(Phone.TYPE_OTHER));
199            kind.typeList.add(buildPhoneType(Phone.TYPE_CUSTOM).setSecondary(true).setCustomColumn(
200                    Phone.LABEL));
201            kind.typeList.add(buildPhoneType(Phone.TYPE_CALLBACK).setSecondary(true));
202            kind.typeList.add(buildPhoneType(Phone.TYPE_CAR).setSecondary(true));
203            kind.typeList.add(buildPhoneType(Phone.TYPE_COMPANY_MAIN).setSecondary(true));
204            kind.typeList.add(buildPhoneType(Phone.TYPE_ISDN).setSecondary(true));
205            kind.typeList.add(buildPhoneType(Phone.TYPE_MAIN).setSecondary(true));
206            kind.typeList.add(buildPhoneType(Phone.TYPE_OTHER_FAX).setSecondary(true));
207            kind.typeList.add(buildPhoneType(Phone.TYPE_RADIO).setSecondary(true));
208            kind.typeList.add(buildPhoneType(Phone.TYPE_TELEX).setSecondary(true));
209            kind.typeList.add(buildPhoneType(Phone.TYPE_TTY_TDD).setSecondary(true));
210            kind.typeList.add(buildPhoneType(Phone.TYPE_WORK_MOBILE).setSecondary(true));
211            kind.typeList.add(buildPhoneType(Phone.TYPE_WORK_PAGER).setSecondary(true));
212            kind.typeList.add(buildPhoneType(Phone.TYPE_ASSISTANT).setSecondary(true)
213                    .setCustomColumn(Phone.LABEL));
214            kind.typeList.add(buildPhoneType(Phone.TYPE_MMS).setSecondary(true));
215
216            kind.fieldList = Lists.newArrayList();
217            kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE));
218        }
219
220        return kind;
221    }
222
223    protected DataKind inflateEmail(Context context, int inflateLevel) {
224        DataKind kind = getKindForMimetype(Email.CONTENT_ITEM_TYPE);
225        if (kind == null) {
226            kind = addKind(new DataKind(Email.CONTENT_ITEM_TYPE,
227                    R.string.emailLabelsGroup, android.R.drawable.sym_action_email, 15, true));
228            kind.actionHeader = new EmailActionInflater();
229            kind.actionBody = new SimpleInflater(Email.DATA);
230        }
231
232        if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
233            kind.typeColumn = Email.TYPE;
234            kind.typeList = Lists.newArrayList();
235            kind.typeList.add(buildEmailType(Email.TYPE_HOME));
236            kind.typeList.add(buildEmailType(Email.TYPE_WORK));
237            kind.typeList.add(buildEmailType(Email.TYPE_OTHER));
238            kind.typeList.add(buildEmailType(Email.TYPE_MOBILE));
239            kind.typeList.add(buildEmailType(Email.TYPE_CUSTOM).setSecondary(true).setCustomColumn(
240                    Email.LABEL));
241
242            kind.fieldList = Lists.newArrayList();
243            kind.fieldList.add(new EditField(Email.DATA, R.string.emailLabelsGroup, FLAGS_EMAIL));
244        }
245
246        return kind;
247    }
248
249    protected DataKind inflateStructuredPostal(Context context, int inflateLevel) {
250        DataKind kind = getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
251        if (kind == null) {
252            kind = addKind(new DataKind(StructuredPostal.CONTENT_ITEM_TYPE,
253                    R.string.postalLabelsGroup, R.drawable.sym_action_map, 25, true));
254            kind.actionHeader = new PostalActionInflater();
255            kind.actionBody = new SimpleInflater(StructuredPostal.FORMATTED_ADDRESS);
256        }
257
258        if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
259            final boolean useJapaneseOrder =
260                Locale.JAPANESE.getLanguage().equals(Locale.getDefault().getLanguage());
261            kind.typeColumn = StructuredPostal.TYPE;
262            kind.typeList = Lists.newArrayList();
263            kind.typeList.add(buildPostalType(StructuredPostal.TYPE_HOME));
264            kind.typeList.add(buildPostalType(StructuredPostal.TYPE_WORK));
265            kind.typeList.add(buildPostalType(StructuredPostal.TYPE_OTHER));
266            kind.typeList.add(buildPostalType(StructuredPostal.TYPE_CUSTOM).setSecondary(true)
267                    .setCustomColumn(StructuredPostal.LABEL));
268
269            kind.fieldList = Lists.newArrayList();
270
271            if (useJapaneseOrder) {
272                kind.fieldList.add(new EditField(StructuredPostal.COUNTRY,
273                        R.string.postal_country, FLAGS_POSTAL).setOptional(true));
274                kind.fieldList.add(new EditField(StructuredPostal.POSTCODE,
275                        R.string.postal_postcode, FLAGS_POSTAL));
276                kind.fieldList.add(new EditField(StructuredPostal.REGION,
277                        R.string.postal_region, FLAGS_POSTAL));
278                kind.fieldList.add(new EditField(StructuredPostal.CITY,
279                        R.string.postal_city, FLAGS_POSTAL));
280                kind.fieldList.add(new EditField(StructuredPostal.NEIGHBORHOOD,
281                        R.string.postal_neighborhood, FLAGS_POSTAL).setOptional(true));
282                kind.fieldList.add(new EditField(StructuredPostal.STREET,
283                        R.string.postal_street, FLAGS_POSTAL));
284                kind.fieldList.add(new EditField(StructuredPostal.POBOX,
285                        R.string.postal_pobox, FLAGS_POSTAL).setOptional(true));
286            } else {
287                kind.fieldList.add(new EditField(StructuredPostal.STREET,
288                        R.string.postal_street, FLAGS_POSTAL));
289                kind.fieldList.add(new EditField(StructuredPostal.POBOX,
290                        R.string.postal_pobox, FLAGS_POSTAL).setOptional(true));
291                kind.fieldList.add(new EditField(StructuredPostal.NEIGHBORHOOD,
292                        R.string.postal_neighborhood, FLAGS_POSTAL).setOptional(true));
293                kind.fieldList.add(new EditField(StructuredPostal.CITY,
294                        R.string.postal_city, FLAGS_POSTAL));
295                kind.fieldList.add(new EditField(StructuredPostal.REGION,
296                        R.string.postal_region, FLAGS_POSTAL));
297                kind.fieldList.add(new EditField(StructuredPostal.POSTCODE,
298                        R.string.postal_postcode, FLAGS_POSTAL));
299                kind.fieldList.add(new EditField(StructuredPostal.COUNTRY,
300                        R.string.postal_country, FLAGS_POSTAL).setOptional(true));
301            }
302        }
303
304        return kind;
305    }
306
307    protected DataKind inflateIm(Context context, int inflateLevel) {
308        DataKind kind = getKindForMimetype(Im.CONTENT_ITEM_TYPE);
309        if (kind == null) {
310            kind = addKind(new DataKind(Im.CONTENT_ITEM_TYPE, R.string.imLabelsGroup,
311                    android.R.drawable.sym_action_chat, 20, true));
312            kind.secondary = true;
313            kind.actionHeader = new ImActionInflater();
314            kind.actionBody = new SimpleInflater(Im.DATA);
315        }
316
317        if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
318            // NOTE: even though a traditional "type" exists, for editing
319            // purposes we're using the protocol to pick labels
320
321            kind.defaultValues = new ContentValues();
322            kind.defaultValues.put(Im.TYPE, Im.TYPE_OTHER);
323
324            kind.typeColumn = Im.PROTOCOL;
325            kind.typeList = Lists.newArrayList();
326            kind.typeList.add(buildImType(Im.PROTOCOL_AIM));
327            kind.typeList.add(buildImType(Im.PROTOCOL_MSN));
328            kind.typeList.add(buildImType(Im.PROTOCOL_YAHOO));
329            kind.typeList.add(buildImType(Im.PROTOCOL_SKYPE));
330            kind.typeList.add(buildImType(Im.PROTOCOL_QQ));
331            kind.typeList.add(buildImType(Im.PROTOCOL_GOOGLE_TALK));
332            kind.typeList.add(buildImType(Im.PROTOCOL_ICQ));
333            kind.typeList.add(buildImType(Im.PROTOCOL_JABBER));
334            kind.typeList.add(buildImType(Im.PROTOCOL_CUSTOM).setSecondary(true).setCustomColumn(
335                    Im.CUSTOM_PROTOCOL));
336
337            kind.fieldList = Lists.newArrayList();
338            kind.fieldList.add(new EditField(Im.DATA, R.string.imLabelsGroup, FLAGS_EMAIL));
339        }
340
341        return kind;
342    }
343
344    protected DataKind inflateOrganization(Context context, int inflateLevel) {
345        DataKind kind = getKindForMimetype(Organization.CONTENT_ITEM_TYPE);
346        if (kind == null) {
347            kind = addKind(new DataKind(Organization.CONTENT_ITEM_TYPE,
348                    R.string.organizationLabelsGroup, R.drawable.sym_action_organization, 30, true));
349            kind.actionHeader = new SimpleInflater(Organization.COMPANY);
350            kind.actionBody = new SimpleInflater(Organization.TITLE);
351        }
352
353        if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
354            kind.typeColumn = Organization.TYPE;
355            kind.typeList = Lists.newArrayList();
356            kind.typeList.add(buildOrgType(Organization.TYPE_WORK));
357            kind.typeList.add(buildOrgType(Organization.TYPE_OTHER));
358            kind.typeList.add(buildOrgType(Organization.TYPE_CUSTOM).setSecondary(true)
359                    .setCustomColumn(Organization.LABEL));
360
361            kind.fieldList = Lists.newArrayList();
362            kind.fieldList.add(new EditField(Organization.COMPANY, R.string.ghostData_company,
363                    FLAGS_GENERIC_NAME));
364            kind.fieldList.add(new EditField(Organization.TITLE, R.string.ghostData_title,
365                    FLAGS_GENERIC_NAME));
366        }
367
368        return kind;
369    }
370
371    protected DataKind inflatePhoto(Context context, int inflateLevel) {
372        DataKind kind = getKindForMimetype(Photo.CONTENT_ITEM_TYPE);
373        if (kind == null) {
374            kind = addKind(new DataKind(Photo.CONTENT_ITEM_TYPE, -1, -1, -1, true));
375        }
376
377        if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
378            kind.fieldList = Lists.newArrayList();
379            kind.fieldList.add(new EditField(Photo.PHOTO, -1, -1));
380        }
381
382        return kind;
383    }
384
385    protected DataKind inflateNote(Context context, int inflateLevel) {
386        DataKind kind = getKindForMimetype(Note.CONTENT_ITEM_TYPE);
387        if (kind == null) {
388            kind = addKind(new DataKind(Note.CONTENT_ITEM_TYPE,
389                    R.string.label_notes, R.drawable.sym_note, 110, true));
390            kind.isList = false;
391            kind.secondary = true;
392            kind.actionHeader = new SimpleInflater(R.string.label_notes);
393            kind.actionBody = new SimpleInflater(Note.NOTE);
394        }
395
396        if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
397            kind.fieldList = Lists.newArrayList();
398            kind.fieldList.add(new EditField(Note.NOTE, R.string.label_notes, FLAGS_NOTE));
399        }
400
401        return kind;
402    }
403
404    protected DataKind inflateWebsite(Context context, int inflateLevel) {
405        DataKind kind = getKindForMimetype(Website.CONTENT_ITEM_TYPE);
406        if (kind == null) {
407            kind = addKind(new DataKind(Website.CONTENT_ITEM_TYPE,
408                    R.string.websiteLabelsGroup, -1, 120, true));
409            kind.secondary = true;
410            kind.actionHeader = new SimpleInflater(R.string.websiteLabelsGroup);
411            kind.actionBody = new SimpleInflater(Website.URL);
412        }
413
414        if (inflateLevel >= ContactsSource.LEVEL_CONSTRAINTS) {
415            kind.defaultValues = new ContentValues();
416            kind.defaultValues.put(Website.TYPE, Website.TYPE_OTHER);
417
418            kind.fieldList = Lists.newArrayList();
419            kind.fieldList.add(new EditField(Website.URL, R.string.websiteLabelsGroup, FLAGS_WEBSITE));
420        }
421
422        return kind;
423    }
424
425    protected DataKind inflateEvent(Context context, int inflateLevel) {
426        DataKind kind = getKindForMimetype(Event.CONTENT_ITEM_TYPE);
427        if (kind == null) {
428            kind = addKind(new DataKind(Event.CONTENT_ITEM_TYPE,
429                    R.string.eventLabelsGroup, -1, 150, false));
430            kind.secondary = true;
431            kind.actionHeader = new EventActionInflater();
432            kind.actionBody = new SimpleInflater(Event.START_DATE);
433        }
434
435        return kind;
436    }
437
438    /**
439     * Simple inflater that assumes a string resource has a "%s" that will be
440     * filled from the given column.
441     */
442    public static class SimpleInflater implements StringInflater {
443        private final int mStringRes;
444        private final String mColumnName;
445
446        public SimpleInflater(int stringRes) {
447            this(stringRes, null);
448        }
449
450        public SimpleInflater(String columnName) {
451            this(-1, columnName);
452        }
453
454        public SimpleInflater(int stringRes, String columnName) {
455            mStringRes = stringRes;
456            mColumnName = columnName;
457        }
458
459        public CharSequence inflateUsing(Context context, Cursor cursor) {
460            final int index = mColumnName != null ? cursor.getColumnIndex(mColumnName) : -1;
461            final boolean validString = mStringRes > 0;
462            final boolean validColumn = index != -1;
463
464            final CharSequence stringValue = validString ? context.getText(mStringRes) : null;
465            final CharSequence columnValue = validColumn ? cursor.getString(index) : null;
466
467            if (validString && validColumn) {
468                return String.format(stringValue.toString(), columnValue);
469            } else if (validString) {
470                return stringValue;
471            } else if (validColumn) {
472                return columnValue;
473            } else {
474                return null;
475            }
476        }
477
478        public CharSequence inflateUsing(Context context, ContentValues values) {
479            final boolean validColumn = values.containsKey(mColumnName);
480            final boolean validString = mStringRes > 0;
481
482            final CharSequence stringValue = validString ? context.getText(mStringRes) : null;
483            final CharSequence columnValue = validColumn ? values.getAsString(mColumnName) : null;
484
485            if (validString && validColumn) {
486                return String.format(stringValue.toString(), columnValue);
487            } else if (validString) {
488                return stringValue;
489            } else if (validColumn) {
490                return columnValue;
491            } else {
492                return null;
493            }
494        }
495    }
496
497    public static abstract class CommonInflater implements StringInflater {
498        protected abstract int getTypeLabelResource(Integer type);
499
500        protected boolean isCustom(Integer type) {
501            return type == BaseTypes.TYPE_CUSTOM;
502        }
503
504        protected String getTypeColumn() {
505            return Phone.TYPE;
506        }
507
508        protected String getLabelColumn() {
509            return Phone.LABEL;
510        }
511
512        protected CharSequence getTypeLabel(Resources res, Integer type, CharSequence label) {
513            final int labelRes = getTypeLabelResource(type);
514            if (type == null) {
515                return res.getText(labelRes);
516            } else if (isCustom(type)) {
517                return res.getString(labelRes, label == null ? "" : label);
518            } else {
519                return res.getText(labelRes);
520            }
521        }
522
523        public CharSequence inflateUsing(Context context, Cursor cursor) {
524            final Integer type = cursor.getInt(cursor.getColumnIndex(getTypeColumn()));
525            final String label = cursor.getString(cursor.getColumnIndex(getLabelColumn()));
526            return getTypeLabel(context.getResources(), type, label);
527        }
528
529        public CharSequence inflateUsing(Context context, ContentValues values) {
530            final Integer type = values.getAsInteger(getTypeColumn());
531            final String label = values.getAsString(getLabelColumn());
532            return getTypeLabel(context.getResources(), type, label);
533        }
534    }
535
536    public static class PhoneActionInflater extends CommonInflater {
537        @Override
538        protected boolean isCustom(Integer type) {
539            return type == Phone.TYPE_CUSTOM || type == Phone.TYPE_ASSISTANT;
540        }
541
542        @Override
543        protected int getTypeLabelResource(Integer type) {
544            if (type == null) return R.string.call_other;
545            switch (type) {
546                case Phone.TYPE_HOME: return R.string.call_home;
547                case Phone.TYPE_MOBILE: return R.string.call_mobile;
548                case Phone.TYPE_WORK: return R.string.call_work;
549                case Phone.TYPE_FAX_WORK: return R.string.call_fax_work;
550                case Phone.TYPE_FAX_HOME: return R.string.call_fax_home;
551                case Phone.TYPE_PAGER: return R.string.call_pager;
552                case Phone.TYPE_OTHER: return R.string.call_other;
553                case Phone.TYPE_CALLBACK: return R.string.call_callback;
554                case Phone.TYPE_CAR: return R.string.call_car;
555                case Phone.TYPE_COMPANY_MAIN: return R.string.call_company_main;
556                case Phone.TYPE_ISDN: return R.string.call_isdn;
557                case Phone.TYPE_MAIN: return R.string.call_main;
558                case Phone.TYPE_OTHER_FAX: return R.string.call_other_fax;
559                case Phone.TYPE_RADIO: return R.string.call_radio;
560                case Phone.TYPE_TELEX: return R.string.call_telex;
561                case Phone.TYPE_TTY_TDD: return R.string.call_tty_tdd;
562                case Phone.TYPE_WORK_MOBILE: return R.string.call_work_mobile;
563                case Phone.TYPE_WORK_PAGER: return R.string.call_work_pager;
564                case Phone.TYPE_ASSISTANT: return R.string.call_assistant;
565                case Phone.TYPE_MMS: return R.string.call_mms;
566                default: return R.string.call_custom;
567            }
568        }
569    }
570
571    public static class PhoneActionAltInflater extends CommonInflater {
572        @Override
573        protected boolean isCustom(Integer type) {
574            return (type == Phone.TYPE_CUSTOM || type == Phone.TYPE_ASSISTANT);
575        }
576
577        @Override
578        protected int getTypeLabelResource(Integer type) {
579            if (type == null) return R.string.sms_other;
580            switch (type) {
581                case Phone.TYPE_HOME: return R.string.sms_home;
582                case Phone.TYPE_MOBILE: return R.string.sms_mobile;
583                case Phone.TYPE_WORK: return R.string.sms_work;
584                case Phone.TYPE_FAX_WORK: return R.string.sms_fax_work;
585                case Phone.TYPE_FAX_HOME: return R.string.sms_fax_home;
586                case Phone.TYPE_PAGER: return R.string.sms_pager;
587                case Phone.TYPE_OTHER: return R.string.sms_other;
588                case Phone.TYPE_CALLBACK: return R.string.sms_callback;
589                case Phone.TYPE_CAR: return R.string.sms_car;
590                case Phone.TYPE_COMPANY_MAIN: return R.string.sms_company_main;
591                case Phone.TYPE_ISDN: return R.string.sms_isdn;
592                case Phone.TYPE_MAIN: return R.string.sms_main;
593                case Phone.TYPE_OTHER_FAX: return R.string.sms_other_fax;
594                case Phone.TYPE_RADIO: return R.string.sms_radio;
595                case Phone.TYPE_TELEX: return R.string.sms_telex;
596                case Phone.TYPE_TTY_TDD: return R.string.sms_tty_tdd;
597                case Phone.TYPE_WORK_MOBILE: return R.string.sms_work_mobile;
598                case Phone.TYPE_WORK_PAGER: return R.string.sms_work_pager;
599                case Phone.TYPE_ASSISTANT: return R.string.sms_assistant;
600                case Phone.TYPE_MMS: return R.string.sms_mms;
601                default: return R.string.sms_custom;
602            }
603        }
604    }
605
606    public static class EmailActionInflater extends CommonInflater {
607        @Override
608        protected int getTypeLabelResource(Integer type) {
609            if (type == null) return R.string.email;
610            switch (type) {
611                case Email.TYPE_HOME: return R.string.email_home;
612                case Email.TYPE_WORK: return R.string.email_work;
613                case Email.TYPE_OTHER: return R.string.email_other;
614                case Email.TYPE_MOBILE: return R.string.email_mobile;
615                default: return R.string.email_custom;
616            }
617        }
618    }
619
620    public static class EventActionInflater extends CommonInflater {
621        @Override
622        protected int getTypeLabelResource(Integer type) {
623            return Event.getTypeResource(type);
624        }
625    }
626
627    public static class PostalActionInflater extends CommonInflater {
628        @Override
629        protected int getTypeLabelResource(Integer type) {
630            if (type == null) return R.string.map_other;
631            switch (type) {
632                case StructuredPostal.TYPE_HOME: return R.string.map_home;
633                case StructuredPostal.TYPE_WORK: return R.string.map_work;
634                case StructuredPostal.TYPE_OTHER: return R.string.map_other;
635                default: return R.string.map_custom;
636            }
637        }
638    }
639
640    public static class ImActionInflater extends CommonInflater {
641        @Override
642        protected String getTypeColumn() {
643            return Im.PROTOCOL;
644        }
645
646        @Override
647        protected String getLabelColumn() {
648            return Im.CUSTOM_PROTOCOL;
649        }
650
651        @Override
652        protected int getTypeLabelResource(Integer type) {
653            if (type == null) return R.string.chat;
654            switch (type) {
655                case Im.PROTOCOL_AIM: return R.string.chat_aim;
656                case Im.PROTOCOL_MSN: return R.string.chat_msn;
657                case Im.PROTOCOL_YAHOO: return R.string.chat_yahoo;
658                case Im.PROTOCOL_SKYPE: return R.string.chat_skype;
659                case Im.PROTOCOL_QQ: return R.string.chat_qq;
660                case Im.PROTOCOL_GOOGLE_TALK: return R.string.chat_gtalk;
661                case Im.PROTOCOL_ICQ: return R.string.chat_icq;
662                case Im.PROTOCOL_JABBER: return R.string.chat_jabber;
663                case Im.PROTOCOL_NETMEETING: return R.string.chat;
664                default: return R.string.chat;
665            }
666        }
667    }
668
669    @Override
670    public int getHeaderColor(Context context) {
671        return 0xff7f93bc;
672    }
673
674    @Override
675    public int getSideBarColor(Context context) {
676        return 0xffbdc7b8;
677    }
678}
679