Contacts.java revision b798689749c64baba81f02e10cf2157c747d6b46
1/*
2 * Copyright (C) 2006 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 android.provider;
18
19import com.android.internal.R;
20
21import android.content.ContentResolver;
22import android.content.ContentUris;
23import android.content.ContentValues;
24import android.content.Context;
25import android.content.Intent;
26import android.database.Cursor;
27import android.graphics.Bitmap;
28import android.graphics.BitmapFactory;
29import android.net.Uri;
30import android.text.TextUtils;
31import android.util.Log;
32import android.widget.ImageView;
33
34import java.io.ByteArrayInputStream;
35import java.io.InputStream;
36
37/**
38 * The Contacts provider stores all information about contacts.
39 */
40public class Contacts {
41    private static final String TAG = "Contacts";
42
43    public static final String AUTHORITY = "contacts";
44
45    /**
46     * The content:// style URL for this provider
47     */
48    public static final Uri CONTENT_URI =
49        Uri.parse("content://" + AUTHORITY);
50
51    /** Signifies an email address row that is stored in the ContactMethods table */
52    public static final int KIND_EMAIL = 1;
53    /** Signifies a postal address row that is stored in the ContactMethods table */
54    public static final int KIND_POSTAL = 2;
55    /** Signifies an IM address row that is stored in the ContactMethods table */
56    public static final int KIND_IM = 3;
57    /** Signifies an Organization row that is stored in the Organizations table */
58    public static final int KIND_ORGANIZATION = 4;
59    /** Signifies an Phone row that is stored in the Phones table */
60    public static final int KIND_PHONE = 5;
61
62    /**
63     * no public constructor since this is a utility class
64     */
65    private Contacts() {}
66
67    /**
68     * Columns from the Settings table that other columns join into themselves.
69     */
70    public interface SettingsColumns {
71        /**
72         * The _SYNC_ACCOUNT to which this setting corresponds. This may be null.
73         * <P>Type: TEXT</P>
74         */
75        public static final String _SYNC_ACCOUNT = "_sync_account";
76
77        /**
78         * The key of this setting.
79         * <P>Type: TEXT</P>
80         */
81        public static final String KEY = "key";
82
83        /**
84         * The value of this setting.
85         * <P>Type: TEXT</P>
86         */
87        public static final String VALUE = "value";
88    }
89
90    /**
91     * The settings over all of the people
92     */
93    public static final class Settings implements BaseColumns, SettingsColumns {
94        /**
95         * no public constructor since this is a utility class
96         */
97        private Settings() {}
98
99        /**
100         * The content:// style URL for this table
101         */
102        public static final Uri CONTENT_URI =
103            Uri.parse("content://contacts/settings");
104
105        /**
106         * The directory twig for this sub-table
107         */
108        public static final String CONTENT_DIRECTORY = "settings";
109
110        /**
111         * The default sort order for this table
112         */
113        public static final String DEFAULT_SORT_ORDER = "key ASC";
114
115        /**
116         * A setting that is used to indicate if we should sync down all groups for the
117         * specified account. For this setting the _SYNC_ACCOUNT column must be set.
118         * If this isn't set then we will only sync the groups whose SHOULD_SYNC column
119         * is set to true.
120         * <p>
121         * This is a boolean setting. It is true if it is set and it is anything other than the
122         * emptry string or "0".
123         */
124        public static final String SYNC_EVERYTHING = "syncEverything";
125
126        public static String getSetting(ContentResolver cr, String account, String key) {
127            // For now we only support a single account and the UI doesn't know what
128            // the account name is, so we're using a global setting for SYNC_EVERYTHING.
129            // Some day when we add multiple accounts to the UI this should honor the account
130            // that was asked for.
131            String selectString;
132            String[] selectArgs;
133            if (false) {
134                selectString = (account == null)
135                        ? "_sync_account is null AND key=?"
136                        : "_sync_account=? AND key=?";
137                selectArgs = (account == null)
138                ? new String[]{key}
139                : new String[]{account, key};
140            } else {
141                selectString = "key=?";
142                selectArgs = new String[] {key};
143            }
144            Cursor cursor = cr.query(Settings.CONTENT_URI, new String[]{VALUE},
145                    selectString, selectArgs, null);
146            try {
147                if (!cursor.moveToNext()) return null;
148                return cursor.getString(0);
149            } finally {
150                cursor.close();
151            }
152        }
153
154        public static void setSetting(ContentResolver cr, String account, String key,
155                String value) {
156            ContentValues values = new ContentValues();
157            // For now we only support a single account and the UI doesn't know what
158            // the account name is, so we're using a global setting for SYNC_EVERYTHING.
159            // Some day when we add multiple accounts to the UI this should honor the account
160            // that was asked for.
161            //values.put(_SYNC_ACCOUNT, account);
162            values.put(KEY, key);
163            values.put(VALUE, value);
164            cr.update(Settings.CONTENT_URI, values, null, null);
165        }
166    }
167
168    /**
169     * Columns from the People table that other tables join into themselves.
170     */
171    public interface PeopleColumns {
172        /**
173         * The person's name.
174         * <P>Type: TEXT</P>
175         */
176        public static final String NAME = "name";
177
178        /**
179         * Phonetic equivalent of the person's name, in a locale-dependent
180         * character set (e.g. hiragana for Japanese).
181         * Used for pronunciation and/or collation in some languages.
182         * <p>Type: TEXT</P>
183         */
184        public static final String PHONETIC_NAME = "phonetic_name";
185
186        /**
187         * The display name. If name is not null name, else if number is not null number,
188         * else if email is not null email.
189         * <P>Type: TEXT</P>
190         */
191        public static final String DISPLAY_NAME = "display_name";
192
193        /**
194         * Notes about the person.
195         * <P>Type: TEXT</P>
196         */
197        public static final String NOTES = "notes";
198
199        /**
200         * The number of times a person has been contacted
201         * <P>Type: INTEGER</P>
202         */
203        public static final String TIMES_CONTACTED = "times_contacted";
204
205        /**
206         * The last time a person was contacted.
207         * <P>Type: INTEGER</P>
208         */
209        public static final String LAST_TIME_CONTACTED = "last_time_contacted";
210
211        /**
212         * A custom ringtone associated with a person. Not always present.
213         * <P>Type: TEXT (URI to the ringtone)</P>
214         */
215        public static final String CUSTOM_RINGTONE = "custom_ringtone";
216
217        /**
218         * Whether the person should always be sent to voicemail. Not always
219         * present.
220         * <P>Type: INTEGER (0 for false, 1 for true)</P>
221         */
222        public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
223
224        /**
225         * Is the contact starred?
226         * <P>Type: INTEGER (boolean)</P>
227         */
228        public static final String STARRED = "starred";
229
230        /**
231         * The server version of the photo
232         * <P>Type: TEXT (the version number portion of the photo URI)</P>
233         */
234        public static final String PHOTO_VERSION = "photo_version";
235    }
236
237    /**
238     * This table contains people.
239     */
240    public static final class People implements BaseColumns, SyncConstValue, PeopleColumns,
241            PhonesColumns, PresenceColumns {
242        /**
243         * no public constructor since this is a utility class
244         */
245        private People() {}
246
247        /**
248         * The content:// style URL for this table
249         */
250        public static final Uri CONTENT_URI =
251            Uri.parse("content://contacts/people");
252
253        /**
254         * The content:// style URL for filtering people by name. The filter
255         * argument should be passed as an additional path segment after this URI.
256         */
257        public static final Uri CONTENT_FILTER_URI =
258            Uri.parse("content://contacts/people/filter");
259
260        /**
261         * The content:// style URL for the table that holds the deleted
262         * contacts.
263         */
264        public static final Uri DELETED_CONTENT_URI =
265            Uri.parse("content://contacts/deleted_people");
266
267        /**
268         * The MIME type of {@link #CONTENT_URI} providing a directory of
269         * people.
270         */
271        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person";
272
273        /**
274         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
275         * person.
276         */
277        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person";
278
279        /**
280         * The default sort order for this table
281         */
282        public static final String DEFAULT_SORT_ORDER = People.NAME + " ASC";
283
284        /**
285         * The ID of the persons preferred phone number.
286         * <P>Type: INTEGER (foreign key to phones table on the _ID field)</P>
287         */
288        public static final String PRIMARY_PHONE_ID = "primary_phone";
289
290        /**
291         * The ID of the persons preferred email.
292         * <P>Type: INTEGER (foreign key to contact_methods table on the
293         * _ID field)</P>
294         */
295        public static final String PRIMARY_EMAIL_ID = "primary_email";
296
297        /**
298         * The ID of the persons preferred organization.
299         * <P>Type: INTEGER (foreign key to organizations table on the
300         * _ID field)</P>
301         */
302        public static final String PRIMARY_ORGANIZATION_ID = "primary_organization";
303
304        /**
305         * Mark a person as having been contacted.
306         *
307         * @param resolver the ContentResolver to use
308         * @param personId the person who was contacted
309         */
310        public static void markAsContacted(ContentResolver resolver, long personId) {
311            Uri uri = ContentUris.withAppendedId(CONTENT_URI, personId);
312            uri = Uri.withAppendedPath(uri, "update_contact_time");
313            ContentValues values = new ContentValues();
314            // There is a trigger in place that will update TIMES_CONTACTED when
315            // LAST_TIME_CONTACTED is modified.
316            values.put(LAST_TIME_CONTACTED, System.currentTimeMillis());
317            resolver.update(uri, values, null, null);
318        }
319
320        /**
321         * Adds a person to the My Contacts group.
322         *
323         * @param resolver the resolver to use
324         * @param personId the person to add to the group
325         * @return the URI of the group membership row
326         * @throws IllegalStateException if the My Contacts group can't be found
327         */
328        public static Uri addToMyContactsGroup(ContentResolver resolver, long personId) {
329            long groupId = 0;
330            Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION,
331                    Groups.SYSTEM_ID + "='" + Groups.GROUP_MY_CONTACTS + "'", null, null);
332            if (groupsCursor != null) {
333                try {
334                    if (groupsCursor.moveToFirst()) {
335                        groupId = groupsCursor.getLong(0);
336                    }
337                } finally {
338                    groupsCursor.close();
339                }
340            }
341
342            if (groupId == 0) {
343                throw new IllegalStateException("Failed to find the My Contacts group");
344            }
345
346            return addToGroup(resolver, personId, groupId);
347        }
348
349        /**
350         * Adds a person to a group referred to by name.
351         *
352         * @param resolver the resolver to use
353         * @param personId the person to add to the group
354         * @param groupName the name of the group to add the contact to
355         * @return the URI of the group membership row
356         * @throws IllegalStateException if the group can't be found
357         */
358        public static Uri addToGroup(ContentResolver resolver, long personId, String groupName) {
359            long groupId = 0;
360            Cursor groupsCursor = resolver.query(Groups.CONTENT_URI, GROUPS_PROJECTION,
361                    Groups.NAME + "=?", new String[] { groupName }, null);
362            if (groupsCursor != null) {
363                try {
364                    if (groupsCursor.moveToFirst()) {
365                        groupId = groupsCursor.getLong(0);
366                    }
367                } finally {
368                    groupsCursor.close();
369                }
370            }
371
372            if (groupId == 0) {
373                throw new IllegalStateException("Failed to find the My Contacts group");
374            }
375
376            return addToGroup(resolver, personId, groupId);
377        }
378
379        /**
380         * Adds a person to a group.
381         *
382         * @param resolver the resolver to use
383         * @param personId the person to add to the group
384         * @param groupId the group to add the person to
385         * @return the URI of the group membership row
386         */
387        public static Uri addToGroup(ContentResolver resolver, long personId, long groupId) {
388            ContentValues values = new ContentValues();
389            values.put(GroupMembership.PERSON_ID, personId);
390            values.put(GroupMembership.GROUP_ID, groupId);
391            return resolver.insert(GroupMembership.CONTENT_URI, values);
392        }
393
394        private static final String[] GROUPS_PROJECTION = new String[] {
395            Groups._ID,
396        };
397
398        /**
399         * Creates a new contacts and adds it to the "My Contacts" group.
400         *
401         * @param resolver the ContentResolver to use
402         * @param values the values to use when creating the contact
403         * @return the URI of the contact, or null if the operation fails
404         */
405        public static Uri createPersonInMyContactsGroup(ContentResolver resolver,
406                ContentValues values) {
407
408            Uri contactUri = resolver.insert(People.CONTENT_URI, values);
409            if (contactUri == null) {
410                Log.e(TAG, "Failed to create the contact");
411                return null;
412            }
413
414            if (addToMyContactsGroup(resolver, ContentUris.parseId(contactUri)) == null) {
415                resolver.delete(contactUri, null, null);
416                return null;
417            }
418            return contactUri;
419        }
420
421        public static Cursor queryGroups(ContentResolver resolver, long person) {
422            return resolver.query(GroupMembership.CONTENT_URI, null, "person=?",
423                    new String[]{String.valueOf(person)}, Groups.DEFAULT_SORT_ORDER);
424        }
425
426        /**
427         * Set the photo for this person. data may be null
428         * @param cr the ContentResolver to use
429         * @param person the Uri of the person whose photo is to be updated
430         * @param data the byte[] that represents the photo
431         */
432        public static void setPhotoData(ContentResolver cr, Uri person, byte[] data) {
433            Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY);
434            ContentValues values = new ContentValues();
435            values.put(Photos.DATA, data);
436            cr.update(photoUri, values, null, null);
437        }
438
439        /**
440         * Opens an InputStream for the person's photo and returns the photo as a Bitmap.
441         * If the person's photo isn't present returns the placeholderImageResource instead.
442         * @param person the person whose photo should be used
443         */
444        public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri person) {
445            Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY);
446            Cursor cursor = cr.query(photoUri, new String[]{Photos.DATA}, null, null, null);
447            try {
448                if (!cursor.moveToNext()) {
449                    return null;
450                }
451                byte[] data = cursor.getBlob(0);
452                if (data == null) {
453                    return null;
454                }
455                return new ByteArrayInputStream(data);
456            } finally {
457                cursor.close();
458            }
459        }
460
461        /**
462         * Opens an InputStream for the person's photo and returns the photo as a Bitmap.
463         * If the person's photo isn't present returns the placeholderImageResource instead.
464         * @param context the Context
465         * @param person the person whose photo should be used
466         * @param placeholderImageResource the image resource to use if the person doesn't
467         *   have a photo
468         * @param options the decoding options, can be set to null
469         */
470        public static Bitmap loadContactPhoto(Context context, Uri person,
471                int placeholderImageResource, BitmapFactory.Options options) {
472            if (person == null) {
473                return loadPlaceholderPhoto(placeholderImageResource, context, options);
474            }
475
476            InputStream stream = openContactPhotoInputStream(context.getContentResolver(), person);
477            Bitmap bm = stream != null ? BitmapFactory.decodeStream(stream, null, options) : null;
478            if (bm == null) {
479                bm = loadPlaceholderPhoto(placeholderImageResource, context, options);
480            }
481            return bm;
482        }
483
484        private static Bitmap loadPlaceholderPhoto(int placeholderImageResource, Context context,
485                BitmapFactory.Options options) {
486            if (placeholderImageResource == 0) {
487                return null;
488            }
489            return BitmapFactory.decodeResource(context.getResources(),
490                    placeholderImageResource, options);
491        }
492
493        /**
494         * A sub directory of a single person that contains all of their Phones.
495         */
496        public static final class Phones implements BaseColumns, PhonesColumns,
497                PeopleColumns {
498            /**
499             * no public constructor since this is a utility class
500             */
501            private Phones() {}
502
503            /**
504             * The directory twig for this sub-table
505             */
506            public static final String CONTENT_DIRECTORY = "phones";
507
508            /**
509             * The default sort order for this table
510             */
511            public static final String DEFAULT_SORT_ORDER = "number ASC";
512        }
513
514        /**
515         * A subdirectory of a single person that contains all of their
516         * ContactMethods.
517         */
518        public static final class ContactMethods
519                implements BaseColumns, ContactMethodsColumns, PeopleColumns {
520            /**
521             * no public constructor since this is a utility class
522             */
523            private ContactMethods() {}
524
525            /**
526             * The directory twig for this sub-table
527             */
528            public static final String CONTENT_DIRECTORY = "contact_methods";
529
530            /**
531             * The default sort order for this table
532             */
533            public static final String DEFAULT_SORT_ORDER = "data ASC";
534        }
535
536        /**
537         * The extensions for a person
538         */
539        public static class Extensions implements BaseColumns, ExtensionsColumns {
540            /**
541             * no public constructor since this is a utility class
542             */
543            private Extensions() {}
544
545            /**
546             * The directory twig for this sub-table
547             */
548            public static final String CONTENT_DIRECTORY = "extensions";
549
550            /**
551             * The default sort order for this table
552             */
553            public static final String DEFAULT_SORT_ORDER = "name ASC";
554
555            /**
556             * The ID of the person this phone number is assigned to.
557             * <P>Type: INTEGER (long)</P>
558             */
559            public static final String PERSON_ID = "person";
560        }
561    }
562
563    /**
564     * Columns from the groups table.
565     */
566    public interface GroupsColumns {
567        /**
568         * The group name.
569         * <P>Type: TEXT</P>
570         */
571        public static final String NAME = "name";
572
573        /**
574         * Notes about the group.
575         * <P>Type: TEXT</P>
576         */
577        public static final String NOTES = "notes";
578
579        /**
580         * Whether this group should be synced if the SYNC_EVERYTHING settings is false
581         * for this group's account.
582         * <P>Type: INTEGER (boolean)</P>
583         */
584        public static final String SHOULD_SYNC = "should_sync";
585
586        /**
587         * The ID of this group if it is a System Group, null otherwise.
588         * <P>Type: TEXT</P>
589         */
590        public static final String SYSTEM_ID = "system_id";
591    }
592
593    /**
594     * This table contains the groups for an account.
595     */
596    public static final class Groups
597            implements BaseColumns, SyncConstValue, GroupsColumns {
598        /**
599         * no public constructor since this is a utility class
600         */
601        private Groups() {}
602
603        /**
604         * The content:// style URL for this table
605         */
606        public static final Uri CONTENT_URI =
607            Uri.parse("content://contacts/groups");
608
609        /**
610         * The content:// style URL for the table that holds the deleted
611         * groups.
612         */
613        public static final Uri DELETED_CONTENT_URI =
614            Uri.parse("content://contacts/deleted_groups");
615
616        /**
617         * The MIME type of {@link #CONTENT_URI} providing a directory of
618         * groups.
619         */
620        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroup";
621
622        /**
623         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
624         * group.
625         */
626        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contactsgroup";
627
628        /**
629         * The default sort order for this table
630         */
631        public static final String DEFAULT_SORT_ORDER = NAME + " ASC";
632
633        /**
634         *
635         */
636        public static final String GROUP_ANDROID_STARRED = "Starred in Android";
637
638        /**
639         * The "My Contacts" system group.
640         */
641        public static final String GROUP_MY_CONTACTS = "Contacts";
642    }
643
644    /**
645     * Columns from the Phones table that other columns join into themselves.
646     */
647    public interface PhonesColumns {
648        /**
649         * The type of the the phone number.
650         * <P>Type: INTEGER (one of the constants below)</P>
651         */
652        public static final String TYPE = "type";
653
654        public static final int TYPE_CUSTOM = 0;
655        public static final int TYPE_HOME = 1;
656        public static final int TYPE_MOBILE = 2;
657        public static final int TYPE_WORK = 3;
658        public static final int TYPE_FAX_WORK = 4;
659        public static final int TYPE_FAX_HOME = 5;
660        public static final int TYPE_PAGER = 6;
661        public static final int TYPE_OTHER = 7;
662
663        /**
664         * The user provided label for the phone number, only used if TYPE is TYPE_CUSTOM.
665         * <P>Type: TEXT</P>
666         */
667        public static final String LABEL = "label";
668
669        /**
670         * The phone number as the user entered it.
671         * <P>Type: TEXT</P>
672         */
673        public static final String NUMBER = "number";
674
675        /**
676         * The normalized phone number
677         * <P>Type: TEXT</P>
678         */
679        public static final String NUMBER_KEY = "number_key";
680
681        /**
682         * Whether this is the primary phone number
683         * <P>Type: INTEGER (if set, non-0 means true)</P>
684         */
685        public static final String ISPRIMARY = "isprimary";
686    }
687
688    /**
689     * This table stores phone numbers and a reference to the person that the
690     * contact method belongs to. Phone numbers are stored separately from
691     * other contact methods to make caller ID lookup more efficient.
692     */
693    public static final class Phones
694            implements BaseColumns, PhonesColumns, PeopleColumns {
695        /**
696         * no public constructor since this is a utility class
697         */
698        private Phones() {}
699
700        public static final CharSequence getDisplayLabel(Context context, int type,
701                CharSequence label, CharSequence[] labelArray) {
702            CharSequence display = "";
703
704            if (type != People.Phones.TYPE_CUSTOM) {
705                CharSequence[] labels = labelArray != null? labelArray
706                        : context.getResources().getTextArray(
707                                com.android.internal.R.array.phoneTypes);
708                try {
709                    display = labels[type - 1];
710                } catch (ArrayIndexOutOfBoundsException e) {
711                    display = labels[People.Phones.TYPE_HOME - 1];
712                }
713            } else {
714                if (!TextUtils.isEmpty(label)) {
715                    display = label;
716                }
717            }
718            return display;
719        }
720
721        public static final CharSequence getDisplayLabel(Context context, int type,
722                CharSequence label) {
723            return getDisplayLabel(context, type, label, null);
724        }
725
726        /**
727         * The content:// style URL for this table
728         */
729        public static final Uri CONTENT_URI =
730            Uri.parse("content://contacts/phones");
731
732        /**
733         * The content:// style URL for filtering phone numbers
734         */
735        public static final Uri CONTENT_FILTER_URL =
736            Uri.parse("content://contacts/phones/filter");
737
738        /**
739         * The MIME type of {@link #CONTENT_URI} providing a directory of
740         * phones.
741         */
742        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone";
743
744        /**
745         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
746         * phone.
747         */
748        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone";
749
750        /**
751         * The default sort order for this table
752         */
753        public static final String DEFAULT_SORT_ORDER = "name ASC";
754
755        /**
756         * The ID of the person this phone number is assigned to.
757         * <P>Type: INTEGER (long)</P>
758         */
759        public static final String PERSON_ID = "person";
760    }
761
762    public static final class GroupMembership implements BaseColumns, GroupsColumns {
763        /**
764         * no public constructor since this is a utility class
765         */
766        private GroupMembership() {}
767
768        /**
769         * The content:// style URL for this table
770         */
771        public static final Uri CONTENT_URI =
772            Uri.parse("content://contacts/groupmembership");
773
774        /**
775         * The content:// style URL for this table
776         */
777        public static final Uri RAW_CONTENT_URI =
778            Uri.parse("content://contacts/groupmembershipraw");
779
780        /**
781         * The directory twig for this sub-table
782         */
783        public static final String CONTENT_DIRECTORY = "groupmembership";
784        /**
785         * The MIME type of {@link #CONTENT_URI} providing a directory of all
786         * person groups.
787         */
788        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contactsgroupmembership";
789
790        /**
791         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
792         * person group.
793         */
794        public static final String CONTENT_ITEM_TYPE =
795                "vnd.android.cursor.item/contactsgroupmembership";
796
797        /**
798         * The default sort order for this table
799         */
800        public static final String DEFAULT_SORT_ORDER = "group_id ASC";
801
802        /**
803         * The row id of the accounts group.
804         * <P>Type: TEXT</P>
805         */
806        public static final String GROUP_ID = "group_id";
807
808        /**
809         * The sync id of the group.
810         * <P>Type: TEXT</P>
811         */
812        public static final String GROUP_SYNC_ID = "group_sync_id";
813
814        /**
815         * The account of the group.
816         * <P>Type: TEXT</P>
817         */
818        public static final String GROUP_SYNC_ACCOUNT = "group_sync_account";
819
820        /**
821         * The row id of the person.
822         * <P>Type: TEXT</P>
823         */
824        public static final String PERSON_ID = "person";
825    }
826
827    /**
828     * Columns from the ContactMethods table that other tables join into
829     * themseleves.
830     */
831    public interface ContactMethodsColumns {
832        /**
833         * The kind of the the contact method. For example, email address,
834         * postal address, etc.
835         * <P>Type: INTEGER (one of the values below)</P>
836         */
837        public static final String KIND = "kind";
838
839        /**
840         * The type of the contact method, must be one of the types below.
841         * <P>Type: INTEGER (one of the values below)</P>
842         */
843        public static final String TYPE = "type";
844        public static final int TYPE_CUSTOM = 0;
845        public static final int TYPE_HOME = 1;
846        public static final int TYPE_WORK = 2;
847        public static final int TYPE_OTHER = 3;
848
849        /**
850         * The user defined label for the the contact method.
851         * <P>Type: TEXT</P>
852         */
853        public static final String LABEL = "label";
854
855        /**
856         * The data for the contact method.
857         * <P>Type: TEXT</P>
858         */
859        public static final String DATA = "data";
860
861        /**
862         * Auxiliary data for the contact method.
863         * <P>Type: TEXT</P>
864         */
865        public static final String AUX_DATA = "aux_data";
866
867        /**
868         * Whether this is the primary organization
869         * <P>Type: INTEGER (if set, non-0 means true)</P>
870         */
871        public static final String ISPRIMARY = "isprimary";
872    }
873
874    /**
875     * This table stores all non-phone contact methods and a reference to the
876     * person that the contact method belongs to.
877     */
878    public static final class ContactMethods
879            implements BaseColumns, ContactMethodsColumns, PeopleColumns {
880        /**
881         * The column with latitude data for postal locations
882         * <P>Type: REAL</P>
883         */
884        public static final String POSTAL_LOCATION_LATITUDE = DATA;
885
886        /**
887         * The column with longitude data for postal locations
888         * <P>Type: REAL</P>
889         */
890        public static final String POSTAL_LOCATION_LONGITUDE = AUX_DATA;
891
892        /**
893         * The predefined IM protocol types. The protocol can either be non-present, one
894         * of these types, or a free-form string. These cases are encoded in the AUX_DATA
895         * column as:
896         *  - null
897         *  - pre:<an integer, one of the protocols below>
898         *  - custom:<a string>
899         */
900        public static final int PROTOCOL_AIM = 0;
901        public static final int PROTOCOL_MSN = 1;
902        public static final int PROTOCOL_YAHOO = 2;
903        public static final int PROTOCOL_SKYPE = 3;
904        public static final int PROTOCOL_QQ = 4;
905        public static final int PROTOCOL_GOOGLE_TALK = 5;
906        public static final int PROTOCOL_ICQ = 6;
907        public static final int PROTOCOL_JABBER = 7;
908
909        public static String encodePredefinedImProtocol(int protocol) {
910            return "pre:" + protocol;
911        }
912
913        public static String encodeCustomImProtocol(String protocolString) {
914            return "custom:" + protocolString;
915        }
916
917        public static Object decodeImProtocol(String encodedString) {
918            if (encodedString == null) {
919                return null;
920            }
921
922            if (encodedString.startsWith("pre:")) {
923                return Integer.parseInt(encodedString.substring(4));
924            }
925
926            if (encodedString.startsWith("custom:")) {
927                return encodedString.substring(7);
928            }
929
930            throw new IllegalArgumentException(
931                    "the value is not a valid encoded protocol, " + encodedString);
932        }
933
934        /**
935         * This looks up the provider category defined in
936         * {@link android.provider.Im.ProviderCategories} from the predefined IM protocol id.
937         * This is used for interacting with the IM application.
938         *
939         * @param protocol the protocol ID
940         * @return the provider category the IM app uses for the given protocol, or null if no
941         * provider is defined for the given protocol
942         * @hide
943         */
944        public static String lookupProviderCategoryFromId(int protocol) {
945            switch (protocol) {
946                case PROTOCOL_GOOGLE_TALK:
947                    return Im.ProviderCategories.GTALK;
948                case PROTOCOL_AIM:
949                    return Im.ProviderCategories.AIM;
950                case PROTOCOL_MSN:
951                    return Im.ProviderCategories.MSN;
952                case PROTOCOL_YAHOO:
953                    return Im.ProviderCategories.YAHOO;
954                case PROTOCOL_ICQ:
955                    return Im.ProviderCategories.ICQ;
956            }
957            return null;
958        }
959
960        /**
961         * no public constructor since this is a utility class
962         */
963        private ContactMethods() {}
964
965        public static final CharSequence getDisplayLabel(Context context, int kind,
966                int type, CharSequence label) {
967            CharSequence display = "";
968            switch (kind) {
969                case KIND_EMAIL: {
970                    if (type != People.ContactMethods.TYPE_CUSTOM) {
971                        CharSequence[] labels = context.getResources().getTextArray(
972                                com.android.internal.R.array.emailAddressTypes);
973                        try {
974                            display = labels[type - 1];
975                        } catch (ArrayIndexOutOfBoundsException e) {
976                            display = labels[ContactMethods.TYPE_HOME - 1];
977                        }
978                    } else {
979                        if (!TextUtils.isEmpty(label)) {
980                            display = label;
981                        }
982                    }
983                    break;
984                }
985
986                case KIND_POSTAL: {
987                    if (type != People.ContactMethods.TYPE_CUSTOM) {
988                        CharSequence[] labels = context.getResources().getTextArray(
989                                com.android.internal.R.array.postalAddressTypes);
990                        try {
991                            display = labels[type - 1];
992                        } catch (ArrayIndexOutOfBoundsException e) {
993                            display = labels[ContactMethods.TYPE_HOME - 1];
994                        }
995                    } else {
996                        if (!TextUtils.isEmpty(label)) {
997                            display = label;
998                        }
999                    }
1000                    break;
1001                }
1002
1003                default:
1004                    display = context.getString(R.string.untitled);
1005            }
1006            return display;
1007        }
1008
1009        /**
1010         * Add a longitude and latitude location to a postal address.
1011         *
1012         * @param context the context to use when updating the database
1013         * @param postalId the address to update
1014         * @param latitude the latitude for the address
1015         * @param longitude the longitude for the address
1016         */
1017        public void addPostalLocation(Context context, long postalId,
1018                double latitude, double longitude) {
1019            final ContentResolver resolver = context.getContentResolver();
1020            // Insert the location
1021            ContentValues values = new ContentValues(2);
1022            values.put(POSTAL_LOCATION_LATITUDE, latitude);
1023            values.put(POSTAL_LOCATION_LONGITUDE, longitude);
1024            Uri loc = resolver.insert(CONTENT_URI, values);
1025            long locId = ContentUris.parseId(loc);
1026
1027            // Update the postal address
1028            values.clear();
1029            values.put(AUX_DATA, locId);
1030            resolver.update(ContentUris.withAppendedId(CONTENT_URI, postalId), values, null, null);
1031        }
1032
1033        /**
1034         * The content:// style URL for this table
1035         */
1036        public static final Uri CONTENT_URI =
1037            Uri.parse("content://contacts/contact_methods");
1038
1039        /**
1040         * The content:// style URL for sub-directory of e-mail addresses.
1041         */
1042        public static final Uri CONTENT_EMAIL_URI =
1043            Uri.parse("content://contacts/contact_methods/email");
1044
1045        /**
1046         * The MIME type of {@link #CONTENT_URI} providing a directory of
1047         * phones.
1048         */
1049        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact-methods";
1050
1051        /**
1052         * The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\
1053         * multiple {@link Contacts#KIND_EMAIL} entries.
1054         */
1055        public static final String CONTENT_EMAIL_TYPE = "vnd.android.cursor.dir/email";
1056
1057        /**
1058         * The MIME type of a {@link #CONTENT_EMAIL_URI} sub-directory of\
1059         * multiple {@link Contacts#KIND_POSTAL} entries.
1060         */
1061        public static final String CONTENT_POSTAL_TYPE = "vnd.android.cursor.dir/postal-address";
1062
1063        /**
1064         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
1065         * {@link Contacts#KIND_EMAIL} entry.
1066         */
1067        public static final String CONTENT_EMAIL_ITEM_TYPE = "vnd.android.cursor.item/email";
1068
1069        /**
1070         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
1071         * {@link Contacts#KIND_POSTAL} entry.
1072         */
1073        public static final String CONTENT_POSTAL_ITEM_TYPE
1074                = "vnd.android.cursor.item/postal-address";
1075
1076        /**
1077         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
1078         * {@link Contacts#KIND_IM} entry.
1079         */
1080        public static final String CONTENT_IM_ITEM_TYPE = "vnd.android.cursor.item/jabber-im";
1081
1082        /**
1083         * The default sort order for this table
1084         */
1085        public static final String DEFAULT_SORT_ORDER = "name ASC";
1086
1087        /**
1088         * The ID of the person this contact method is assigned to.
1089         * <P>Type: INTEGER (long)</P>
1090         */
1091        public static final String PERSON_ID = "person";
1092    }
1093
1094    /**
1095     * The IM presence columns with some contacts specific columns mixed in.
1096     */
1097    public interface PresenceColumns extends Im.CommonPresenceColumns {
1098        /**
1099         * The IM service the presence is coming from. Formatted using either
1100         * {@link Contacts.ContactMethods#encodePredefinedImProtocol} or
1101         * {@link Contacts.ContactMethods#encodeCustomImProtocol}.
1102         * <P>Type: STRING</P>
1103         */
1104        public static final String IM_PROTOCOL = "im_protocol";
1105
1106        /**
1107         * The IM handle the presence item is for. The handle is scoped to
1108         * the {@link #IM_PROTOCOL}.
1109         * <P>Type: STRING</P>
1110         */
1111        public static final String IM_HANDLE = "im_handle";
1112
1113        /**
1114         * The IM account for the local user that the presence data came from.
1115         * <P>Type: STRING</P>
1116         */
1117        public static final String IM_ACCOUNT = "im_account";
1118    }
1119
1120    /**
1121     * Contains presence information about contacts.
1122     * @hide
1123     */
1124    public static final class Presence
1125            implements BaseColumns, PresenceColumns, PeopleColumns {
1126        /**
1127         * The content:// style URL for this table
1128         */
1129        public static final Uri CONTENT_URI =
1130            Uri.parse("content://contacts/presence");
1131
1132        /**
1133         * The ID of the person this presence item is assigned to.
1134         * <P>Type: INTEGER (long)</P>
1135         */
1136        public static final String PERSON_ID = "person";
1137
1138        /**
1139         * Gets the resource ID for the proper presence icon.
1140         *
1141         * @param status the status to get the icon for
1142         * @return the resource ID for the proper presence icon
1143         */
1144        public static final int getPresenceIconResourceId(int status) {
1145            switch (status) {
1146                case Contacts.People.AVAILABLE:
1147                    return com.android.internal.R.drawable.presence_online;
1148
1149                case Contacts.People.IDLE:
1150                case Contacts.People.AWAY:
1151                    return com.android.internal.R.drawable.presence_away;
1152
1153                case Contacts.People.DO_NOT_DISTURB:
1154                    return com.android.internal.R.drawable.presence_busy;
1155
1156                case Contacts.People.INVISIBLE:
1157                    return com.android.internal.R.drawable.presence_invisible;
1158
1159                case Contacts.People.OFFLINE:
1160                default:
1161                    return com.android.internal.R.drawable.presence_offline;
1162            }
1163        }
1164
1165        /**
1166         * Sets a presence icon to the proper graphic
1167         *
1168         * @param icon the icon to to set
1169         * @param serverStatus that status
1170         */
1171        public static final void setPresenceIcon(ImageView icon, int serverStatus) {
1172            icon.setImageResource(getPresenceIconResourceId(serverStatus));
1173        }
1174    }
1175
1176    /**
1177     * Columns from the Organizations table that other columns join into themselves.
1178     */
1179    public interface OrganizationColumns {
1180        /**
1181         * The type of the the phone number.
1182         * <P>Type: INTEGER (one of the constants below)</P>
1183         */
1184        public static final String TYPE = "type";
1185
1186        public static final int TYPE_CUSTOM = 0;
1187        public static final int TYPE_WORK = 1;
1188        public static final int TYPE_OTHER = 2;
1189
1190        /**
1191         * The user provided label, only used if TYPE is TYPE_CUSTOM.
1192         * <P>Type: TEXT</P>
1193         */
1194        public static final String LABEL = "label";
1195
1196        /**
1197         * The name of the company for this organization.
1198         * <P>Type: TEXT</P>
1199         */
1200        public static final String COMPANY = "company";
1201
1202        /**
1203         * The title within this organization.
1204         * <P>Type: TEXT</P>
1205         */
1206        public static final String TITLE = "title";
1207
1208        /**
1209         * The person this organization is tied to.
1210         * <P>Type: TEXT</P>
1211         */
1212        public static final String PERSON_ID = "person";
1213
1214        /**
1215         * Whether this is the primary organization
1216         * <P>Type: INTEGER (if set, non-0 means true)</P>
1217         */
1218        public static final String ISPRIMARY = "isprimary";
1219    }
1220
1221    /**
1222     * A sub directory of a single person that contains all of their Phones.
1223     */
1224    public static final class Organizations implements BaseColumns, OrganizationColumns {
1225        /**
1226         * no public constructor since this is a utility class
1227         */
1228        private Organizations() {}
1229
1230        public static final CharSequence getDisplayLabel(Context context, int type,
1231                CharSequence label) {
1232            CharSequence display = "";
1233
1234            if (type != TYPE_CUSTOM) {
1235                CharSequence[] labels = context.getResources().getTextArray(
1236                        com.android.internal.R.array.organizationTypes);
1237                try {
1238                    display = labels[type - 1];
1239                } catch (ArrayIndexOutOfBoundsException e) {
1240                    display = labels[Organizations.TYPE_WORK - 1];
1241                }
1242            } else {
1243                if (!TextUtils.isEmpty(label)) {
1244                    display = label;
1245                }
1246            }
1247            return display;
1248        }
1249
1250        /**
1251         * The content:// style URL for this table
1252         */
1253        public static final Uri CONTENT_URI =
1254            Uri.parse("content://contacts/organizations");
1255
1256        /**
1257         * The directory twig for this sub-table
1258         */
1259        public static final String CONTENT_DIRECTORY = "organizations";
1260
1261        /**
1262         * The default sort order for this table
1263         */
1264        public static final String DEFAULT_SORT_ORDER = "company, title, isprimary ASC";
1265    }
1266
1267    /**
1268     * Columns from the Photos table that other columns join into themselves.
1269     */
1270    public interface PhotosColumns {
1271        /**
1272         * The _SYNC_VERSION of the photo that was last downloaded
1273         * <P>Type: TEXT</P>
1274         */
1275        public static final String LOCAL_VERSION = "local_version";
1276
1277        /**
1278         * The person this photo is associated with.
1279         * <P>Type: TEXT</P>
1280         */
1281        public static final String PERSON_ID = "person";
1282
1283        /**
1284         * non-zero if a download is required and the photo isn't marked as a bad resource.
1285         * You must specify this in the columns in order to use it in the where clause.
1286         * <P>Type: INTEGER(boolean)</P>
1287         */
1288        public static final String DOWNLOAD_REQUIRED = "download_required";
1289
1290        /**
1291         * non-zero if this photo is known to exist on the server
1292         * <P>Type: INTEGER(boolean)</P>
1293         */
1294        public static final String EXISTS_ON_SERVER = "exists_on_server";
1295
1296        /**
1297         * Contains the description of the upload or download error from
1298         * the previous attempt. If null then the previous attempt succeeded.
1299         * <P>Type: TEXT</P>
1300         */
1301        public static final String SYNC_ERROR = "sync_error";
1302
1303        /**
1304         * The image data, or null if there is no image.
1305         * <P>Type: BLOB</P>
1306         */
1307        public static final String DATA = "data";
1308
1309    }
1310
1311    /**
1312     * The photos over all of the people
1313     */
1314    public static final class Photos implements BaseColumns, PhotosColumns, SyncConstValue {
1315        /**
1316         * no public constructor since this is a utility class
1317         */
1318        private Photos() {}
1319
1320        /**
1321         * The content:// style URL for this table
1322         */
1323        public static final Uri CONTENT_URI =
1324            Uri.parse("content://contacts/photos");
1325
1326        /**
1327         * The directory twig for this sub-table
1328         */
1329        public static final String CONTENT_DIRECTORY = "photo";
1330
1331        /**
1332         * The default sort order for this table
1333         */
1334        public static final String DEFAULT_SORT_ORDER = "person ASC";
1335    }
1336
1337    public interface ExtensionsColumns {
1338        /**
1339         * The name of this extension. May not be null. There may be at most one row for each name.
1340         * <P>Type: TEXT</P>
1341         */
1342        public static final String NAME = "name";
1343
1344        /**
1345         * The value of this extension. May not be null.
1346         * <P>Type: TEXT</P>
1347         */
1348        public static final String VALUE = "value";
1349    }
1350
1351    /**
1352     * The extensions for a person
1353     */
1354    public static final class Extensions implements BaseColumns, ExtensionsColumns {
1355        /**
1356         * no public constructor since this is a utility class
1357         */
1358        private Extensions() {}
1359
1360        /**
1361         * The content:// style URL for this table
1362         */
1363        public static final Uri CONTENT_URI =
1364            Uri.parse("content://contacts/extensions");
1365
1366        /**
1367         * The MIME type of {@link #CONTENT_URI} providing a directory of
1368         * phones.
1369         */
1370        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_extensions";
1371
1372        /**
1373         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
1374         * phone.
1375         */
1376        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_extensions";
1377        /**
1378         * The default sort order for this table
1379         */
1380        public static final String DEFAULT_SORT_ORDER = "person, name ASC";
1381
1382        /**
1383         * The ID of the person this phone number is assigned to.
1384         * <P>Type: INTEGER (long)</P>
1385         */
1386        public static final String PERSON_ID = "person";
1387    }
1388
1389    /**
1390     * Contains helper classes used to create or manage {@link android.content.Intent Intents}
1391     * that involve contacts.
1392     */
1393    public static final class Intents {
1394        /**
1395         * This is the intent that is fired when a search suggestion is clicked on.
1396         */
1397        public static final String SEARCH_SUGGESTION_CLICKED =
1398                "android.provider.Contacts.SEARCH_SUGGESTION_CLICKED";
1399
1400        /**
1401         * This is the intent that is fired when a search suggestion for dialing a number
1402         * is clicked on.
1403         */
1404        public static final String SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED =
1405                "android.provider.Contacts.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED";
1406
1407        /**
1408         * This is the intent that is fired when a search suggestion for creating a contact
1409         * is clicked on.
1410         */
1411        public static final String SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED =
1412                "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
1413
1414        /**
1415         * Starts an Activity that lets the user pick a contact to attach an image to.
1416         * After picking the contact it launches the image cropper in face detection mode.
1417         */
1418        public static final String ATTACH_IMAGE =
1419                "com.android.contacts.action.ATTACH_IMAGE";
1420
1421        /**
1422         * Intents related to the Contacts app UI.
1423         */
1424        public static final class UI {
1425            /**
1426             * The action for the default contacts list tab.
1427             */
1428            public static final String LIST_DEFAULT =
1429                    "com.android.contacts.action.LIST_DEFAULT";
1430
1431            /**
1432             * The action for the contacts list tab.
1433             */
1434            public static final String LIST_GROUP_ACTION =
1435                    "com.android.contacts.action.LIST_GROUP";
1436
1437            /**
1438             * When in LIST_GROUP_ACTION mode, this is the group to display.
1439             */
1440            public static final String GROUP_NAME_EXTRA_KEY = "com.android.contacts.extra.GROUP";
1441
1442            /**
1443             * The action for the all contacts list tab.
1444             */
1445            public static final String LIST_ALL_CONTACTS_ACTION =
1446                    "com.android.contacts.action.LIST_ALL_CONTACTS";
1447
1448            /**
1449             * The action for the contacts with phone numbers list tab.
1450             */
1451            public static final String LIST_CONTACTS_WITH_PHONES_ACTION =
1452                    "com.android.contacts.action.LIST_CONTACTS_WITH_PHONES";
1453
1454            /**
1455             * The action for the starred contacts list tab.
1456             */
1457            public static final String LIST_STARRED_ACTION =
1458                    "com.android.contacts.action.LIST_STARRED";
1459
1460            /**
1461             * The action for the frequent contacts list tab.
1462             */
1463            public static final String LIST_FREQUENT_ACTION =
1464                    "com.android.contacts.action.LIST_FREQUENT";
1465
1466            /**
1467             * The action for the "strequent" contacts list tab. It first lists the starred
1468             * contacts in alphabetical order and then the frequent contacts in descending
1469             * order of the number of times they have been contacted.
1470             */
1471            public static final String LIST_STREQUENT_ACTION =
1472                    "com.android.contacts.action.LIST_STREQUENT";
1473
1474            /**
1475             * A key for to be used as an intent extra to set the activity
1476             * title to a custom String value.
1477             */
1478            public static final String TITLE_EXTRA_KEY =
1479                "com.android.contacts.extra.TITLE_EXTRA";
1480
1481            /**
1482             * Activity Action: Display a filtered list of contacts
1483             * <p>
1484             * Input: Extra field {@link #FILTER_TEXT_EXTRA_KEY} is the text to use for
1485             * filtering
1486             * <p>
1487             * Output: Nothing.
1488             */
1489            public static final String FILTER_CONTACTS_ACTION =
1490                "com.android.contacts.action.FILTER_CONTACTS";
1491
1492            /**
1493             * Used as an int extra field in {@link #FILTER_CONTACTS_ACTION}
1494             * intents to supply the text on which to filter.
1495             */
1496            public static final String FILTER_TEXT_EXTRA_KEY =
1497                "com.android.contacts.extra.FILTER_TEXT";
1498        }
1499
1500        /**
1501         * Convenience class that contains string constants used
1502         * to create contact {@link android.content.Intent Intents}.
1503         */
1504        public static final class Insert {
1505            /** The action code to use when adding a contact */
1506            public static final String ACTION = Intent.ACTION_INSERT;
1507
1508            /**
1509             * If present, forces a bypass of quick insert mode.
1510             */
1511            public static final String FULL_MODE = "full_mode";
1512
1513            /**
1514             * The extra field for the contact name.
1515             * <P>Type: String</P>
1516             */
1517            public static final String NAME = "name";
1518
1519            /**
1520             * The extra field for the contact phonetic name.
1521             * <P>Type: String</P>
1522             */
1523            public static final String PHONETIC_NAME = "phonetic_name";
1524
1525            /**
1526             * The extra field for the contact company.
1527             * <P>Type: String</P>
1528             */
1529            public static final String COMPANY = "company";
1530
1531            /**
1532             * The extra field for the contact job title.
1533             * <P>Type: String</P>
1534             */
1535            public static final String JOB_TITLE = "job_title";
1536
1537            /**
1538             * The extra field for the contact notes.
1539             * <P>Type: String</P>
1540             */
1541            public static final String NOTES = "notes";
1542
1543            /**
1544             * The extra field for the contact phone number.
1545             * <P>Type: String</P>
1546             */
1547            public static final String PHONE = "phone";
1548
1549            /**
1550             * The extra field for the contact phone number type.
1551             * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
1552             *  or a string specifying a custom label.</P>
1553             */
1554            public static final String PHONE_TYPE = "phone_type";
1555
1556            /**
1557             * The extra field for the phone isprimary flag.
1558             * <P>Type: boolean</P>
1559             */
1560            public static final String PHONE_ISPRIMARY = "phone_isprimary";
1561
1562            /**
1563             * The extra field for an optional second contact phone number.
1564             * <P>Type: String</P>
1565             */
1566            public static final String SECONDARY_PHONE = "secondary_phone";
1567
1568            /**
1569             * The extra field for an optional second contact phone number type.
1570             * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
1571             *  or a string specifying a custom label.</P>
1572             */
1573            public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type";
1574
1575            /**
1576             * The extra field for an optional third contact phone number.
1577             * <P>Type: String</P>
1578             */
1579            public static final String TERTIARY_PHONE = "tertiary_phone";
1580
1581            /**
1582             * The extra field for an optional third contact phone number type.
1583             * <P>Type: Either an integer value from {@link android.provider.Contacts.PhonesColumns PhonesColumns},
1584             *  or a string specifying a custom label.</P>
1585             */
1586            public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type";
1587
1588            /**
1589             * The extra field for the contact email address.
1590             * <P>Type: String</P>
1591             */
1592            public static final String EMAIL = "email";
1593
1594            /**
1595             * The extra field for the contact email type.
1596             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
1597             *  or a string specifying a custom label.</P>
1598             */
1599            public static final String EMAIL_TYPE = "email_type";
1600
1601            /**
1602             * The extra field for the email isprimary flag.
1603             * <P>Type: boolean</P>
1604             */
1605            public static final String EMAIL_ISPRIMARY = "email_isprimary";
1606
1607            /**
1608             * The extra field for an optional second contact email address.
1609             * <P>Type: String</P>
1610             */
1611            public static final String SECONDARY_EMAIL = "secondary_email";
1612
1613            /**
1614             * The extra field for an optional second contact email type.
1615             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
1616             *  or a string specifying a custom label.</P>
1617             */
1618            public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type";
1619
1620            /**
1621             * The extra field for an optional third contact email address.
1622             * <P>Type: String</P>
1623             */
1624            public static final String TERTIARY_EMAIL = "tertiary_email";
1625
1626            /**
1627             * The extra field for an optional third contact email type.
1628             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
1629             *  or a string specifying a custom label.</P>
1630             */
1631            public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type";
1632
1633            /**
1634             * The extra field for the contact postal address.
1635             * <P>Type: String</P>
1636             */
1637            public static final String POSTAL = "postal";
1638
1639            /**
1640             * The extra field for the contact postal address type.
1641             * <P>Type: Either an integer value from {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns}
1642             *  or a string specifying a custom label.</P>
1643             */
1644            public static final String POSTAL_TYPE = "postal_type";
1645
1646            /**
1647             * The extra field for the postal isprimary flag.
1648             * <P>Type: boolean</P>
1649             */
1650            public static final String POSTAL_ISPRIMARY = "postal_isprimary";
1651
1652            /**
1653             * The extra field for an IM handle.
1654             * <P>Type: String</P>
1655             */
1656            public static final String IM_HANDLE = "im_handle";
1657
1658            /**
1659             * The extra field for the IM protocol
1660             * <P>Type: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}
1661             * or {@link Contacts.ContactMethods#encodeCustomImProtocol}.</P>
1662             */
1663            public static final String IM_PROTOCOL = "im_protocol";
1664
1665            /**
1666             * The extra field for the IM isprimary flag.
1667             * <P>Type: boolean</P>
1668             */
1669            public static final String IM_ISPRIMARY = "im_isprimary";
1670        }
1671    }
1672}
1673